• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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   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   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   array->Initialize(0)->ToObjectChecked();
671 
672   // Set array length to 0.
673   array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
674   CHECK_EQ(Smi::FromInt(0), array->length());
675   // Must be in fast mode.
676   CHECK(array->HasFastTypeElements());
677 
678   // array[length] = name.
679   array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
680   CHECK_EQ(Smi::FromInt(1), array->length());
681   CHECK_EQ(array->GetElement(0), *name);
682 
683   // Set array length with larger than smi value.
684   Handle<Object> length =
685       FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
686   array->SetElementsLength(*length)->ToObjectChecked();
687 
688   uint32_t int_length = 0;
689   CHECK(length->ToArrayIndex(&int_length));
690   CHECK_EQ(*length, array->length());
691   CHECK(array->HasDictionaryElements());  // Must be in slow mode.
692 
693   // array[length] = name.
694   array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
695   uint32_t new_int_length = 0;
696   CHECK(array->length()->ToArrayIndex(&new_int_length));
697   CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
698   CHECK_EQ(array->GetElement(int_length), *name);
699   CHECK_EQ(array->GetElement(0), *name);
700 }
701 
702 
TEST(JSObjectCopy)703 TEST(JSObjectCopy) {
704   InitializeVM();
705 
706   v8::HandleScope sc;
707   String* object_symbol = String::cast(HEAP->Object_symbol());
708   Object* raw_object = Isolate::Current()->context()->global()->
709       GetProperty(object_symbol)->ToObjectChecked();
710   JSFunction* object_function = JSFunction::cast(raw_object);
711   Handle<JSFunction> constructor(object_function);
712   Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
713   Handle<String> first = FACTORY->LookupAsciiSymbol("first");
714   Handle<String> second = FACTORY->LookupAsciiSymbol("second");
715 
716   obj->SetProperty(
717       *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
718   obj->SetProperty(
719       *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
720 
721   obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
722   obj->SetElement(1, *second, NONE, 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   clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
741   clone->SetElement(1, *first, NONE, 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, FAST_ELEMENTS, 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 = Page::kMaxNonCodeHeapObjectSize + 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(EmptyHandleEscapeFrom)839 TEST(EmptyHandleEscapeFrom) {
840   InitializeVM();
841 
842   v8::HandleScope scope;
843   Handle<JSObject> runaway;
844 
845   {
846       v8::HandleScope nested;
847       Handle<JSObject> empty;
848       runaway = empty.EscapeFrom(&nested);
849   }
850 
851   CHECK(runaway.is_null());
852 }
853 
854 
LenFromSize(int size)855 static int LenFromSize(int size) {
856   return (size - FixedArray::kHeaderSize) / kPointerSize;
857 }
858 
859 
TEST(Regression39128)860 TEST(Regression39128) {
861   // Test case for crbug.com/39128.
862   InitializeVM();
863 
864   // Increase the chance of 'bump-the-pointer' allocation in old space.
865   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
866 
867   v8::HandleScope scope;
868 
869   // The plan: create JSObject which references objects in new space.
870   // Then clone this object (forcing it to go into old space) and check
871   // that region dirty marks are updated correctly.
872 
873   // Step 1: prepare a map for the object.  We add 1 inobject property to it.
874   Handle<JSFunction> object_ctor(
875       Isolate::Current()->global_context()->object_function());
876   CHECK(object_ctor->has_initial_map());
877   Handle<Map> object_map(object_ctor->initial_map());
878   // Create a map with single inobject property.
879   Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
880   int n_properties = my_map->inobject_properties();
881   CHECK_GT(n_properties, 0);
882 
883   int object_size = my_map->instance_size();
884 
885   // Step 2: allocate a lot of objects so to almost fill new space: we need
886   // just enough room to allocate JSObject and thus fill the newspace.
887 
888   int allocation_amount = Min(FixedArray::kMaxSize,
889                               HEAP->MaxObjectSizeInNewSpace());
890   int allocation_len = LenFromSize(allocation_amount);
891   NewSpace* new_space = HEAP->new_space();
892   Address* top_addr = new_space->allocation_top_address();
893   Address* limit_addr = new_space->allocation_limit_address();
894   while ((*limit_addr - *top_addr) > allocation_amount) {
895     CHECK(!HEAP->always_allocate());
896     Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
897     CHECK(!array->IsFailure());
898     CHECK(new_space->Contains(array));
899   }
900 
901   // Step 3: now allocate fixed array and JSObject to fill the whole new space.
902   int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
903   int fixed_array_len = LenFromSize(to_fill);
904   CHECK(fixed_array_len < FixedArray::kMaxLength);
905 
906   CHECK(!HEAP->always_allocate());
907   Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
908   CHECK(!array->IsFailure());
909   CHECK(new_space->Contains(array));
910 
911   Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
912   CHECK(new_space->Contains(object));
913   JSObject* jsobject = JSObject::cast(object);
914   CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
915   CHECK_EQ(0, jsobject->properties()->length());
916   // Create a reference to object in new space in jsobject.
917   jsobject->FastPropertyAtPut(-1, array);
918 
919   CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
920 
921   // Step 4: clone jsobject, but force always allocate first to create a clone
922   // in old pointer space.
923   Address old_pointer_space_top = HEAP->old_pointer_space()->top();
924   AlwaysAllocateScope aa_scope;
925   Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
926   JSObject* clone = JSObject::cast(clone_obj);
927   if (clone->address() != old_pointer_space_top) {
928     // Alas, got allocated from free list, we cannot do checks.
929     return;
930   }
931   CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
932 }
933 
934 
TEST(TestCodeFlushing)935 TEST(TestCodeFlushing) {
936   i::FLAG_allow_natives_syntax = true;
937   // If we do not flush code this test is invalid.
938   if (!FLAG_flush_code) return;
939   InitializeVM();
940   v8::HandleScope scope;
941   const char* source = "function foo() {"
942                        "  var x = 42;"
943                        "  var y = 42;"
944                        "  var z = x + y;"
945                        "};"
946                        "foo()";
947   Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
948 
949   // This compile will add the code to the compilation cache.
950   { v8::HandleScope scope;
951     CompileRun(source);
952   }
953 
954   // Check function is compiled.
955   Object* func_value = Isolate::Current()->context()->global()->
956       GetProperty(*foo_name)->ToObjectChecked();
957   CHECK(func_value->IsJSFunction());
958   Handle<JSFunction> function(JSFunction::cast(func_value));
959   CHECK(function->shared()->is_compiled());
960 
961   // TODO(1609) Currently incremental marker does not support code flushing.
962   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
963   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
964 
965   CHECK(function->shared()->is_compiled());
966 
967   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
968   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
969   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
970   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
971   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
972   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
973 
974   // foo should no longer be in the compilation cache
975   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
976   CHECK(!function->is_compiled() || function->IsOptimized());
977   // Call foo to get it recompiled.
978   CompileRun("foo()");
979   CHECK(function->shared()->is_compiled());
980   CHECK(function->is_compiled());
981 }
982 
983 
984 // Count the number of global contexts in the weak list of global contexts.
CountGlobalContexts()985 static int CountGlobalContexts() {
986   int count = 0;
987   Object* object = HEAP->global_contexts_list();
988   while (!object->IsUndefined()) {
989     count++;
990     object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
991   }
992   return count;
993 }
994 
995 
996 // Count the number of user functions in the weak list of optimized
997 // functions attached to a global context.
CountOptimizedUserFunctions(v8::Handle<v8::Context> context)998 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
999   int count = 0;
1000   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1001   Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1002   while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1003     count++;
1004     object = JSFunction::cast(object)->next_function_link();
1005   }
1006   return count;
1007 }
1008 
1009 
TEST(TestInternalWeakLists)1010 TEST(TestInternalWeakLists) {
1011   v8::V8::Initialize();
1012 
1013   static const int kNumTestContexts = 10;
1014 
1015   v8::HandleScope scope;
1016   v8::Persistent<v8::Context> ctx[kNumTestContexts];
1017 
1018   CHECK_EQ(0, CountGlobalContexts());
1019 
1020   // Create a number of global contests which gets linked together.
1021   for (int i = 0; i < kNumTestContexts; i++) {
1022     ctx[i] = v8::Context::New();
1023 
1024     bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1025 
1026     CHECK_EQ(i + 1, CountGlobalContexts());
1027 
1028     ctx[i]->Enter();
1029 
1030     // Create a handle scope so no function objects get stuch in the outer
1031     // handle scope
1032     v8::HandleScope scope;
1033     const char* source = "function f1() { };"
1034                          "function f2() { };"
1035                          "function f3() { };"
1036                          "function f4() { };"
1037                          "function f5() { };";
1038     CompileRun(source);
1039     CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1040     CompileRun("f1()");
1041     CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1042     CompileRun("f2()");
1043     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1044     CompileRun("f3()");
1045     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1046     CompileRun("f4()");
1047     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1048     CompileRun("f5()");
1049     CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1050 
1051     // Remove function f1, and
1052     CompileRun("f1=null");
1053 
1054     // Scavenge treats these references as strong.
1055     for (int j = 0; j < 10; j++) {
1056       HEAP->PerformScavenge();
1057       CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1058     }
1059 
1060     // Mark compact handles the weak references.
1061     HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1062     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1063 
1064     // Get rid of f3 and f5 in the same way.
1065     CompileRun("f3=null");
1066     for (int j = 0; j < 10; j++) {
1067       HEAP->PerformScavenge();
1068       CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1069     }
1070     HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1071     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1072     CompileRun("f5=null");
1073     for (int j = 0; j < 10; j++) {
1074       HEAP->PerformScavenge();
1075       CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1076     }
1077     HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1078     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1079 
1080     ctx[i]->Exit();
1081   }
1082 
1083   // Force compilation cache cleanup.
1084   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1085 
1086   // Dispose the global contexts one by one.
1087   for (int i = 0; i < kNumTestContexts; i++) {
1088     ctx[i].Dispose();
1089     ctx[i].Clear();
1090 
1091     // Scavenge treats these references as strong.
1092     for (int j = 0; j < 10; j++) {
1093       HEAP->PerformScavenge();
1094       CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1095     }
1096 
1097     // Mark compact handles the weak references.
1098     HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1099     CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1100   }
1101 
1102   CHECK_EQ(0, CountGlobalContexts());
1103 }
1104 
1105 
1106 // Count the number of global contexts in the weak list of global contexts
1107 // causing a GC after the specified number of elements.
CountGlobalContextsWithGC(int n)1108 static int CountGlobalContextsWithGC(int n) {
1109   int count = 0;
1110   Handle<Object> object(HEAP->global_contexts_list());
1111   while (!object->IsUndefined()) {
1112     count++;
1113     if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1114     object =
1115         Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1116   }
1117   return count;
1118 }
1119 
1120 
1121 // Count the number of user functions in the weak list of optimized
1122 // functions attached to a global context causing a GC after the
1123 // specified number of elements.
CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,int n)1124 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1125                                              int n) {
1126   int count = 0;
1127   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1128   Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1129   while (object->IsJSFunction() &&
1130          !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1131     count++;
1132     if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1133     object = Handle<Object>(
1134         Object::cast(JSFunction::cast(*object)->next_function_link()));
1135   }
1136   return count;
1137 }
1138 
1139 
TEST(TestInternalWeakListsTraverseWithGC)1140 TEST(TestInternalWeakListsTraverseWithGC) {
1141   v8::V8::Initialize();
1142 
1143   static const int kNumTestContexts = 10;
1144 
1145   v8::HandleScope scope;
1146   v8::Persistent<v8::Context> ctx[kNumTestContexts];
1147 
1148   CHECK_EQ(0, CountGlobalContexts());
1149 
1150   // Create an number of contexts and check the length of the weak list both
1151   // with and without GCs while iterating the list.
1152   for (int i = 0; i < kNumTestContexts; i++) {
1153     ctx[i] = v8::Context::New();
1154     CHECK_EQ(i + 1, CountGlobalContexts());
1155     CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
1156   }
1157 
1158   bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1159 
1160   // Compile a number of functions the length of the weak list of optimized
1161   // functions both with and without GCs while iterating the list.
1162   ctx[0]->Enter();
1163   const char* source = "function f1() { };"
1164                        "function f2() { };"
1165                        "function f3() { };"
1166                        "function f4() { };"
1167                        "function f5() { };";
1168   CompileRun(source);
1169   CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1170   CompileRun("f1()");
1171   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1172   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1173   CompileRun("f2()");
1174   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1175   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1176   CompileRun("f3()");
1177   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1178   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1179   CompileRun("f4()");
1180   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1181   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1182   CompileRun("f5()");
1183   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1184   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1185 
1186   ctx[0]->Exit();
1187 }
1188 
1189 
TEST(TestSizeOfObjects)1190 TEST(TestSizeOfObjects) {
1191   v8::V8::Initialize();
1192 
1193   // Get initial heap size after several full GCs, which will stabilize
1194   // the heap size and return with sweeping finished completely.
1195   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1196   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1197   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1198   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1199   CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1200   int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1201 
1202   {
1203     // Allocate objects on several different old-space pages so that
1204     // lazy sweeping kicks in for subsequent GC runs.
1205     AlwaysAllocateScope always_allocate;
1206     int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1207     for (int i = 1; i <= 100; i++) {
1208       HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1209       CHECK_EQ(initial_size + i * filler_size,
1210                static_cast<int>(HEAP->SizeOfObjects()));
1211     }
1212   }
1213 
1214   // The heap size should go back to initial size after a full GC, even
1215   // though sweeping didn't finish yet.
1216   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1217   CHECK(!HEAP->old_pointer_space()->IsSweepingComplete());
1218   CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1219 
1220   // Advancing the sweeper step-wise should not change the heap size.
1221   while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1222     HEAP->old_pointer_space()->AdvanceSweeper(KB);
1223     CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1224   }
1225 }
1226 
1227 
TEST(TestSizeOfObjectsVsHeapIteratorPrecision)1228 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1229   InitializeVM();
1230   HEAP->EnsureHeapIsIterable();
1231   intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
1232   HeapIterator iterator;
1233   intptr_t size_of_objects_2 = 0;
1234   for (HeapObject* obj = iterator.next();
1235        obj != NULL;
1236        obj = iterator.next()) {
1237     size_of_objects_2 += obj->Size();
1238   }
1239   // Delta must be within 5% of the larger result.
1240   // TODO(gc): Tighten this up by distinguishing between byte
1241   // arrays that are real and those that merely mark free space
1242   // on the heap.
1243   if (size_of_objects_1 > size_of_objects_2) {
1244     intptr_t delta = size_of_objects_1 - size_of_objects_2;
1245     PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1246            "Iterator: %" V8_PTR_PREFIX "d, "
1247            "delta: %" V8_PTR_PREFIX "d\n",
1248            size_of_objects_1, size_of_objects_2, delta);
1249     CHECK_GT(size_of_objects_1 / 20, delta);
1250   } else {
1251     intptr_t delta = size_of_objects_2 - size_of_objects_1;
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_2 / 20, delta);
1257   }
1258 }
1259 
1260 
FillUpNewSpace(NewSpace * new_space)1261 static void FillUpNewSpace(NewSpace* new_space) {
1262   // Fill up new space to the point that it is completely full. Make sure
1263   // that the scavenger does not undo the filling.
1264   v8::HandleScope scope;
1265   AlwaysAllocateScope always_allocate;
1266   intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
1267   intptr_t number_of_fillers = (available / FixedArray::SizeFor(1000)) - 10;
1268   for (intptr_t i = 0; i < number_of_fillers; i++) {
1269     CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(1000, NOT_TENURED)));
1270   }
1271 }
1272 
1273 
TEST(GrowAndShrinkNewSpace)1274 TEST(GrowAndShrinkNewSpace) {
1275   InitializeVM();
1276   NewSpace* new_space = HEAP->new_space();
1277 
1278   // Explicitly growing should double the space capacity.
1279   intptr_t old_capacity, new_capacity;
1280   old_capacity = new_space->Capacity();
1281   new_space->Grow();
1282   new_capacity = new_space->Capacity();
1283   CHECK(2 * old_capacity == new_capacity);
1284 
1285   old_capacity = new_space->Capacity();
1286   FillUpNewSpace(new_space);
1287   new_capacity = new_space->Capacity();
1288   CHECK(old_capacity == new_capacity);
1289 
1290   // Explicitly shrinking should not affect space capacity.
1291   old_capacity = new_space->Capacity();
1292   new_space->Shrink();
1293   new_capacity = new_space->Capacity();
1294   CHECK(old_capacity == new_capacity);
1295 
1296   // Let the scavenger empty the new space.
1297   HEAP->CollectGarbage(NEW_SPACE);
1298   CHECK_LE(new_space->Size(), old_capacity);
1299 
1300   // Explicitly shrinking should halve the space capacity.
1301   old_capacity = new_space->Capacity();
1302   new_space->Shrink();
1303   new_capacity = new_space->Capacity();
1304   CHECK(old_capacity == 2 * new_capacity);
1305 
1306   // Consecutive shrinking should not affect space capacity.
1307   old_capacity = new_space->Capacity();
1308   new_space->Shrink();
1309   new_space->Shrink();
1310   new_space->Shrink();
1311   new_capacity = new_space->Capacity();
1312   CHECK(old_capacity == new_capacity);
1313 }
1314 
1315 
TEST(CollectingAllAvailableGarbageShrinksNewSpace)1316 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1317   InitializeVM();
1318   v8::HandleScope scope;
1319   NewSpace* new_space = HEAP->new_space();
1320   intptr_t old_capacity, new_capacity;
1321   old_capacity = new_space->Capacity();
1322   new_space->Grow();
1323   new_capacity = new_space->Capacity();
1324   CHECK(2 * old_capacity == new_capacity);
1325   FillUpNewSpace(new_space);
1326   HEAP->CollectAllAvailableGarbage();
1327   new_capacity = new_space->Capacity();
1328   CHECK(old_capacity == new_capacity);
1329 }
1330 
1331 
NumberOfGlobalObjects()1332 static int NumberOfGlobalObjects() {
1333   int count = 0;
1334   HeapIterator iterator;
1335   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1336     if (obj->IsGlobalObject()) count++;
1337   }
1338   return count;
1339 }
1340 
1341 
1342 // Test that we don't embed maps from foreign contexts into
1343 // optimized code.
TEST(LeakGlobalContextViaMap)1344 TEST(LeakGlobalContextViaMap) {
1345   i::FLAG_allow_natives_syntax = true;
1346   v8::HandleScope outer_scope;
1347   v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1348   v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1349   ctx1->Enter();
1350 
1351   HEAP->CollectAllAvailableGarbage();
1352   CHECK_EQ(4, NumberOfGlobalObjects());
1353 
1354   {
1355     v8::HandleScope inner_scope;
1356     CompileRun("var v = {x: 42}");
1357     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1358     ctx2->Enter();
1359     ctx2->Global()->Set(v8_str("o"), v);
1360     v8::Local<v8::Value> res = CompileRun(
1361         "function f() { return o.x; }"
1362         "for (var i = 0; i < 10; ++i) f();"
1363         "%OptimizeFunctionOnNextCall(f);"
1364         "f();");
1365     CHECK_EQ(42, res->Int32Value());
1366     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1367     ctx2->Exit();
1368     ctx1->Exit();
1369     ctx1.Dispose();
1370   }
1371   HEAP->CollectAllAvailableGarbage();
1372   CHECK_EQ(2, NumberOfGlobalObjects());
1373   ctx2.Dispose();
1374   HEAP->CollectAllAvailableGarbage();
1375   CHECK_EQ(0, NumberOfGlobalObjects());
1376 }
1377 
1378 
1379 // Test that we don't embed functions from foreign contexts into
1380 // optimized code.
TEST(LeakGlobalContextViaFunction)1381 TEST(LeakGlobalContextViaFunction) {
1382   i::FLAG_allow_natives_syntax = true;
1383   v8::HandleScope outer_scope;
1384   v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1385   v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1386   ctx1->Enter();
1387 
1388   HEAP->CollectAllAvailableGarbage();
1389   CHECK_EQ(4, NumberOfGlobalObjects());
1390 
1391   {
1392     v8::HandleScope inner_scope;
1393     CompileRun("var v = function() { return 42; }");
1394     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1395     ctx2->Enter();
1396     ctx2->Global()->Set(v8_str("o"), v);
1397     v8::Local<v8::Value> res = CompileRun(
1398         "function f(x) { return x(); }"
1399         "for (var i = 0; i < 10; ++i) f(o);"
1400         "%OptimizeFunctionOnNextCall(f);"
1401         "f(o);");
1402     CHECK_EQ(42, res->Int32Value());
1403     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1404     ctx2->Exit();
1405     ctx1->Exit();
1406     ctx1.Dispose();
1407   }
1408   HEAP->CollectAllAvailableGarbage();
1409   CHECK_EQ(2, NumberOfGlobalObjects());
1410   ctx2.Dispose();
1411   HEAP->CollectAllAvailableGarbage();
1412   CHECK_EQ(0, NumberOfGlobalObjects());
1413 }
1414 
1415 
TEST(LeakGlobalContextViaMapKeyed)1416 TEST(LeakGlobalContextViaMapKeyed) {
1417   i::FLAG_allow_natives_syntax = true;
1418   v8::HandleScope outer_scope;
1419   v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1420   v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1421   ctx1->Enter();
1422 
1423   HEAP->CollectAllAvailableGarbage();
1424   CHECK_EQ(4, NumberOfGlobalObjects());
1425 
1426   {
1427     v8::HandleScope inner_scope;
1428     CompileRun("var v = [42, 43]");
1429     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1430     ctx2->Enter();
1431     ctx2->Global()->Set(v8_str("o"), v);
1432     v8::Local<v8::Value> res = CompileRun(
1433         "function f() { return o[0]; }"
1434         "for (var i = 0; i < 10; ++i) f();"
1435         "%OptimizeFunctionOnNextCall(f);"
1436         "f();");
1437     CHECK_EQ(42, res->Int32Value());
1438     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1439     ctx2->Exit();
1440     ctx1->Exit();
1441     ctx1.Dispose();
1442   }
1443   HEAP->CollectAllAvailableGarbage();
1444   CHECK_EQ(2, NumberOfGlobalObjects());
1445   ctx2.Dispose();
1446   HEAP->CollectAllAvailableGarbage();
1447   CHECK_EQ(0, NumberOfGlobalObjects());
1448 }
1449 
1450 
TEST(LeakGlobalContextViaMapProto)1451 TEST(LeakGlobalContextViaMapProto) {
1452   i::FLAG_allow_natives_syntax = true;
1453   v8::HandleScope outer_scope;
1454   v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1455   v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1456   ctx1->Enter();
1457 
1458   HEAP->CollectAllAvailableGarbage();
1459   CHECK_EQ(4, NumberOfGlobalObjects());
1460 
1461   {
1462     v8::HandleScope inner_scope;
1463     CompileRun("var v = { y: 42}");
1464     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1465     ctx2->Enter();
1466     ctx2->Global()->Set(v8_str("o"), v);
1467     v8::Local<v8::Value> res = CompileRun(
1468         "function f() {"
1469         "  var p = {x: 42};"
1470         "  p.__proto__ = o;"
1471         "  return p.x;"
1472         "}"
1473         "for (var i = 0; i < 10; ++i) f();"
1474         "%OptimizeFunctionOnNextCall(f);"
1475         "f();");
1476     CHECK_EQ(42, res->Int32Value());
1477     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1478     ctx2->Exit();
1479     ctx1->Exit();
1480     ctx1.Dispose();
1481   }
1482   HEAP->CollectAllAvailableGarbage();
1483   CHECK_EQ(2, NumberOfGlobalObjects());
1484   ctx2.Dispose();
1485   HEAP->CollectAllAvailableGarbage();
1486   CHECK_EQ(0, NumberOfGlobalObjects());
1487 }
1488 
1489 
TEST(InstanceOfStubWriteBarrier)1490 TEST(InstanceOfStubWriteBarrier) {
1491   i::FLAG_allow_natives_syntax = true;
1492 #ifdef DEBUG
1493   i::FLAG_verify_heap = true;
1494 #endif
1495   InitializeVM();
1496   if (!i::V8::UseCrankshaft()) return;
1497   v8::HandleScope outer_scope;
1498 
1499   {
1500     v8::HandleScope scope;
1501     CompileRun(
1502         "function foo () { }"
1503         "function mkbar () { return new (new Function(\"\")) (); }"
1504         "function f (x) { return (x instanceof foo); }"
1505         "function g () { f(mkbar()); }"
1506         "f(new foo()); f(new foo());"
1507         "%OptimizeFunctionOnNextCall(f);"
1508         "f(new foo()); g();");
1509   }
1510 
1511   IncrementalMarking* marking = HEAP->incremental_marking();
1512   marking->Abort();
1513   marking->Start();
1514 
1515   Handle<JSFunction> f =
1516       v8::Utils::OpenHandle(
1517           *v8::Handle<v8::Function>::Cast(
1518               v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1519 
1520   CHECK(f->IsOptimized());
1521 
1522   while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1523          !marking->IsStopped()) {
1524     // Discard any pending GC requests otherwise we will get GC when we enter
1525     // code below.
1526     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1527   }
1528 
1529   CHECK(marking->IsMarking());
1530 
1531   {
1532     v8::HandleScope scope;
1533     v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1534     v8::Handle<v8::Function> g =
1535         v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1536     g->Call(global, 0, NULL);
1537   }
1538 
1539   HEAP->incremental_marking()->set_should_hurry(true);
1540   HEAP->CollectGarbage(OLD_POINTER_SPACE);
1541 }
1542 
1543 
TEST(PrototypeTransitionClearing)1544 TEST(PrototypeTransitionClearing) {
1545   InitializeVM();
1546   v8::HandleScope scope;
1547 
1548   CompileRun(
1549       "var base = {};"
1550       "var live = [];"
1551       "for (var i = 0; i < 10; i++) {"
1552       "  var object = {};"
1553       "  var prototype = {};"
1554       "  object.__proto__ = prototype;"
1555       "  if (i >= 3) live.push(object, prototype);"
1556       "}");
1557 
1558   Handle<JSObject> baseObject =
1559       v8::Utils::OpenHandle(
1560           *v8::Handle<v8::Object>::Cast(
1561               v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1562 
1563   // Verify that only dead prototype transitions are cleared.
1564   CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
1565   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1566   CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());
1567 
1568   // Verify that prototype transitions array was compacted.
1569   FixedArray* trans = baseObject->map()->prototype_transitions();
1570   for (int i = 0; i < 10 - 3; i++) {
1571     int j = Map::kProtoTransitionHeaderSize +
1572         i * Map::kProtoTransitionElementsPerEntry;
1573     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
1574     CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
1575   }
1576 
1577   // Make sure next prototype is placed on an old-space evacuation candidate.
1578   Handle<JSObject> prototype;
1579   PagedSpace* space = HEAP->old_pointer_space();
1580   do {
1581     prototype = FACTORY->NewJSArray(32 * KB, FAST_ELEMENTS, TENURED);
1582   } while (space->FirstPage() == space->LastPage() ||
1583       !space->LastPage()->Contains(prototype->address()));
1584 
1585   // Add a prototype on an evacuation candidate and verify that transition
1586   // clearing correctly records slots in prototype transition array.
1587   i::FLAG_always_compact = true;
1588   Handle<Map> map(baseObject->map());
1589   CHECK(!space->LastPage()->Contains(map->prototype_transitions()->address()));
1590   CHECK(space->LastPage()->Contains(prototype->address()));
1591   baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1592   CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1593   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1594   CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1595 }
1596 
1597 
TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking)1598 TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1599   i::FLAG_allow_natives_syntax = true;
1600 #ifdef DEBUG
1601   i::FLAG_verify_heap = true;
1602 #endif
1603   InitializeVM();
1604   if (!i::V8::UseCrankshaft()) return;
1605   v8::HandleScope outer_scope;
1606 
1607   {
1608     v8::HandleScope scope;
1609     CompileRun(
1610         "function f () {"
1611         "  var s = 0;"
1612         "  for (var i = 0; i < 100; i++)  s += i;"
1613         "  return s;"
1614         "}"
1615         "f(); f();"
1616         "%OptimizeFunctionOnNextCall(f);"
1617         "f();");
1618   }
1619   Handle<JSFunction> f =
1620       v8::Utils::OpenHandle(
1621           *v8::Handle<v8::Function>::Cast(
1622               v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1623   CHECK(f->IsOptimized());
1624 
1625   IncrementalMarking* marking = HEAP->incremental_marking();
1626   marking->Abort();
1627   marking->Start();
1628 
1629   // The following two calls will increment HEAP->global_ic_age().
1630   const int kLongIdlePauseInMs = 1000;
1631   v8::V8::ContextDisposedNotification();
1632   v8::V8::IdleNotification(kLongIdlePauseInMs);
1633 
1634   while (!marking->IsStopped() && !marking->IsComplete()) {
1635     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1636   }
1637 
1638   CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1639   CHECK_EQ(0, f->shared()->opt_count());
1640   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1641 }
1642 
1643 
TEST(ResetSharedFunctionInfoCountersDuringMarkSweep)1644 TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1645   i::FLAG_allow_natives_syntax = true;
1646 #ifdef DEBUG
1647   i::FLAG_verify_heap = true;
1648 #endif
1649   InitializeVM();
1650   if (!i::V8::UseCrankshaft()) return;
1651   v8::HandleScope outer_scope;
1652 
1653   {
1654     v8::HandleScope scope;
1655     CompileRun(
1656         "function f () {"
1657         "  var s = 0;"
1658         "  for (var i = 0; i < 100; i++)  s += i;"
1659         "  return s;"
1660         "}"
1661         "f(); f();"
1662         "%OptimizeFunctionOnNextCall(f);"
1663         "f();");
1664   }
1665   Handle<JSFunction> f =
1666       v8::Utils::OpenHandle(
1667           *v8::Handle<v8::Function>::Cast(
1668               v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1669   CHECK(f->IsOptimized());
1670 
1671   HEAP->incremental_marking()->Abort();
1672 
1673   // The following two calls will increment HEAP->global_ic_age().
1674   // Since incremental marking is off, IdleNotification will do full GC.
1675   const int kLongIdlePauseInMs = 1000;
1676   v8::V8::ContextDisposedNotification();
1677   v8::V8::IdleNotification(kLongIdlePauseInMs);
1678 
1679   CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1680   CHECK_EQ(0, f->shared()->opt_count());
1681   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1682 }
1683