1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2
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
13 using namespace v8::internal;
14
15 static v8::Persistent<v8::Context> env;
16
InitializeVM()17 static void InitializeVM() {
18 if (env.IsEmpty()) env = v8::Context::New();
19 v8::HandleScope scope;
20 env->Enter();
21 }
22
23
CheckMap(Map * map,int type,int instance_size)24 static 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
TEST(HeapMaps)35 TEST(HeapMaps) {
36 InitializeVM();
37 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
38 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
39 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
40 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
41 }
42
43
CheckOddball(Object * obj,const char * string)44 static 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
CheckSmi(int value,const char * string)52 static 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
CheckNumber(double value,const char * string)60 static void CheckNumber(double value, const char* string) {
61 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
62 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
CheckFindCodeObject()69 static void CheckFindCodeObject() {
70 // Test FindCodeObject
71 #define __ assm.
72
73 Assembler assm(Isolate::Current(), NULL, 0);
74
75 __ nop(); // supported on all architectures
76
77 CodeDesc desc;
78 assm.GetCode(&desc);
79 Object* code = HEAP->CreateCode(
80 desc,
81 Code::ComputeFlags(Code::STUB),
82 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
83 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
93 Object* copy = HEAP->CreateCode(
94 desc,
95 Code::ComputeFlags(Code::STUB),
96 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
97 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
TEST(HeapObjects)105 TEST(HeapObjects) {
106 InitializeVM();
107
108 v8::HandleScope sc;
109 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
110 CHECK(value->IsHeapNumber());
111 CHECK(value->IsNumber());
112 CHECK_EQ(1.000123, value->Number());
113
114 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
115 CHECK(value->IsSmi());
116 CHECK(value->IsNumber());
117 CHECK_EQ(1.0, value->Number());
118
119 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
120 CHECK(value->IsSmi());
121 CHECK(value->IsNumber());
122 CHECK_EQ(1024.0, value->Number());
123
124 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
125 CHECK(value->IsSmi());
126 CHECK(value->IsNumber());
127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
128
129 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
130 CHECK(value->IsSmi());
131 CHECK(value->IsNumber());
132 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
133
134 #ifndef V8_TARGET_ARCH_X64
135 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
136 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
137 CHECK(value->IsHeapNumber());
138 CHECK(value->IsNumber());
139 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
140 #endif
141
142 MaybeObject* maybe_value =
143 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
144 value = maybe_value->ToObjectChecked();
145 CHECK(value->IsHeapNumber());
146 CHECK(value->IsNumber());
147 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
148 value->Number());
149
150 // nan oddball checks
151 CHECK(HEAP->nan_value()->IsNumber());
152 CHECK(isnan(HEAP->nan_value()->Number()));
153
154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
155 CHECK(s->IsString());
156 CHECK_EQ(10, s->length());
157
158 String* object_symbol = String::cast(HEAP->Object_symbol());
159 CHECK(
160 Isolate::Current()->context()->global()->HasLocalProperty(object_symbol));
161
162 // Check ToString for oddballs
163 CheckOddball(HEAP->true_value(), "true");
164 CheckOddball(HEAP->false_value(), "false");
165 CheckOddball(HEAP->null_value(), "null");
166 CheckOddball(HEAP->undefined_value(), "undefined");
167
168 // Check ToString for Smis
169 CheckSmi(0, "0");
170 CheckSmi(42, "42");
171 CheckSmi(-42, "-42");
172
173 // Check ToString for Numbers
174 CheckNumber(1.1, "1.1");
175
176 CheckFindCodeObject();
177 }
178
179
TEST(Tagging)180 TEST(Tagging) {
181 InitializeVM();
182 int request = 24;
183 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
184 CHECK(Smi::FromInt(42)->IsSmi());
185 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
186 CHECK_EQ(NEW_SPACE,
187 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
188 CHECK_EQ(OLD_POINTER_SPACE,
189 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
190 CHECK(Failure::Exception()->IsFailure());
191 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
192 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
193 }
194
195
TEST(GarbageCollection)196 TEST(GarbageCollection) {
197 InitializeVM();
198
199 v8::HandleScope sc;
200 // Check GC.
201 HEAP->CollectGarbage(NEW_SPACE);
202
203 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
204 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
205 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
206 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
207
208 {
209 v8::HandleScope inner_scope;
210 // Allocate a function and keep it in global object's property.
211 Handle<JSFunction> function =
212 FACTORY->NewFunction(name, FACTORY->undefined_value());
213 Handle<Map> initial_map =
214 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
215 function->set_initial_map(*initial_map);
216 Isolate::Current()->context()->global()->SetProperty(
217 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
218 // Allocate an object. Unrooted after leaving the scope.
219 Handle<JSObject> obj = FACTORY->NewJSObject(function);
220 obj->SetProperty(
221 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
222 obj->SetProperty(
223 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
224
225 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
226 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
227 }
228
229 HEAP->CollectGarbage(NEW_SPACE);
230
231 // Function should be alive.
232 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name));
233 // Check function is retained.
234 Object* func_value = Isolate::Current()->context()->global()->
235 GetProperty(*name)->ToObjectChecked();
236 CHECK(func_value->IsJSFunction());
237 Handle<JSFunction> function(JSFunction::cast(func_value));
238
239 {
240 HandleScope inner_scope;
241 // Allocate another object, make it reachable from global.
242 Handle<JSObject> obj = FACTORY->NewJSObject(function);
243 Isolate::Current()->context()->global()->SetProperty(
244 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
245 obj->SetProperty(
246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
247 }
248
249 // After gc, it should survive.
250 HEAP->CollectGarbage(NEW_SPACE);
251
252 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name));
253 CHECK(Isolate::Current()->context()->global()->
254 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
255 Object* obj = Isolate::Current()->context()->global()->
256 GetProperty(*obj_name)->ToObjectChecked();
257 JSObject* js_obj = JSObject::cast(obj);
258 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
259 }
260
261
VerifyStringAllocation(const char * string)262 static void VerifyStringAllocation(const char* string) {
263 v8::HandleScope scope;
264 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
265 CHECK_EQ(StrLength(string), s->length());
266 for (int index = 0; index < s->length(); index++) {
267 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
268 }
269 }
270
271
TEST(String)272 TEST(String) {
273 InitializeVM();
274
275 VerifyStringAllocation("a");
276 VerifyStringAllocation("ab");
277 VerifyStringAllocation("abc");
278 VerifyStringAllocation("abcd");
279 VerifyStringAllocation("fiskerdrengen er paa havet");
280 }
281
282
TEST(LocalHandles)283 TEST(LocalHandles) {
284 InitializeVM();
285
286 v8::HandleScope scope;
287 const char* name = "Kasper the spunky";
288 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
289 CHECK_EQ(StrLength(name), string->length());
290 }
291
292
TEST(GlobalHandles)293 TEST(GlobalHandles) {
294 InitializeVM();
295 GlobalHandles* global_handles = Isolate::Current()->global_handles();
296
297 Handle<Object> h1;
298 Handle<Object> h2;
299 Handle<Object> h3;
300 Handle<Object> h4;
301
302 {
303 HandleScope scope;
304
305 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
306 Handle<Object> u = FACTORY->NewNumber(1.12344);
307
308 h1 = global_handles->Create(*i);
309 h2 = global_handles->Create(*u);
310 h3 = global_handles->Create(*i);
311 h4 = global_handles->Create(*u);
312 }
313
314 // after gc, it should survive
315 HEAP->CollectGarbage(NEW_SPACE);
316
317 CHECK((*h1)->IsString());
318 CHECK((*h2)->IsHeapNumber());
319 CHECK((*h3)->IsString());
320 CHECK((*h4)->IsHeapNumber());
321
322 CHECK_EQ(*h3, *h1);
323 global_handles->Destroy(h1.location());
324 global_handles->Destroy(h3.location());
325
326 CHECK_EQ(*h4, *h2);
327 global_handles->Destroy(h2.location());
328 global_handles->Destroy(h4.location());
329 }
330
331
332 static bool WeakPointerCleared = false;
333
TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,void * id)334 static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
335 void* id) {
336 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
337 handle.Dispose();
338 }
339
340
TEST(WeakGlobalHandlesScavenge)341 TEST(WeakGlobalHandlesScavenge) {
342 InitializeVM();
343 GlobalHandles* global_handles = Isolate::Current()->global_handles();
344
345 WeakPointerCleared = false;
346
347 Handle<Object> h1;
348 Handle<Object> h2;
349
350 {
351 HandleScope scope;
352
353 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
354 Handle<Object> u = FACTORY->NewNumber(1.12344);
355
356 h1 = global_handles->Create(*i);
357 h2 = global_handles->Create(*u);
358 }
359
360 global_handles->MakeWeak(h2.location(),
361 reinterpret_cast<void*>(1234),
362 &TestWeakGlobalHandleCallback);
363
364 // Scavenge treats weak pointers as normal roots.
365 HEAP->PerformScavenge();
366
367 CHECK((*h1)->IsString());
368 CHECK((*h2)->IsHeapNumber());
369
370 CHECK(!WeakPointerCleared);
371 CHECK(!global_handles->IsNearDeath(h2.location()));
372 CHECK(!global_handles->IsNearDeath(h1.location()));
373
374 global_handles->Destroy(h1.location());
375 global_handles->Destroy(h2.location());
376 }
377
378
TEST(WeakGlobalHandlesMark)379 TEST(WeakGlobalHandlesMark) {
380 InitializeVM();
381 GlobalHandles* global_handles = Isolate::Current()->global_handles();
382
383 WeakPointerCleared = false;
384
385 Handle<Object> h1;
386 Handle<Object> h2;
387
388 {
389 HandleScope scope;
390
391 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
392 Handle<Object> u = FACTORY->NewNumber(1.12344);
393
394 h1 = global_handles->Create(*i);
395 h2 = global_handles->Create(*u);
396 }
397
398 HEAP->CollectGarbage(OLD_POINTER_SPACE);
399 HEAP->CollectGarbage(NEW_SPACE);
400 // Make sure the object is promoted.
401
402 global_handles->MakeWeak(h2.location(),
403 reinterpret_cast<void*>(1234),
404 &TestWeakGlobalHandleCallback);
405 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
406 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
407
408 HEAP->CollectGarbage(OLD_POINTER_SPACE);
409
410 CHECK((*h1)->IsString());
411
412 CHECK(WeakPointerCleared);
413 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
414
415 global_handles->Destroy(h1.location());
416 }
417
TEST(DeleteWeakGlobalHandle)418 TEST(DeleteWeakGlobalHandle) {
419 InitializeVM();
420 GlobalHandles* global_handles = Isolate::Current()->global_handles();
421
422 WeakPointerCleared = false;
423
424 Handle<Object> h;
425
426 {
427 HandleScope scope;
428
429 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
430 h = global_handles->Create(*i);
431 }
432
433 global_handles->MakeWeak(h.location(),
434 reinterpret_cast<void*>(1234),
435 &TestWeakGlobalHandleCallback);
436
437 // Scanvenge does not recognize weak reference.
438 HEAP->PerformScavenge();
439
440 CHECK(!WeakPointerCleared);
441
442 // Mark-compact treats weak reference properly.
443 HEAP->CollectGarbage(OLD_POINTER_SPACE);
444
445 CHECK(WeakPointerCleared);
446 }
447
448 static const char* not_so_random_string_table[] = {
449 "abstract",
450 "boolean",
451 "break",
452 "byte",
453 "case",
454 "catch",
455 "char",
456 "class",
457 "const",
458 "continue",
459 "debugger",
460 "default",
461 "delete",
462 "do",
463 "double",
464 "else",
465 "enum",
466 "export",
467 "extends",
468 "false",
469 "final",
470 "finally",
471 "float",
472 "for",
473 "function",
474 "goto",
475 "if",
476 "implements",
477 "import",
478 "in",
479 "instanceof",
480 "int",
481 "interface",
482 "long",
483 "native",
484 "new",
485 "null",
486 "package",
487 "private",
488 "protected",
489 "public",
490 "return",
491 "short",
492 "static",
493 "super",
494 "switch",
495 "synchronized",
496 "this",
497 "throw",
498 "throws",
499 "transient",
500 "true",
501 "try",
502 "typeof",
503 "var",
504 "void",
505 "volatile",
506 "while",
507 "with",
508 0
509 };
510
511
CheckSymbols(const char ** strings)512 static void CheckSymbols(const char** strings) {
513 for (const char* string = *strings; *strings != 0; string = *strings++) {
514 Object* a;
515 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
516 // LookupAsciiSymbol may return a failure if a GC is needed.
517 if (!maybe_a->ToObject(&a)) continue;
518 CHECK(a->IsSymbol());
519 Object* b;
520 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
521 if (!maybe_b->ToObject(&b)) continue;
522 CHECK_EQ(b, a);
523 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
524 }
525 }
526
527
TEST(SymbolTable)528 TEST(SymbolTable) {
529 InitializeVM();
530
531 CheckSymbols(not_so_random_string_table);
532 CheckSymbols(not_so_random_string_table);
533 }
534
535
TEST(FunctionAllocation)536 TEST(FunctionAllocation) {
537 InitializeVM();
538
539 v8::HandleScope sc;
540 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
541 Handle<JSFunction> function =
542 FACTORY->NewFunction(name, FACTORY->undefined_value());
543 Handle<Map> initial_map =
544 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
545 function->set_initial_map(*initial_map);
546
547 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
548 Handle<JSObject> obj = FACTORY->NewJSObject(function);
549 obj->SetProperty(
550 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
551 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
552 // Check that we can add properties to function objects.
553 function->SetProperty(
554 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
555 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
556 }
557
558
TEST(ObjectProperties)559 TEST(ObjectProperties) {
560 InitializeVM();
561
562 v8::HandleScope sc;
563 String* object_symbol = String::cast(HEAP->Object_symbol());
564 Object* raw_object = Isolate::Current()->context()->global()->
565 GetProperty(object_symbol)->ToObjectChecked();
566 JSFunction* object_function = JSFunction::cast(raw_object);
567 Handle<JSFunction> constructor(object_function);
568 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
569 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
570 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
571
572 // check for empty
573 CHECK(!obj->HasLocalProperty(*first));
574
575 // add first
576 obj->SetProperty(
577 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
578 CHECK(obj->HasLocalProperty(*first));
579
580 // delete first
581 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
582 CHECK(!obj->HasLocalProperty(*first));
583
584 // add first and then second
585 obj->SetProperty(
586 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
587 obj->SetProperty(
588 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
589 CHECK(obj->HasLocalProperty(*first));
590 CHECK(obj->HasLocalProperty(*second));
591
592 // delete first and then second
593 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
594 CHECK(obj->HasLocalProperty(*second));
595 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
596 CHECK(!obj->HasLocalProperty(*first));
597 CHECK(!obj->HasLocalProperty(*second));
598
599 // add first and then second
600 obj->SetProperty(
601 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
602 obj->SetProperty(
603 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
604 CHECK(obj->HasLocalProperty(*first));
605 CHECK(obj->HasLocalProperty(*second));
606
607 // delete second and then first
608 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
609 CHECK(obj->HasLocalProperty(*first));
610 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
611 CHECK(!obj->HasLocalProperty(*first));
612 CHECK(!obj->HasLocalProperty(*second));
613
614 // check string and symbol match
615 static const char* string1 = "fisk";
616 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
617 obj->SetProperty(
618 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
619 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
620 CHECK(obj->HasLocalProperty(*s1_symbol));
621
622 // check symbol and string match
623 static const char* string2 = "fugl";
624 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
625 obj->SetProperty(
626 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
627 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
628 CHECK(obj->HasLocalProperty(*s2));
629 }
630
631
TEST(JSObjectMaps)632 TEST(JSObjectMaps) {
633 InitializeVM();
634
635 v8::HandleScope sc;
636 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
637 Handle<JSFunction> function =
638 FACTORY->NewFunction(name, FACTORY->undefined_value());
639 Handle<Map> initial_map =
640 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
641 function->set_initial_map(*initial_map);
642
643 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
644 Handle<JSObject> obj = FACTORY->NewJSObject(function);
645
646 // Set a propery
647 obj->SetProperty(
648 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
649 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
650
651 // Check the map has changed
652 CHECK(*initial_map != obj->map());
653 }
654
655
TEST(JSArray)656 TEST(JSArray) {
657 InitializeVM();
658
659 v8::HandleScope sc;
660 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
661 Object* raw_object = Isolate::Current()->context()->global()->
662 GetProperty(*name)->ToObjectChecked();
663 Handle<JSFunction> function = Handle<JSFunction>(
664 JSFunction::cast(raw_object));
665
666 // Allocate the object.
667 Handle<JSObject> object = FACTORY->NewJSObject(function);
668 Handle<JSArray> array = Handle<JSArray>::cast(object);
669 // We just initialized the VM, no heap allocation failure yet.
670 Object* ok = array->Initialize(0)->ToObjectChecked();
671
672 // Set array length to 0.
673 ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
674 CHECK_EQ(Smi::FromInt(0), array->length());
675 CHECK(array->HasFastElements()); // Must be in fast mode.
676
677 // array[length] = name.
678 ok = array->SetElement(0, *name, kNonStrictMode)->ToObjectChecked();
679 CHECK_EQ(Smi::FromInt(1), array->length());
680 CHECK_EQ(array->GetElement(0), *name);
681
682 // Set array length with larger than smi value.
683 Handle<Object> length =
684 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
685 ok = array->SetElementsLength(*length)->ToObjectChecked();
686
687 uint32_t int_length = 0;
688 CHECK(length->ToArrayIndex(&int_length));
689 CHECK_EQ(*length, array->length());
690 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
691
692 // array[length] = name.
693 ok = array->SetElement(int_length, *name, kNonStrictMode)->ToObjectChecked();
694 uint32_t new_int_length = 0;
695 CHECK(array->length()->ToArrayIndex(&new_int_length));
696 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
697 CHECK_EQ(array->GetElement(int_length), *name);
698 CHECK_EQ(array->GetElement(0), *name);
699 }
700
701
TEST(JSObjectCopy)702 TEST(JSObjectCopy) {
703 InitializeVM();
704
705 v8::HandleScope sc;
706 String* object_symbol = String::cast(HEAP->Object_symbol());
707 Object* raw_object = Isolate::Current()->context()->global()->
708 GetProperty(object_symbol)->ToObjectChecked();
709 JSFunction* object_function = JSFunction::cast(raw_object);
710 Handle<JSFunction> constructor(object_function);
711 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
712 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
713 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
714
715 obj->SetProperty(
716 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
717 obj->SetProperty(
718 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
719
720 Object* ok = obj->SetElement(0, *first, kNonStrictMode)->ToObjectChecked();
721
722 ok = obj->SetElement(1, *second, kNonStrictMode)->ToObjectChecked();
723
724 // Make the clone.
725 Handle<JSObject> clone = Copy(obj);
726 CHECK(!clone.is_identical_to(obj));
727
728 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
729 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
730
731 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
732 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
733
734 // Flip the values.
735 clone->SetProperty(
736 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
737 clone->SetProperty(
738 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
739
740 ok = clone->SetElement(0, *second, kNonStrictMode)->ToObjectChecked();
741 ok = clone->SetElement(1, *first, kNonStrictMode)->ToObjectChecked();
742
743 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
744 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
745
746 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
747 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
748 }
749
750
TEST(StringAllocation)751 TEST(StringAllocation) {
752 InitializeVM();
753
754
755 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
756 for (int length = 0; length < 100; length++) {
757 v8::HandleScope scope;
758 char* non_ascii = NewArray<char>(3 * length + 1);
759 char* ascii = NewArray<char>(length + 1);
760 non_ascii[3 * length] = 0;
761 ascii[length] = 0;
762 for (int i = 0; i < length; i++) {
763 ascii[i] = 'a';
764 non_ascii[3 * i] = chars[0];
765 non_ascii[3 * i + 1] = chars[1];
766 non_ascii[3 * i + 2] = chars[2];
767 }
768 Handle<String> non_ascii_sym =
769 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
770 CHECK_EQ(length, non_ascii_sym->length());
771 Handle<String> ascii_sym =
772 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
773 CHECK_EQ(length, ascii_sym->length());
774 Handle<String> non_ascii_str =
775 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
776 non_ascii_str->Hash();
777 CHECK_EQ(length, non_ascii_str->length());
778 Handle<String> ascii_str =
779 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
780 ascii_str->Hash();
781 CHECK_EQ(length, ascii_str->length());
782 DeleteArray(non_ascii);
783 DeleteArray(ascii);
784 }
785 }
786
787
ObjectsFoundInHeap(Handle<Object> objs[],int size)788 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
789 // Count the number of objects found in the heap.
790 int found_count = 0;
791 HeapIterator iterator;
792 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
793 for (int i = 0; i < size; i++) {
794 if (*objs[i] == obj) {
795 found_count++;
796 }
797 }
798 }
799 return found_count;
800 }
801
802
TEST(Iteration)803 TEST(Iteration) {
804 InitializeVM();
805 v8::HandleScope scope;
806
807 // Array of objects to scan haep for.
808 const int objs_count = 6;
809 Handle<Object> objs[objs_count];
810 int next_objs_index = 0;
811
812 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
813 objs[next_objs_index++] = FACTORY->NewJSArray(10);
814 objs[next_objs_index++] = FACTORY->NewJSArray(10, TENURED);
815
816 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
817 objs[next_objs_index++] =
818 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
819 objs[next_objs_index++] =
820 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
821
822 // Allocate a large string (for large object space).
823 int large_size = HEAP->MaxObjectSizeInPagedSpace() + 1;
824 char* str = new char[large_size];
825 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
826 str[large_size - 1] = '\0';
827 objs[next_objs_index++] =
828 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
829 delete[] str;
830
831 // Add a Map object to look for.
832 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
833
834 CHECK_EQ(objs_count, next_objs_index);
835 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
836 }
837
838
TEST(LargeObjectSpaceContains)839 TEST(LargeObjectSpaceContains) {
840 InitializeVM();
841
842 HEAP->CollectGarbage(NEW_SPACE);
843
844 Address current_top = HEAP->new_space()->top();
845 Page* page = Page::FromAddress(current_top);
846 Address current_page = page->address();
847 Address next_page = current_page + Page::kPageSize;
848 int bytes_to_page = static_cast<int>(next_page - current_top);
849 if (bytes_to_page <= FixedArray::kHeaderSize) {
850 // Alas, need to cross another page to be able to
851 // put desired value.
852 next_page += Page::kPageSize;
853 bytes_to_page = static_cast<int>(next_page - current_top);
854 }
855 CHECK(bytes_to_page > FixedArray::kHeaderSize);
856
857 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_;
858 Address flags_addr = reinterpret_cast<Address>(flags_ptr);
859
860 int bytes_to_allocate =
861 static_cast<int>(flags_addr - current_top) + kPointerSize;
862
863 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) /
864 kPointerSize;
865 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
866 FixedArray* array = FixedArray::cast(
867 HEAP->AllocateFixedArray(n_elements)->ToObjectChecked());
868
869 int index = n_elements - 1;
870 CHECK_EQ(flags_ptr,
871 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index)));
872 array->set(index, Smi::FromInt(0));
873 // This chould have turned next page into LargeObjectPage:
874 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
875
876 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
877 CHECK(HEAP->new_space()->Contains(addr));
878 CHECK(!HEAP->lo_space()->Contains(addr));
879 }
880
881
TEST(EmptyHandleEscapeFrom)882 TEST(EmptyHandleEscapeFrom) {
883 InitializeVM();
884
885 v8::HandleScope scope;
886 Handle<JSObject> runaway;
887
888 {
889 v8::HandleScope nested;
890 Handle<JSObject> empty;
891 runaway = empty.EscapeFrom(&nested);
892 }
893
894 CHECK(runaway.is_null());
895 }
896
897
LenFromSize(int size)898 static int LenFromSize(int size) {
899 return (size - FixedArray::kHeaderSize) / kPointerSize;
900 }
901
902
TEST(Regression39128)903 TEST(Regression39128) {
904 // Test case for crbug.com/39128.
905 InitializeVM();
906
907 // Increase the chance of 'bump-the-pointer' allocation in old space.
908 bool force_compaction = true;
909 HEAP->CollectAllGarbage(force_compaction);
910
911 v8::HandleScope scope;
912
913 // The plan: create JSObject which references objects in new space.
914 // Then clone this object (forcing it to go into old space) and check
915 // that region dirty marks are updated correctly.
916
917 // Step 1: prepare a map for the object. We add 1 inobject property to it.
918 Handle<JSFunction> object_ctor(
919 Isolate::Current()->global_context()->object_function());
920 CHECK(object_ctor->has_initial_map());
921 Handle<Map> object_map(object_ctor->initial_map());
922 // Create a map with single inobject property.
923 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
924 int n_properties = my_map->inobject_properties();
925 CHECK_GT(n_properties, 0);
926
927 int object_size = my_map->instance_size();
928
929 // Step 2: allocate a lot of objects so to almost fill new space: we need
930 // just enough room to allocate JSObject and thus fill the newspace.
931
932 int allocation_amount = Min(FixedArray::kMaxSize,
933 HEAP->MaxObjectSizeInNewSpace());
934 int allocation_len = LenFromSize(allocation_amount);
935 NewSpace* new_space = HEAP->new_space();
936 Address* top_addr = new_space->allocation_top_address();
937 Address* limit_addr = new_space->allocation_limit_address();
938 while ((*limit_addr - *top_addr) > allocation_amount) {
939 CHECK(!HEAP->always_allocate());
940 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
941 CHECK(!array->IsFailure());
942 CHECK(new_space->Contains(array));
943 }
944
945 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
946 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
947 int fixed_array_len = LenFromSize(to_fill);
948 CHECK(fixed_array_len < FixedArray::kMaxLength);
949
950 CHECK(!HEAP->always_allocate());
951 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
952 CHECK(!array->IsFailure());
953 CHECK(new_space->Contains(array));
954
955 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
956 CHECK(new_space->Contains(object));
957 JSObject* jsobject = JSObject::cast(object);
958 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
959 CHECK_EQ(0, jsobject->properties()->length());
960 // Create a reference to object in new space in jsobject.
961 jsobject->FastPropertyAtPut(-1, array);
962
963 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
964
965 // Step 4: clone jsobject, but force always allocate first to create a clone
966 // in old pointer space.
967 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
968 AlwaysAllocateScope aa_scope;
969 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
970 JSObject* clone = JSObject::cast(clone_obj);
971 if (clone->address() != old_pointer_space_top) {
972 // Alas, got allocated from free list, we cannot do checks.
973 return;
974 }
975 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
976
977 // Step 5: verify validity of region dirty marks.
978 Address clone_addr = clone->address();
979 Page* page = Page::FromAddress(clone_addr);
980 // Check that region covering inobject property 1 is marked dirty.
981 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
982 }
983
984
TEST(TestCodeFlushing)985 TEST(TestCodeFlushing) {
986 i::FLAG_allow_natives_syntax = true;
987 // If we do not flush code this test is invalid.
988 if (!FLAG_flush_code) return;
989 InitializeVM();
990 v8::HandleScope scope;
991 const char* source = "function foo() {"
992 " var x = 42;"
993 " var y = 42;"
994 " var z = x + y;"
995 "};"
996 "foo()";
997 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
998
999 // This compile will add the code to the compilation cache.
1000 { v8::HandleScope scope;
1001 CompileRun(source);
1002 }
1003
1004 // Check function is compiled.
1005 Object* func_value = Isolate::Current()->context()->global()->
1006 GetProperty(*foo_name)->ToObjectChecked();
1007 CHECK(func_value->IsJSFunction());
1008 Handle<JSFunction> function(JSFunction::cast(func_value));
1009 CHECK(function->shared()->is_compiled());
1010
1011 HEAP->CollectAllGarbage(true);
1012 HEAP->CollectAllGarbage(true);
1013
1014 CHECK(function->shared()->is_compiled());
1015
1016 HEAP->CollectAllGarbage(true);
1017 HEAP->CollectAllGarbage(true);
1018 HEAP->CollectAllGarbage(true);
1019 HEAP->CollectAllGarbage(true);
1020 HEAP->CollectAllGarbage(true);
1021 HEAP->CollectAllGarbage(true);
1022
1023 // foo should no longer be in the compilation cache
1024 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1025 CHECK(!function->is_compiled() || function->IsOptimized());
1026 // Call foo to get it recompiled.
1027 CompileRun("foo()");
1028 CHECK(function->shared()->is_compiled());
1029 CHECK(function->is_compiled());
1030 }
1031
1032
1033 // Count the number of global contexts in the weak list of global contexts.
CountGlobalContexts()1034 static int CountGlobalContexts() {
1035 int count = 0;
1036 Object* object = HEAP->global_contexts_list();
1037 while (!object->IsUndefined()) {
1038 count++;
1039 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1040 }
1041 return count;
1042 }
1043
1044
1045 // Count the number of user functions in the weak list of optimized
1046 // functions attached to a global context.
CountOptimizedUserFunctions(v8::Handle<v8::Context> context)1047 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1048 int count = 0;
1049 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1050 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1051 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1052 count++;
1053 object = JSFunction::cast(object)->next_function_link();
1054 }
1055 return count;
1056 }
1057
1058
TEST(TestInternalWeakLists)1059 TEST(TestInternalWeakLists) {
1060 v8::V8::Initialize();
1061
1062 static const int kNumTestContexts = 10;
1063
1064 v8::HandleScope scope;
1065 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1066
1067 CHECK_EQ(0, CountGlobalContexts());
1068
1069 // Create a number of global contests which gets linked together.
1070 for (int i = 0; i < kNumTestContexts; i++) {
1071 ctx[i] = v8::Context::New();
1072
1073 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1074
1075 CHECK_EQ(i + 1, CountGlobalContexts());
1076
1077 ctx[i]->Enter();
1078
1079 // Create a handle scope so no function objects get stuch in the outer
1080 // handle scope
1081 v8::HandleScope scope;
1082 const char* source = "function f1() { };"
1083 "function f2() { };"
1084 "function f3() { };"
1085 "function f4() { };"
1086 "function f5() { };";
1087 CompileRun(source);
1088 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1089 CompileRun("f1()");
1090 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1091 CompileRun("f2()");
1092 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1093 CompileRun("f3()");
1094 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1095 CompileRun("f4()");
1096 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1097 CompileRun("f5()");
1098 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1099
1100 // Remove function f1, and
1101 CompileRun("f1=null");
1102
1103 // Scavenge treats these references as strong.
1104 for (int j = 0; j < 10; j++) {
1105 HEAP->PerformScavenge();
1106 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1107 }
1108
1109 // Mark compact handles the weak references.
1110 HEAP->CollectAllGarbage(true);
1111 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1112
1113 // Get rid of f3 and f5 in the same way.
1114 CompileRun("f3=null");
1115 for (int j = 0; j < 10; j++) {
1116 HEAP->PerformScavenge();
1117 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1118 }
1119 HEAP->CollectAllGarbage(true);
1120 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1121 CompileRun("f5=null");
1122 for (int j = 0; j < 10; j++) {
1123 HEAP->PerformScavenge();
1124 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1125 }
1126 HEAP->CollectAllGarbage(true);
1127 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1128
1129 ctx[i]->Exit();
1130 }
1131
1132 // Force compilation cache cleanup.
1133 HEAP->CollectAllGarbage(true);
1134
1135 // Dispose the global contexts one by one.
1136 for (int i = 0; i < kNumTestContexts; i++) {
1137 ctx[i].Dispose();
1138 ctx[i].Clear();
1139
1140 // Scavenge treats these references as strong.
1141 for (int j = 0; j < 10; j++) {
1142 HEAP->PerformScavenge();
1143 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1144 }
1145
1146 // Mark compact handles the weak references.
1147 HEAP->CollectAllGarbage(true);
1148 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1149 }
1150
1151 CHECK_EQ(0, CountGlobalContexts());
1152 }
1153
1154
1155 // Count the number of global contexts in the weak list of global contexts
1156 // causing a GC after the specified number of elements.
CountGlobalContextsWithGC(int n)1157 static int CountGlobalContextsWithGC(int n) {
1158 int count = 0;
1159 Handle<Object> object(HEAP->global_contexts_list());
1160 while (!object->IsUndefined()) {
1161 count++;
1162 if (count == n) HEAP->CollectAllGarbage(true);
1163 object =
1164 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1165 }
1166 return count;
1167 }
1168
1169
1170 // Count the number of user functions in the weak list of optimized
1171 // functions attached to a global context causing a GC after the
1172 // specified number of elements.
CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,int n)1173 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1174 int n) {
1175 int count = 0;
1176 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1177 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1178 while (object->IsJSFunction() &&
1179 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1180 count++;
1181 if (count == n) HEAP->CollectAllGarbage(true);
1182 object = Handle<Object>(
1183 Object::cast(JSFunction::cast(*object)->next_function_link()));
1184 }
1185 return count;
1186 }
1187
1188
TEST(TestInternalWeakListsTraverseWithGC)1189 TEST(TestInternalWeakListsTraverseWithGC) {
1190 v8::V8::Initialize();
1191
1192 static const int kNumTestContexts = 10;
1193
1194 v8::HandleScope scope;
1195 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1196
1197 CHECK_EQ(0, CountGlobalContexts());
1198
1199 // Create an number of contexts and check the length of the weak list both
1200 // with and without GCs while iterating the list.
1201 for (int i = 0; i < kNumTestContexts; i++) {
1202 ctx[i] = v8::Context::New();
1203 CHECK_EQ(i + 1, CountGlobalContexts());
1204 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
1205 }
1206
1207 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1208
1209 // Compile a number of functions the length of the weak list of optimized
1210 // functions both with and without GCs while iterating the list.
1211 ctx[0]->Enter();
1212 const char* source = "function f1() { };"
1213 "function f2() { };"
1214 "function f3() { };"
1215 "function f4() { };"
1216 "function f5() { };";
1217 CompileRun(source);
1218 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1219 CompileRun("f1()");
1220 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1221 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1222 CompileRun("f2()");
1223 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1224 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1225 CompileRun("f3()");
1226 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1227 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1228 CompileRun("f4()");
1229 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1230 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1231 CompileRun("f5()");
1232 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1233 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1234
1235 ctx[0]->Exit();
1236 }
1237
1238
TEST(TestSizeOfObjectsVsHeapIteratorPrecision)1239 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1240 InitializeVM();
1241 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
1242 HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
1243 intptr_t size_of_objects_2 = 0;
1244 for (HeapObject* obj = iterator.next();
1245 obj != NULL;
1246 obj = iterator.next()) {
1247 size_of_objects_2 += obj->Size();
1248 }
1249 // Delta must be within 1% of the larger result.
1250 if (size_of_objects_1 > size_of_objects_2) {
1251 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1252 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1253 "Iterator: %" V8_PTR_PREFIX "d, "
1254 "delta: %" V8_PTR_PREFIX "d\n",
1255 size_of_objects_1, size_of_objects_2, delta);
1256 CHECK_GT(size_of_objects_1 / 100, delta);
1257 } else {
1258 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1259 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1260 "Iterator: %" V8_PTR_PREFIX "d, "
1261 "delta: %" V8_PTR_PREFIX "d\n",
1262 size_of_objects_1, size_of_objects_2, delta);
1263 CHECK_GT(size_of_objects_2 / 100, delta);
1264 }
1265 }
1266
1267
1268 class HeapIteratorTestHelper {
1269 public:
HeapIteratorTestHelper(Object * a,Object * b)1270 HeapIteratorTestHelper(Object* a, Object* b)
1271 : a_(a), b_(b), a_found_(false), b_found_(false) {}
a_found()1272 bool a_found() { return a_found_; }
b_found()1273 bool b_found() { return b_found_; }
IterateHeap(HeapIterator::HeapObjectsFiltering mode)1274 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
1275 HeapIterator iterator(mode);
1276 for (HeapObject* obj = iterator.next();
1277 obj != NULL;
1278 obj = iterator.next()) {
1279 if (obj == a_)
1280 a_found_ = true;
1281 else if (obj == b_)
1282 b_found_ = true;
1283 }
1284 }
1285 private:
1286 Object* a_;
1287 Object* b_;
1288 bool a_found_;
1289 bool b_found_;
1290 };
1291
TEST(HeapIteratorFilterUnreachable)1292 TEST(HeapIteratorFilterUnreachable) {
1293 InitializeVM();
1294 v8::HandleScope scope;
1295 CompileRun("a = {}; b = {};");
1296 v8::Handle<Object> a(ISOLATE->context()->global()->GetProperty(
1297 *FACTORY->LookupAsciiSymbol("a"))->ToObjectChecked());
1298 v8::Handle<Object> b(ISOLATE->context()->global()->GetProperty(
1299 *FACTORY->LookupAsciiSymbol("b"))->ToObjectChecked());
1300 CHECK_NE(*a, *b);
1301 {
1302 HeapIteratorTestHelper helper(*a, *b);
1303 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1304 CHECK(helper.a_found());
1305 CHECK(helper.b_found());
1306 }
1307 CHECK(ISOLATE->context()->global()->DeleteProperty(
1308 *FACTORY->LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
1309 // We ensure that GC will not happen, so our raw pointer stays valid.
1310 AssertNoAllocation no_alloc;
1311 Object* a_saved = *a;
1312 a.Clear();
1313 // Verify that "a" object still resides in the heap...
1314 {
1315 HeapIteratorTestHelper helper(a_saved, *b);
1316 helper.IterateHeap(HeapIterator::kNoFiltering);
1317 CHECK(helper.a_found());
1318 CHECK(helper.b_found());
1319 }
1320 // ...but is now unreachable.
1321 {
1322 HeapIteratorTestHelper helper(a_saved, *b);
1323 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1324 CHECK(!helper.a_found());
1325 CHECK(helper.b_found());
1326 }
1327 }
1328