Home | History | Annotate | Download | only in cctest
      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 
     17 static void InitializeVM() {
     18   if (env.IsEmpty()) env = v8::Context::New();
     19   v8::HandleScope scope;
     20   env->Enter();
     21 }
     22 
     23 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    528 TEST(SymbolTable) {
    529   InitializeVM();
    530 
    531   CheckSymbols(not_so_random_string_table);
    532   CheckSymbols(not_so_random_string_table);
    533 }
    534 
    535 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    898 static int LenFromSize(int size) {
    899   return (size - FixedArray::kHeaderSize) / kPointerSize;
    900 }
    901 
    902 
    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 
    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.
   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.
   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 
   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.
   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.
   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 
   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 
   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:
   1270   HeapIteratorTestHelper(Object* a, Object* b)
   1271       : a_(a), b_(b), a_found_(false), b_found_(false) {}
   1272   bool a_found() { return a_found_; }
   1273   bool b_found() { return b_found_; }
   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 
   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