blob: 9cce01eaea91cbe02a3dce955e9397b6d8e19355 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002
3#include <stdlib.h>
4
5#include "v8.h"
6
7#include "execution.h"
8#include "factory.h"
9#include "macro-assembler.h"
10#include "global-handles.h"
11#include "cctest.h"
12
13using namespace v8::internal;
14
15static v8::Persistent<v8::Context> env;
16
17static void InitializeVM() {
18 if (env.IsEmpty()) env = v8::Context::New();
19 v8::HandleScope scope;
20 env->Enter();
21}
22
23
24static void CheckMap(Map* map, int type, int instance_size) {
25 CHECK(map->IsHeapObject());
26#ifdef DEBUG
27 CHECK(Heap::Contains(map));
28#endif
29 CHECK_EQ(Heap::meta_map(), map->map());
30 CHECK_EQ(type, map->instance_type());
31 CHECK_EQ(instance_size, map->instance_size());
32}
33
34
35TEST(HeapMaps) {
36 InitializeVM();
37 CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
38 CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000039 CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
40 CheckMap(Heap::string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041}
42
43
44static void CheckOddball(Object* obj, const char* string) {
45 CHECK(obj->IsOddball());
46 bool exc;
47 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
48 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
49}
50
51
52static void CheckSmi(int value, const char* string) {
53 bool exc;
54 Object* print_string =
55 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
56 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
57}
58
59
60static void CheckNumber(double value, const char* string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000061 Object* obj = Heap::NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062 CHECK(obj->IsNumber());
63 bool exc;
64 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
65 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
66}
67
68
69static void CheckFindCodeObject() {
70 // Test FindCodeObject
71#define __ assm.
72
73 Assembler assm(NULL, 0);
74
75 __ nop(); // supported on all architectures
76
77 CodeDesc desc;
78 assm.GetCode(&desc);
lrn@chromium.org303ada72010-10-27 09:33:13 +000079 Object* code = Heap::CreateCode(
80 desc,
81 Code::ComputeFlags(Code::STUB),
82 Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083 CHECK(code->IsCode());
84
85 HeapObject* obj = HeapObject::cast(code);
86 Address obj_addr = obj->address();
87
88 for (int i = 0; i < obj->Size(); i += kPointerSize) {
89 Object* found = Heap::FindCodeObject(obj_addr + i);
90 CHECK_EQ(code, found);
91 }
92
lrn@chromium.org303ada72010-10-27 09:33:13 +000093 Object* copy = Heap::CreateCode(
94 desc,
95 Code::ComputeFlags(Code::STUB),
96 Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000097 CHECK(copy->IsCode());
98 HeapObject* obj_copy = HeapObject::cast(copy);
99 Object* not_right = Heap::FindCodeObject(obj_copy->address() +
100 obj_copy->Size() / 2);
101 CHECK(not_right != code);
102}
103
104
105TEST(HeapObjects) {
106 InitializeVM();
107
108 v8::HandleScope sc;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* value = Heap::NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 CHECK(value->IsHeapNumber());
111 CHECK(value->IsNumber());
112 CHECK_EQ(1.000123, value->Number());
113
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 value = Heap::NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115 CHECK(value->IsSmi());
116 CHECK(value->IsNumber());
117 CHECK_EQ(1.0, value->Number());
118
lrn@chromium.org303ada72010-10-27 09:33:13 +0000119 value = Heap::NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000120 CHECK(value->IsSmi());
121 CHECK(value->IsNumber());
122 CHECK_EQ(1024.0, value->Number());
123
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 value = Heap::NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125 CHECK(value->IsSmi());
126 CHECK(value->IsNumber());
127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
128
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 value = Heap::NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000130 CHECK(value->IsSmi());
131 CHECK(value->IsNumber());
132 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
133
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000134#ifndef V8_TARGET_ARCH_X64
135 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 value = Heap::NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 CHECK(value->IsHeapNumber());
138 CHECK(value->IsNumber());
139 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000140#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000141
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 MaybeObject* maybe_value =
143 Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
144 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 CHECK(value->IsHeapNumber());
146 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000147 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
148 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149
150 // nan oddball checks
151 CHECK(Heap::nan_value()->IsNumber());
152 CHECK(isnan(Heap::nan_value()->Number()));
153
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000154 Handle<String> s = Factory::NewStringFromAscii(CStrVector("fisk hest "));
155 CHECK(s->IsString());
156 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157
158 String* object_symbol = String::cast(Heap::Object_symbol());
159 CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
160
161 // Check ToString for oddballs
162 CheckOddball(Heap::true_value(), "true");
163 CheckOddball(Heap::false_value(), "false");
164 CheckOddball(Heap::null_value(), "null");
165 CheckOddball(Heap::undefined_value(), "undefined");
166
167 // Check ToString for Smis
168 CheckSmi(0, "0");
169 CheckSmi(42, "42");
170 CheckSmi(-42, "-42");
171
172 // Check ToString for Numbers
173 CheckNumber(1.1, "1.1");
174
175 CheckFindCodeObject();
176}
177
178
179TEST(Tagging) {
180 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000181 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000182 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000184 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000185 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000186 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000187 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000188 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000189 CHECK(Failure::Exception()->IsFailure());
190 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
191 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
192}
193
194
195TEST(GarbageCollection) {
196 InitializeVM();
197
198 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000199 // Check GC.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000200 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000201
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000202 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
203 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
204 Handle<String> prop_namex = Factory::LookupAsciiSymbol("theSlotx");
205 Handle<String> obj_name = Factory::LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000207 {
208 v8::HandleScope inner_scope;
209 // Allocate a function and keep it in global object's property.
210 Handle<JSFunction> function =
211 Factory::NewFunction(name, Factory::undefined_value());
212 Handle<Map> initial_map =
213 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
214 function->set_initial_map(*initial_map);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000215 Top::context()->global()->SetProperty(
216 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000217 // Allocate an object. Unrooted after leaving the scope.
218 Handle<JSObject> obj = Factory::NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000219 obj->SetProperty(
220 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
221 obj->SetProperty(
222 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000224 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
225 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
226 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000228 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000229
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000230 // Function should be alive.
231 CHECK(Top::context()->global()->HasLocalProperty(*name));
232 // Check function is retained.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000233 Object* func_value =
234 Top::context()->global()->GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000236 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 {
239 HandleScope inner_scope;
240 // Allocate another object, make it reachable from global.
241 Handle<JSObject> obj = Factory::NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000242 Top::context()->global()->SetProperty(
243 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
244 obj->SetProperty(
245 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000246 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000247
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000248 // After gc, it should survive.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000249 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000251 CHECK(Top::context()->global()->HasLocalProperty(*obj_name));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000252 CHECK(Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked()->
253 IsJSObject());
254 Object* obj =
255 Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked();
256 JSObject* js_obj = JSObject::cast(obj);
257 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000258}
259
260
261static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000262 v8::HandleScope scope;
263 Handle<String> s = Factory::NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000264 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000265 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
267 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268}
269
270
271TEST(String) {
272 InitializeVM();
273
274 VerifyStringAllocation("a");
275 VerifyStringAllocation("ab");
276 VerifyStringAllocation("abc");
277 VerifyStringAllocation("abcd");
278 VerifyStringAllocation("fiskerdrengen er paa havet");
279}
280
281
282TEST(LocalHandles) {
283 InitializeVM();
284
285 v8::HandleScope scope;
286 const char* name = "Kasper the spunky";
287 Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000288 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000289}
290
291
292TEST(GlobalHandles) {
293 InitializeVM();
294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000295 Handle<Object> h1;
296 Handle<Object> h2;
297 Handle<Object> h3;
298 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000299
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 {
301 HandleScope scope;
302
303 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
304 Handle<Object> u = Factory::NewNumber(1.12344);
305
306 h1 = GlobalHandles::Create(*i);
307 h2 = GlobalHandles::Create(*u);
308 h3 = GlobalHandles::Create(*i);
309 h4 = GlobalHandles::Create(*u);
310 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000311
312 // after gc, it should survive
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000313 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314
315 CHECK((*h1)->IsString());
316 CHECK((*h2)->IsHeapNumber());
317 CHECK((*h3)->IsString());
318 CHECK((*h4)->IsHeapNumber());
319
320 CHECK_EQ(*h3, *h1);
321 GlobalHandles::Destroy(h1.location());
322 GlobalHandles::Destroy(h3.location());
323
324 CHECK_EQ(*h4, *h2);
325 GlobalHandles::Destroy(h2.location());
326 GlobalHandles::Destroy(h4.location());
327}
328
329
330static bool WeakPointerCleared = false;
331
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000332static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000333 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000334 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000335 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000336}
337
338
339TEST(WeakGlobalHandlesScavenge) {
340 InitializeVM();
341
342 WeakPointerCleared = false;
343
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000344 Handle<Object> h1;
345 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000347 {
348 HandleScope scope;
349
350 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
351 Handle<Object> u = Factory::NewNumber(1.12344);
352
353 h1 = GlobalHandles::Create(*i);
354 h2 = GlobalHandles::Create(*u);
355 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356
357 GlobalHandles::MakeWeak(h2.location(),
358 reinterpret_cast<void*>(1234),
359 &TestWeakGlobalHandleCallback);
360
361 // Scavenge treats weak pointers as normal roots.
362 Heap::PerformScavenge();
363
364 CHECK((*h1)->IsString());
365 CHECK((*h2)->IsHeapNumber());
366
367 CHECK(!WeakPointerCleared);
368 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
369 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
370
371 GlobalHandles::Destroy(h1.location());
372 GlobalHandles::Destroy(h2.location());
373}
374
375
376TEST(WeakGlobalHandlesMark) {
377 InitializeVM();
378
379 WeakPointerCleared = false;
380
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000381 Handle<Object> h1;
382 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000383
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000384 {
385 HandleScope scope;
386
387 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
388 Handle<Object> u = Factory::NewNumber(1.12344);
389
390 h1 = GlobalHandles::Create(*i);
391 h2 = GlobalHandles::Create(*u);
392 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000393
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000394 Heap::CollectGarbage(OLD_POINTER_SPACE);
395 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396 // Make sure the object is promoted.
397
398 GlobalHandles::MakeWeak(h2.location(),
399 reinterpret_cast<void*>(1234),
400 &TestWeakGlobalHandleCallback);
401 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
402 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
403
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000404 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405
406 CHECK((*h1)->IsString());
407
408 CHECK(WeakPointerCleared);
409 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000410
411 GlobalHandles::Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000412}
413
414TEST(DeleteWeakGlobalHandle) {
415 InitializeVM();
416
417 WeakPointerCleared = false;
418
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000419 Handle<Object> h;
420
421 {
422 HandleScope scope;
423
424 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
425 h = GlobalHandles::Create(*i);
426 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427
428 GlobalHandles::MakeWeak(h.location(),
429 reinterpret_cast<void*>(1234),
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000430 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000431
432 // Scanvenge does not recognize weak reference.
433 Heap::PerformScavenge();
434
435 CHECK(!WeakPointerCleared);
436
437 // Mark-compact treats weak reference properly.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000438 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439
440 CHECK(WeakPointerCleared);
441}
442
443static const char* not_so_random_string_table[] = {
444 "abstract",
445 "boolean",
446 "break",
447 "byte",
448 "case",
449 "catch",
450 "char",
451 "class",
452 "const",
453 "continue",
454 "debugger",
455 "default",
456 "delete",
457 "do",
458 "double",
459 "else",
460 "enum",
461 "export",
462 "extends",
463 "false",
464 "final",
465 "finally",
466 "float",
467 "for",
468 "function",
469 "goto",
470 "if",
471 "implements",
472 "import",
473 "in",
474 "instanceof",
475 "int",
476 "interface",
477 "long",
478 "native",
479 "new",
480 "null",
481 "package",
482 "private",
483 "protected",
484 "public",
485 "return",
486 "short",
487 "static",
488 "super",
489 "switch",
490 "synchronized",
491 "this",
492 "throw",
493 "throws",
494 "transient",
495 "true",
496 "try",
497 "typeof",
498 "var",
499 "void",
500 "volatile",
501 "while",
502 "with",
503 0
504};
505
506
507static void CheckSymbols(const char** strings) {
508 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000509 Object* a;
510 MaybeObject* maybe_a = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000511 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000513 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000514 Object* b;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515 MaybeObject *maybe_b = Heap::LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000516 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000517 CHECK_EQ(b, a);
518 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
519 }
520}
521
522
523TEST(SymbolTable) {
524 InitializeVM();
525
526 CheckSymbols(not_so_random_string_table);
527 CheckSymbols(not_so_random_string_table);
528}
529
530
531TEST(FunctionAllocation) {
532 InitializeVM();
533
534 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000535 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
536 Handle<JSFunction> function =
537 Factory::NewFunction(name, Factory::undefined_value());
538 Handle<Map> initial_map =
539 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
540 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000541
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000542 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
543 Handle<JSObject> obj = Factory::NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000544 obj->SetProperty(
545 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000546 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000547 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000548 function->SetProperty(
549 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000550 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000551}
552
553
554TEST(ObjectProperties) {
555 InitializeVM();
556
557 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000558 String* object_symbol = String::cast(Heap::Object_symbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000559 Object* raw_object =
560 Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
561 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000562 Handle<JSFunction> constructor(object_function);
563 Handle<JSObject> obj = Factory::NewJSObject(constructor);
564 Handle<String> first = Factory::LookupAsciiSymbol("first");
565 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000566
567 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000568 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000569
570 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000571 obj->SetProperty(
572 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000573 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000574
575 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000576 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
577 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000578
579 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000580 obj->SetProperty(
581 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
582 obj->SetProperty(
583 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000584 CHECK(obj->HasLocalProperty(*first));
585 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000586
587 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000588 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
589 CHECK(obj->HasLocalProperty(*second));
590 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
591 CHECK(!obj->HasLocalProperty(*first));
592 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000593
594 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000595 obj->SetProperty(
596 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
597 obj->SetProperty(
598 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000599 CHECK(obj->HasLocalProperty(*first));
600 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000601
602 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000603 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
604 CHECK(obj->HasLocalProperty(*first));
605 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
606 CHECK(!obj->HasLocalProperty(*first));
607 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000608
609 // check string and symbol match
610 static const char* string1 = "fisk";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000611 Handle<String> s1 = Factory::NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000612 obj->SetProperty(
613 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000614 Handle<String> s1_symbol = Factory::LookupAsciiSymbol(string1);
615 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000616
617 // check symbol and string match
618 static const char* string2 = "fugl";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000619 Handle<String> s2_symbol = Factory::LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000620 obj->SetProperty(
621 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622 Handle<String> s2 = Factory::NewStringFromAscii(CStrVector(string2));
623 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000624}
625
626
627TEST(JSObjectMaps) {
628 InitializeVM();
629
630 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000631 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
632 Handle<JSFunction> function =
633 Factory::NewFunction(name, Factory::undefined_value());
634 Handle<Map> initial_map =
635 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
636 function->set_initial_map(*initial_map);
637
638 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
639 Handle<JSObject> obj = Factory::NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000640
641 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000642 obj->SetProperty(
643 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000645
646 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000647 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000648}
649
650
651TEST(JSArray) {
652 InitializeVM();
653
654 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000655 Handle<String> name = Factory::LookupAsciiSymbol("Array");
lrn@chromium.org303ada72010-10-27 09:33:13 +0000656 Object* raw_object =
657 Top::context()->global()->GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000658 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000659 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000660
661 // Allocate the object.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000662 Handle<JSObject> object = Factory::NewJSObject(function);
663 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000664 // We just initialized the VM, no heap allocation failure yet.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000665 Object* ok = array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000666
667 // Set array length to 0.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000668 ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000669 CHECK_EQ(Smi::FromInt(0), array->length());
670 CHECK(array->HasFastElements()); // Must be in fast mode.
671
672 // array[length] = name.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000673 ok = array->SetElement(0, *name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000675 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000677 // Set array length with larger than smi value.
678 Handle<Object> length =
679 Factory::NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000680 ok = array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000681
682 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000683 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000684 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000685 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000686
687 // array[length] = name.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000688 ok = array->SetElement(int_length, *name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000689 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000690 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000691 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 CHECK_EQ(array->GetElement(int_length), *name);
693 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000694}
695
696
697TEST(JSObjectCopy) {
698 InitializeVM();
699
700 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000701 String* object_symbol = String::cast(Heap::Object_symbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000702 Object* raw_object =
703 Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
704 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 Handle<JSFunction> constructor(object_function);
706 Handle<JSObject> obj = Factory::NewJSObject(constructor);
707 Handle<String> first = Factory::LookupAsciiSymbol("first");
708 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000709
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000710 obj->SetProperty(
711 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
712 obj->SetProperty(
713 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000714
lrn@chromium.org303ada72010-10-27 09:33:13 +0000715 Object* ok = obj->SetElement(0, *first)->ToObjectChecked();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000716
lrn@chromium.org303ada72010-10-27 09:33:13 +0000717 ok = obj->SetElement(1, *second)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000718
719 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000720 Handle<JSObject> clone = Copy(obj);
721 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722
723 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
724 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
725
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000726 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
727 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000728
729 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000730 clone->SetProperty(
731 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
732 clone->SetProperty(
733 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000734
lrn@chromium.org303ada72010-10-27 09:33:13 +0000735 ok = clone->SetElement(0, *second)->ToObjectChecked();
736 ok = clone->SetElement(1, *first)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000737
738 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
739 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
740
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000741 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
742 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000743}
744
745
746TEST(StringAllocation) {
747 InitializeVM();
748
749
750 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
751 for (int length = 0; length < 100; length++) {
752 v8::HandleScope scope;
753 char* non_ascii = NewArray<char>(3 * length + 1);
754 char* ascii = NewArray<char>(length + 1);
755 non_ascii[3 * length] = 0;
756 ascii[length] = 0;
757 for (int i = 0; i < length; i++) {
758 ascii[i] = 'a';
759 non_ascii[3 * i] = chars[0];
760 non_ascii[3 * i + 1] = chars[1];
761 non_ascii[3 * i + 2] = chars[2];
762 }
763 Handle<String> non_ascii_sym =
764 Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
765 CHECK_EQ(length, non_ascii_sym->length());
766 Handle<String> ascii_sym =
767 Factory::LookupSymbol(Vector<const char>(ascii, length));
768 CHECK_EQ(length, ascii_sym->length());
769 Handle<String> non_ascii_str =
770 Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
771 non_ascii_str->Hash();
772 CHECK_EQ(length, non_ascii_str->length());
773 Handle<String> ascii_str =
774 Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
775 ascii_str->Hash();
776 CHECK_EQ(length, ascii_str->length());
777 DeleteArray(non_ascii);
778 DeleteArray(ascii);
779 }
780}
781
782
783static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
784 // Count the number of objects found in the heap.
785 int found_count = 0;
786 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000787 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000788 for (int i = 0; i < size; i++) {
789 if (*objs[i] == obj) {
790 found_count++;
791 }
792 }
793 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 return found_count;
795}
796
797
798TEST(Iteration) {
799 InitializeVM();
800 v8::HandleScope scope;
801
802 // Array of objects to scan haep for.
803 const int objs_count = 6;
804 Handle<Object> objs[objs_count];
805 int next_objs_index = 0;
806
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000807 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000808 objs[next_objs_index++] = Factory::NewJSArray(10);
809 objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
810
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000811 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000812 objs[next_objs_index++] =
813 Factory::NewStringFromAscii(CStrVector("abcdefghij"));
814 objs[next_objs_index++] =
815 Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
816
817 // Allocate a large string (for large object space).
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000818 int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819 char* str = new char[large_size];
820 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
821 str[large_size - 1] = '\0';
822 objs[next_objs_index++] =
823 Factory::NewStringFromAscii(CStrVector(str), TENURED);
824 delete[] str;
825
826 // Add a Map object to look for.
827 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
828
829 CHECK_EQ(objs_count, next_objs_index);
830 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
831}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000832
833
834TEST(LargeObjectSpaceContains) {
835 InitializeVM();
836
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000837 Heap::CollectGarbage(NEW_SPACE);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000838
839 Address current_top = Heap::new_space()->top();
840 Page* page = Page::FromAddress(current_top);
841 Address current_page = page->address();
842 Address next_page = current_page + Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000843 int bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000844 if (bytes_to_page <= FixedArray::kHeaderSize) {
845 // Alas, need to cross another page to be able to
846 // put desired value.
847 next_page += Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000848 bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000849 }
850 CHECK(bytes_to_page > FixedArray::kHeaderSize);
851
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000852 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000853 Address flags_addr = reinterpret_cast<Address>(flags_ptr);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000854
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000855 int bytes_to_allocate =
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000856 static_cast<int>(flags_addr - current_top) + kPointerSize;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000857
858 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) /
859 kPointerSize;
860 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
861 FixedArray* array = FixedArray::cast(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000862 Heap::AllocateFixedArray(n_elements)->ToObjectChecked());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000863
864 int index = n_elements - 1;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000865 CHECK_EQ(flags_ptr,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000866 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index)));
867 array->set(index, Smi::FromInt(0));
868 // This chould have turned next page into LargeObjectPage:
869 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
870
871 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
872 CHECK(Heap::new_space()->Contains(addr));
873 CHECK(!Heap::lo_space()->Contains(addr));
874}
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000875
876
877TEST(EmptyHandleEscapeFrom) {
878 InitializeVM();
879
880 v8::HandleScope scope;
881 Handle<JSObject> runaway;
882
883 {
884 v8::HandleScope nested;
885 Handle<JSObject> empty;
886 runaway = empty.EscapeFrom(&nested);
887 }
888
889 CHECK(runaway.is_null());
890}
891
892
893static int LenFromSize(int size) {
894 return (size - FixedArray::kHeaderSize) / kPointerSize;
895}
896
897
898TEST(Regression39128) {
899 // Test case for crbug.com/39128.
900 InitializeVM();
901
902 // Increase the chance of 'bump-the-pointer' allocation in old space.
903 bool force_compaction = true;
904 Heap::CollectAllGarbage(force_compaction);
905
906 v8::HandleScope scope;
907
908 // The plan: create JSObject which references objects in new space.
909 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000910 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000911
912 // Step 1: prepare a map for the object. We add 1 inobject property to it.
913 Handle<JSFunction> object_ctor(Top::global_context()->object_function());
914 CHECK(object_ctor->has_initial_map());
915 Handle<Map> object_map(object_ctor->initial_map());
916 // Create a map with single inobject property.
917 Handle<Map> my_map = Factory::CopyMap(object_map, 1);
918 int n_properties = my_map->inobject_properties();
919 CHECK_GT(n_properties, 0);
920
921 int object_size = my_map->instance_size();
922
923 // Step 2: allocate a lot of objects so to almost fill new space: we need
924 // just enough room to allocate JSObject and thus fill the newspace.
925
926 int allocation_amount = Min(FixedArray::kMaxSize,
927 Heap::MaxObjectSizeInNewSpace());
928 int allocation_len = LenFromSize(allocation_amount);
929 NewSpace* new_space = Heap::new_space();
930 Address* top_addr = new_space->allocation_top_address();
931 Address* limit_addr = new_space->allocation_limit_address();
932 while ((*limit_addr - *top_addr) > allocation_amount) {
933 CHECK(!Heap::always_allocate());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000934 Object* array =
935 Heap::AllocateFixedArray(allocation_len)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000936 CHECK(new_space->Contains(array));
937 }
938
939 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000940 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000941 int fixed_array_len = LenFromSize(to_fill);
942 CHECK(fixed_array_len < FixedArray::kMaxLength);
943
944 CHECK(!Heap::always_allocate());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000945 Object* array =
946 Heap::AllocateFixedArray(fixed_array_len)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000947 CHECK(new_space->Contains(array));
948
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949 Object* object = Heap::AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000950 CHECK(new_space->Contains(object));
951 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000952 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000953 CHECK_EQ(0, jsobject->properties()->length());
954 // Create a reference to object in new space in jsobject.
955 jsobject->FastPropertyAtPut(-1, array);
956
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000957 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000958
959 // Step 4: clone jsobject, but force always allocate first to create a clone
960 // in old pointer space.
961 Address old_pointer_space_top = Heap::old_pointer_space()->top();
962 AlwaysAllocateScope aa_scope;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000963 Object* clone_obj = Heap::CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000964 JSObject* clone = JSObject::cast(clone_obj);
965 if (clone->address() != old_pointer_space_top) {
966 // Alas, got allocated from free list, we cannot do checks.
967 return;
968 }
969 CHECK(Heap::old_pointer_space()->Contains(clone->address()));
970
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000971 // Step 5: verify validity of region dirty marks.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000972 Address clone_addr = clone->address();
973 Page* page = Page::FromAddress(clone_addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000974 // Check that region covering inobject property 1 is marked dirty.
975 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000976}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000977
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000978
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000979TEST(TestCodeFlushing) {
980 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000981 // If we do not flush code this test is invalid.
982 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000983 InitializeVM();
984 v8::HandleScope scope;
985 const char* source = "function foo() {"
986 " var x = 42;"
987 " var y = 42;"
988 " var z = x + y;"
989 "};"
990 "foo()";
991 Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
992
993 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000994 { v8::HandleScope scope;
995 CompileRun(source);
996 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997
998 // Check function is compiled.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000999 Object* func_value =
1000 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001001 CHECK(func_value->IsJSFunction());
1002 Handle<JSFunction> function(JSFunction::cast(func_value));
1003 CHECK(function->shared()->is_compiled());
1004
1005 Heap::CollectAllGarbage(true);
1006 Heap::CollectAllGarbage(true);
1007
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001008 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001009
1010 Heap::CollectAllGarbage(true);
1011 Heap::CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001012 Heap::CollectAllGarbage(true);
1013 Heap::CollectAllGarbage(true);
1014 Heap::CollectAllGarbage(true);
1015 Heap::CollectAllGarbage(true);
1016
1017 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001018 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1019 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001020 // Call foo to get it recompiled.
1021 CompileRun("foo()");
1022 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001023 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001024}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001025
1026
1027// Count the number of global contexts in the weak list of global contexts.
1028static int CountGlobalContexts() {
1029 int count = 0;
1030 Object* object = Heap::global_contexts_list();
1031 while (!object->IsUndefined()) {
1032 count++;
1033 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1034 }
1035 return count;
1036}
1037
1038
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001039// Count the number of user functions in the weak list of optimized
1040// functions attached to a global context.
1041static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1042 int count = 0;
1043 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1044 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1045 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1046 count++;
1047 object = JSFunction::cast(object)->next_function_link();
1048 }
1049 return count;
1050}
1051
1052
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001053TEST(TestInternalWeakLists) {
1054 static const int kNumTestContexts = 10;
1055
1056 v8::HandleScope scope;
1057 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1058
1059 CHECK_EQ(0, CountGlobalContexts());
1060
1061 // Create a number of global contests which gets linked together.
1062 for (int i = 0; i < kNumTestContexts; i++) {
1063 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064
1065 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1066
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001067 CHECK_EQ(i + 1, CountGlobalContexts());
1068
1069 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001070
1071 // Create a handle scope so no function objects get stuch in the outer
1072 // handle scope
1073 v8::HandleScope scope;
1074 const char* source = "function f1() { };"
1075 "function f2() { };"
1076 "function f3() { };"
1077 "function f4() { };"
1078 "function f5() { };";
1079 CompileRun(source);
1080 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1081 CompileRun("f1()");
1082 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1083 CompileRun("f2()");
1084 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1085 CompileRun("f3()");
1086 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1087 CompileRun("f4()");
1088 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1089 CompileRun("f5()");
1090 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1091
1092 // Remove function f1, and
1093 CompileRun("f1=null");
1094
1095 // Scavenge treats these references as strong.
1096 for (int j = 0; j < 10; j++) {
1097 Heap::PerformScavenge();
1098 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1099 }
1100
1101 // Mark compact handles the weak references.
1102 Heap::CollectAllGarbage(true);
1103 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1104
1105 // Get rid of f3 and f5 in the same way.
1106 CompileRun("f3=null");
1107 for (int j = 0; j < 10; j++) {
1108 Heap::PerformScavenge();
1109 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1110 }
1111 Heap::CollectAllGarbage(true);
1112 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1113 CompileRun("f5=null");
1114 for (int j = 0; j < 10; j++) {
1115 Heap::PerformScavenge();
1116 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1117 }
1118 Heap::CollectAllGarbage(true);
1119 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1120
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001121 ctx[i]->Exit();
1122 }
1123
1124 // Force compilation cache cleanup.
1125 Heap::CollectAllGarbage(true);
1126
1127 // Dispose the global contexts one by one.
1128 for (int i = 0; i < kNumTestContexts; i++) {
1129 ctx[i].Dispose();
1130 ctx[i].Clear();
1131
1132 // Scavenge treats these references as strong.
1133 for (int j = 0; j < 10; j++) {
1134 Heap::PerformScavenge();
1135 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1136 }
1137
1138 // Mark compact handles the weak references.
1139 Heap::CollectAllGarbage(true);
1140 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1141 }
1142
1143 CHECK_EQ(0, CountGlobalContexts());
1144}
1145
1146
1147// Count the number of global contexts in the weak list of global contexts
1148// causing a GC after the specified number of elements.
1149static int CountGlobalContextsWithGC(int n) {
1150 int count = 0;
1151 Handle<Object> object(Heap::global_contexts_list());
1152 while (!object->IsUndefined()) {
1153 count++;
1154 if (count == n) Heap::CollectAllGarbage(true);
1155 object =
1156 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1157 }
1158 return count;
1159}
1160
1161
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001162// Count the number of user functions in the weak list of optimized
1163// functions attached to a global context causing a GC after the
1164// specified number of elements.
1165static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1166 int n) {
1167 int count = 0;
1168 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1169 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1170 while (object->IsJSFunction() &&
1171 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1172 count++;
1173 if (count == n) Heap::CollectAllGarbage(true);
1174 object = Handle<Object>(
1175 Object::cast(JSFunction::cast(*object)->next_function_link()));
1176 }
1177 return count;
1178}
1179
1180
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001181TEST(TestInternalWeakListsTraverseWithGC) {
1182 static const int kNumTestContexts = 10;
1183
1184 v8::HandleScope scope;
1185 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1186
1187 CHECK_EQ(0, CountGlobalContexts());
1188
1189 // Create an number of contexts and check the length of the weak list both
1190 // with and without GCs while iterating the list.
1191 for (int i = 0; i < kNumTestContexts; i++) {
1192 ctx[i] = v8::Context::New();
1193 CHECK_EQ(i + 1, CountGlobalContexts());
1194 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001195 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001196
1197 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1198
1199 // Compile a number of functions the length of the weak list of optimized
1200 // functions both with and without GCs while iterating the list.
1201 ctx[0]->Enter();
1202 const char* source = "function f1() { };"
1203 "function f2() { };"
1204 "function f3() { };"
1205 "function f4() { };"
1206 "function f5() { };";
1207 CompileRun(source);
1208 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1209 CompileRun("f1()");
1210 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1211 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1212 CompileRun("f2()");
1213 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1214 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1215 CompileRun("f3()");
1216 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1217 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1218 CompileRun("f4()");
1219 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1220 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1221 CompileRun("f5()");
1222 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1223 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1224
1225 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001226}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001227
1228
1229TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1230 InitializeVM();
1231 intptr_t size_of_objects_1 = Heap::SizeOfObjects();
whesse@chromium.org023421e2010-12-21 12:19:12 +00001232 HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001233 intptr_t size_of_objects_2 = 0;
1234 for (HeapObject* obj = iterator.next();
1235 obj != NULL;
1236 obj = iterator.next()) {
1237 size_of_objects_2 += obj->Size();
1238 }
1239 // Delta must be within 1% of the larger result.
1240 if (size_of_objects_1 > size_of_objects_2) {
1241 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1242 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1243 "Iterator: %" V8_PTR_PREFIX "d, "
1244 "delta: %" V8_PTR_PREFIX "d\n",
1245 size_of_objects_1, size_of_objects_2, delta);
1246 CHECK_GT(size_of_objects_1 / 100, delta);
1247 } else {
1248 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1249 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1250 "Iterator: %" V8_PTR_PREFIX "d, "
1251 "delta: %" V8_PTR_PREFIX "d\n",
1252 size_of_objects_1, size_of_objects_2, delta);
1253 CHECK_GT(size_of_objects_2 / 100, delta);
1254 }
1255}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001256
1257
1258class HeapIteratorTestHelper {
1259 public:
1260 HeapIteratorTestHelper(Object* a, Object* b)
1261 : a_(a), b_(b), a_found_(false), b_found_(false) {}
1262 bool a_found() { return a_found_; }
1263 bool b_found() { return b_found_; }
1264 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
1265 HeapIterator iterator(mode);
1266 for (HeapObject* obj = iterator.next();
1267 obj != NULL;
1268 obj = iterator.next()) {
1269 if (obj == a_)
1270 a_found_ = true;
1271 else if (obj == b_)
1272 b_found_ = true;
1273 }
1274 }
1275 private:
1276 Object* a_;
1277 Object* b_;
1278 bool a_found_;
1279 bool b_found_;
1280};
1281
1282TEST(HeapIteratorFilterUnreachable) {
1283 InitializeVM();
1284 v8::HandleScope scope;
1285 CompileRun("a = {}; b = {};");
1286 v8::Handle<Object> a(Top::context()->global()->GetProperty(
1287 *Factory::LookupAsciiSymbol("a"))->ToObjectChecked());
1288 v8::Handle<Object> b(Top::context()->global()->GetProperty(
1289 *Factory::LookupAsciiSymbol("b"))->ToObjectChecked());
1290 CHECK_NE(*a, *b);
1291 {
1292 HeapIteratorTestHelper helper(*a, *b);
1293 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1294 CHECK(helper.a_found());
1295 CHECK(helper.b_found());
1296 }
1297 CHECK(Top::context()->global()->DeleteProperty(
1298 *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
1299 // We ensure that GC will not happen, so our raw pointer stays valid.
1300 AssertNoAllocation no_alloc;
1301 Object* a_saved = *a;
1302 a.Clear();
1303 // Verify that "a" object still resides in the heap...
1304 {
1305 HeapIteratorTestHelper helper(a_saved, *b);
1306 helper.IterateHeap(HeapIterator::kNoFiltering);
1307 CHECK(helper.a_found());
1308 CHECK(helper.b_found());
1309 }
1310 // ...but is now unreachable.
1311 {
1312 HeapIteratorTestHelper helper(a_saved, *b);
1313 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1314 CHECK(!helper.a_found());
1315 CHECK(helper.b_found());
1316 }
1317}