• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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