Home | History | Annotate | Download | only in cctest
      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 
     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   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 
    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   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 
    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 
    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, 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 
    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 
    855 static int LenFromSize(int size) {
    856   return (size - FixedArray::kHeaderSize) / kPointerSize;
    857 }
    858 
    859 
    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 
    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.
    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.
    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 
   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.
   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.
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   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.
   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 
   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 
   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 
   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 
   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 
   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 
   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