Home | History | Annotate | Download | only in cctest
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <stdlib.h>
     29 #include <utility>
     30 
     31 #include "src/v8.h"
     32 
     33 #include "src/compilation-cache.h"
     34 #include "src/execution.h"
     35 #include "src/factory.h"
     36 #include "src/global-handles.h"
     37 #include "src/macro-assembler.h"
     38 #include "src/stub-cache.h"
     39 #include "test/cctest/cctest.h"
     40 
     41 using namespace v8::internal;
     42 
     43 // Go through all incremental marking steps in one swoop.
     44 static void SimulateIncrementalMarking() {
     45   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
     46   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
     47   if (collector->IsConcurrentSweepingInProgress()) {
     48     collector->WaitUntilSweepingCompleted();
     49   }
     50   CHECK(marking->IsMarking() || marking->IsStopped());
     51   if (marking->IsStopped()) {
     52     marking->Start();
     53   }
     54   CHECK(marking->IsMarking());
     55   while (!marking->IsComplete()) {
     56     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
     57   }
     58   CHECK(marking->IsComplete());
     59 }
     60 
     61 
     62 static void CheckMap(Map* map, int type, int instance_size) {
     63   CHECK(map->IsHeapObject());
     64 #ifdef DEBUG
     65   CHECK(CcTest::heap()->Contains(map));
     66 #endif
     67   CHECK_EQ(CcTest::heap()->meta_map(), map->map());
     68   CHECK_EQ(type, map->instance_type());
     69   CHECK_EQ(instance_size, map->instance_size());
     70 }
     71 
     72 
     73 TEST(HeapMaps) {
     74   CcTest::InitializeVM();
     75   Heap* heap = CcTest::heap();
     76   CheckMap(heap->meta_map(), MAP_TYPE, Map::kSize);
     77   CheckMap(heap->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
     78   CheckMap(heap->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
     79   CheckMap(heap->string_map(), STRING_TYPE, kVariableSizeSentinel);
     80 }
     81 
     82 
     83 static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
     84   CHECK(obj->IsOddball());
     85   Handle<Object> handle(obj, isolate);
     86   Object* print_string =
     87       *Execution::ToString(isolate, handle).ToHandleChecked();
     88   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
     89 }
     90 
     91 
     92 static void CheckSmi(Isolate* isolate, int value, const char* string) {
     93   Handle<Object> handle(Smi::FromInt(value), isolate);
     94   Object* print_string =
     95       *Execution::ToString(isolate, handle).ToHandleChecked();
     96   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
     97 }
     98 
     99 
    100 static void CheckNumber(Isolate* isolate, double value, const char* string) {
    101   Handle<Object> number = isolate->factory()->NewNumber(value);
    102   CHECK(number->IsNumber());
    103   Handle<Object> print_string =
    104       Execution::ToString(isolate, number).ToHandleChecked();
    105   CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
    106 }
    107 
    108 
    109 static void CheckFindCodeObject(Isolate* isolate) {
    110   // Test FindCodeObject
    111 #define __ assm.
    112 
    113   Assembler assm(isolate, NULL, 0);
    114 
    115   __ nop();  // supported on all architectures
    116 
    117   CodeDesc desc;
    118   assm.GetCode(&desc);
    119   Handle<Code> code = isolate->factory()->NewCode(
    120       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
    121   CHECK(code->IsCode());
    122 
    123   HeapObject* obj = HeapObject::cast(*code);
    124   Address obj_addr = obj->address();
    125 
    126   for (int i = 0; i < obj->Size(); i += kPointerSize) {
    127     Object* found = isolate->FindCodeObject(obj_addr + i);
    128     CHECK_EQ(*code, found);
    129   }
    130 
    131   Handle<Code> copy = isolate->factory()->NewCode(
    132       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
    133   HeapObject* obj_copy = HeapObject::cast(*copy);
    134   Object* not_right = isolate->FindCodeObject(obj_copy->address() +
    135                                               obj_copy->Size() / 2);
    136   CHECK(not_right != *code);
    137 }
    138 
    139 
    140 TEST(HandleNull) {
    141   CcTest::InitializeVM();
    142   Isolate* isolate = CcTest::i_isolate();
    143   HandleScope outer_scope(isolate);
    144   LocalContext context;
    145   Handle<Object> n(reinterpret_cast<Object*>(NULL), isolate);
    146   CHECK(!n.is_null());
    147 }
    148 
    149 
    150 TEST(HeapObjects) {
    151   CcTest::InitializeVM();
    152   Isolate* isolate = CcTest::i_isolate();
    153   Factory* factory = isolate->factory();
    154   Heap* heap = isolate->heap();
    155 
    156   HandleScope sc(isolate);
    157   Handle<Object> value = factory->NewNumber(1.000123);
    158   CHECK(value->IsHeapNumber());
    159   CHECK(value->IsNumber());
    160   CHECK_EQ(1.000123, value->Number());
    161 
    162   value = factory->NewNumber(1.0);
    163   CHECK(value->IsSmi());
    164   CHECK(value->IsNumber());
    165   CHECK_EQ(1.0, value->Number());
    166 
    167   value = factory->NewNumberFromInt(1024);
    168   CHECK(value->IsSmi());
    169   CHECK(value->IsNumber());
    170   CHECK_EQ(1024.0, value->Number());
    171 
    172   value = factory->NewNumberFromInt(Smi::kMinValue);
    173   CHECK(value->IsSmi());
    174   CHECK(value->IsNumber());
    175   CHECK_EQ(Smi::kMinValue, Handle<Smi>::cast(value)->value());
    176 
    177   value = factory->NewNumberFromInt(Smi::kMaxValue);
    178   CHECK(value->IsSmi());
    179   CHECK(value->IsNumber());
    180   CHECK_EQ(Smi::kMaxValue, Handle<Smi>::cast(value)->value());
    181 
    182 #if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64)
    183   // TODO(lrn): We need a NumberFromIntptr function in order to test this.
    184   value = factory->NewNumberFromInt(Smi::kMinValue - 1);
    185   CHECK(value->IsHeapNumber());
    186   CHECK(value->IsNumber());
    187   CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
    188 #endif
    189 
    190   value = factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
    191   CHECK(value->IsHeapNumber());
    192   CHECK(value->IsNumber());
    193   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
    194            value->Number());
    195 
    196   value = factory->NewNumberFromUint(static_cast<uint32_t>(1) << 31);
    197   CHECK(value->IsHeapNumber());
    198   CHECK(value->IsNumber());
    199   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
    200            value->Number());
    201 
    202   // nan oddball checks
    203   CHECK(factory->nan_value()->IsNumber());
    204   CHECK(std::isnan(factory->nan_value()->Number()));
    205 
    206   Handle<String> s = factory->NewStringFromStaticAscii("fisk hest ");
    207   CHECK(s->IsString());
    208   CHECK_EQ(10, s->length());
    209 
    210   Handle<String> object_string = Handle<String>::cast(factory->Object_string());
    211   Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
    212   CHECK(JSReceiver::HasOwnProperty(global, object_string));
    213 
    214   // Check ToString for oddballs
    215   CheckOddball(isolate, heap->true_value(), "true");
    216   CheckOddball(isolate, heap->false_value(), "false");
    217   CheckOddball(isolate, heap->null_value(), "null");
    218   CheckOddball(isolate, heap->undefined_value(), "undefined");
    219 
    220   // Check ToString for Smis
    221   CheckSmi(isolate, 0, "0");
    222   CheckSmi(isolate, 42, "42");
    223   CheckSmi(isolate, -42, "-42");
    224 
    225   // Check ToString for Numbers
    226   CheckNumber(isolate, 1.1, "1.1");
    227 
    228   CheckFindCodeObject(isolate);
    229 }
    230 
    231 
    232 TEST(Tagging) {
    233   CcTest::InitializeVM();
    234   int request = 24;
    235   CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
    236   CHECK(Smi::FromInt(42)->IsSmi());
    237   CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
    238   CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
    239 }
    240 
    241 
    242 TEST(GarbageCollection) {
    243   CcTest::InitializeVM();
    244   Isolate* isolate = CcTest::i_isolate();
    245   Heap* heap = isolate->heap();
    246   Factory* factory = isolate->factory();
    247 
    248   HandleScope sc(isolate);
    249   // Check GC.
    250   heap->CollectGarbage(NEW_SPACE);
    251 
    252   Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
    253   Handle<String> name = factory->InternalizeUtf8String("theFunction");
    254   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
    255   Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
    256   Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
    257   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
    258   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
    259 
    260   {
    261     HandleScope inner_scope(isolate);
    262     // Allocate a function and keep it in global object's property.
    263     Handle<JSFunction> function = factory->NewFunction(name);
    264     JSReceiver::SetProperty(global, name, function, NONE, SLOPPY).Check();
    265     // Allocate an object.  Unrooted after leaving the scope.
    266     Handle<JSObject> obj = factory->NewJSObject(function);
    267     JSReceiver::SetProperty(
    268         obj, prop_name, twenty_three, NONE, SLOPPY).Check();
    269     JSReceiver::SetProperty(
    270         obj, prop_namex, twenty_four, NONE, SLOPPY).Check();
    271 
    272     CHECK_EQ(Smi::FromInt(23),
    273              *Object::GetProperty(obj, prop_name).ToHandleChecked());
    274     CHECK_EQ(Smi::FromInt(24),
    275              *Object::GetProperty(obj, prop_namex).ToHandleChecked());
    276   }
    277 
    278   heap->CollectGarbage(NEW_SPACE);
    279 
    280   // Function should be alive.
    281   CHECK(JSReceiver::HasOwnProperty(global, name));
    282   // Check function is retained.
    283   Handle<Object> func_value =
    284       Object::GetProperty(global, name).ToHandleChecked();
    285   CHECK(func_value->IsJSFunction());
    286   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
    287 
    288   {
    289     HandleScope inner_scope(isolate);
    290     // Allocate another object, make it reachable from global.
    291     Handle<JSObject> obj = factory->NewJSObject(function);
    292     JSReceiver::SetProperty(global, obj_name, obj, NONE, SLOPPY).Check();
    293     JSReceiver::SetProperty(
    294         obj, prop_name, twenty_three, NONE, SLOPPY).Check();
    295   }
    296 
    297   // After gc, it should survive.
    298   heap->CollectGarbage(NEW_SPACE);
    299 
    300   CHECK(JSReceiver::HasOwnProperty(global, obj_name));
    301   Handle<Object> obj =
    302       Object::GetProperty(global, obj_name).ToHandleChecked();
    303   CHECK(obj->IsJSObject());
    304   CHECK_EQ(Smi::FromInt(23),
    305            *Object::GetProperty(obj, prop_name).ToHandleChecked());
    306 }
    307 
    308 
    309 static void VerifyStringAllocation(Isolate* isolate, const char* string) {
    310   HandleScope scope(isolate);
    311   Handle<String> s = isolate->factory()->NewStringFromUtf8(
    312       CStrVector(string)).ToHandleChecked();
    313   CHECK_EQ(StrLength(string), s->length());
    314   for (int index = 0; index < s->length(); index++) {
    315     CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
    316   }
    317 }
    318 
    319 
    320 TEST(String) {
    321   CcTest::InitializeVM();
    322   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
    323 
    324   VerifyStringAllocation(isolate, "a");
    325   VerifyStringAllocation(isolate, "ab");
    326   VerifyStringAllocation(isolate, "abc");
    327   VerifyStringAllocation(isolate, "abcd");
    328   VerifyStringAllocation(isolate, "fiskerdrengen er paa havet");
    329 }
    330 
    331 
    332 TEST(LocalHandles) {
    333   CcTest::InitializeVM();
    334   Isolate* isolate = CcTest::i_isolate();
    335   Factory* factory = isolate->factory();
    336 
    337   v8::HandleScope scope(CcTest::isolate());
    338   const char* name = "Kasper the spunky";
    339   Handle<String> string = factory->NewStringFromAsciiChecked(name);
    340   CHECK_EQ(StrLength(name), string->length());
    341 }
    342 
    343 
    344 TEST(GlobalHandles) {
    345   CcTest::InitializeVM();
    346   Isolate* isolate = CcTest::i_isolate();
    347   Heap* heap = isolate->heap();
    348   Factory* factory = isolate->factory();
    349   GlobalHandles* global_handles = isolate->global_handles();
    350 
    351   Handle<Object> h1;
    352   Handle<Object> h2;
    353   Handle<Object> h3;
    354   Handle<Object> h4;
    355 
    356   {
    357     HandleScope scope(isolate);
    358 
    359     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
    360     Handle<Object> u = factory->NewNumber(1.12344);
    361 
    362     h1 = global_handles->Create(*i);
    363     h2 = global_handles->Create(*u);
    364     h3 = global_handles->Create(*i);
    365     h4 = global_handles->Create(*u);
    366   }
    367 
    368   // after gc, it should survive
    369   heap->CollectGarbage(NEW_SPACE);
    370 
    371   CHECK((*h1)->IsString());
    372   CHECK((*h2)->IsHeapNumber());
    373   CHECK((*h3)->IsString());
    374   CHECK((*h4)->IsHeapNumber());
    375 
    376   CHECK_EQ(*h3, *h1);
    377   GlobalHandles::Destroy(h1.location());
    378   GlobalHandles::Destroy(h3.location());
    379 
    380   CHECK_EQ(*h4, *h2);
    381   GlobalHandles::Destroy(h2.location());
    382   GlobalHandles::Destroy(h4.location());
    383 }
    384 
    385 
    386 static bool WeakPointerCleared = false;
    387 
    388 static void TestWeakGlobalHandleCallback(
    389     const v8::WeakCallbackData<v8::Value, void>& data) {
    390   std::pair<v8::Persistent<v8::Value>*, int>* p =
    391       reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>(
    392           data.GetParameter());
    393   if (p->second == 1234) WeakPointerCleared = true;
    394   p->first->Reset();
    395 }
    396 
    397 
    398 TEST(WeakGlobalHandlesScavenge) {
    399   i::FLAG_stress_compaction = false;
    400   CcTest::InitializeVM();
    401   Isolate* isolate = CcTest::i_isolate();
    402   Heap* heap = isolate->heap();
    403   Factory* factory = isolate->factory();
    404   GlobalHandles* global_handles = isolate->global_handles();
    405 
    406   WeakPointerCleared = false;
    407 
    408   Handle<Object> h1;
    409   Handle<Object> h2;
    410 
    411   {
    412     HandleScope scope(isolate);
    413 
    414     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
    415     Handle<Object> u = factory->NewNumber(1.12344);
    416 
    417     h1 = global_handles->Create(*i);
    418     h2 = global_handles->Create(*u);
    419   }
    420 
    421   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
    422   GlobalHandles::MakeWeak(h2.location(),
    423                           reinterpret_cast<void*>(&handle_and_id),
    424                           &TestWeakGlobalHandleCallback);
    425 
    426   // Scavenge treats weak pointers as normal roots.
    427   heap->CollectGarbage(NEW_SPACE);
    428 
    429   CHECK((*h1)->IsString());
    430   CHECK((*h2)->IsHeapNumber());
    431 
    432   CHECK(!WeakPointerCleared);
    433   CHECK(!global_handles->IsNearDeath(h2.location()));
    434   CHECK(!global_handles->IsNearDeath(h1.location()));
    435 
    436   GlobalHandles::Destroy(h1.location());
    437   GlobalHandles::Destroy(h2.location());
    438 }
    439 
    440 
    441 TEST(WeakGlobalHandlesMark) {
    442   CcTest::InitializeVM();
    443   Isolate* isolate = CcTest::i_isolate();
    444   Heap* heap = isolate->heap();
    445   Factory* factory = isolate->factory();
    446   GlobalHandles* global_handles = isolate->global_handles();
    447 
    448   WeakPointerCleared = false;
    449 
    450   Handle<Object> h1;
    451   Handle<Object> h2;
    452 
    453   {
    454     HandleScope scope(isolate);
    455 
    456     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
    457     Handle<Object> u = factory->NewNumber(1.12344);
    458 
    459     h1 = global_handles->Create(*i);
    460     h2 = global_handles->Create(*u);
    461   }
    462 
    463   // Make sure the objects are promoted.
    464   heap->CollectGarbage(OLD_POINTER_SPACE);
    465   heap->CollectGarbage(NEW_SPACE);
    466   CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
    467 
    468   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
    469   GlobalHandles::MakeWeak(h2.location(),
    470                           reinterpret_cast<void*>(&handle_and_id),
    471                           &TestWeakGlobalHandleCallback);
    472   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
    473   CHECK(!GlobalHandles::IsNearDeath(h2.location()));
    474 
    475   // Incremental marking potentially marked handles before they turned weak.
    476   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
    477 
    478   CHECK((*h1)->IsString());
    479 
    480   CHECK(WeakPointerCleared);
    481   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
    482 
    483   GlobalHandles::Destroy(h1.location());
    484 }
    485 
    486 
    487 TEST(DeleteWeakGlobalHandle) {
    488   i::FLAG_stress_compaction = false;
    489   CcTest::InitializeVM();
    490   Isolate* isolate = CcTest::i_isolate();
    491   Heap* heap = isolate->heap();
    492   Factory* factory = isolate->factory();
    493   GlobalHandles* global_handles = isolate->global_handles();
    494 
    495   WeakPointerCleared = false;
    496 
    497   Handle<Object> h;
    498 
    499   {
    500     HandleScope scope(isolate);
    501 
    502     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
    503     h = global_handles->Create(*i);
    504   }
    505 
    506   std::pair<Handle<Object>*, int> handle_and_id(&h, 1234);
    507   GlobalHandles::MakeWeak(h.location(),
    508                           reinterpret_cast<void*>(&handle_and_id),
    509                           &TestWeakGlobalHandleCallback);
    510 
    511   // Scanvenge does not recognize weak reference.
    512   heap->CollectGarbage(NEW_SPACE);
    513 
    514   CHECK(!WeakPointerCleared);
    515 
    516   // Mark-compact treats weak reference properly.
    517   heap->CollectGarbage(OLD_POINTER_SPACE);
    518 
    519   CHECK(WeakPointerCleared);
    520 }
    521 
    522 
    523 static const char* not_so_random_string_table[] = {
    524   "abstract",
    525   "boolean",
    526   "break",
    527   "byte",
    528   "case",
    529   "catch",
    530   "char",
    531   "class",
    532   "const",
    533   "continue",
    534   "debugger",
    535   "default",
    536   "delete",
    537   "do",
    538   "double",
    539   "else",
    540   "enum",
    541   "export",
    542   "extends",
    543   "false",
    544   "final",
    545   "finally",
    546   "float",
    547   "for",
    548   "function",
    549   "goto",
    550   "if",
    551   "implements",
    552   "import",
    553   "in",
    554   "instanceof",
    555   "int",
    556   "interface",
    557   "long",
    558   "native",
    559   "new",
    560   "null",
    561   "package",
    562   "private",
    563   "protected",
    564   "public",
    565   "return",
    566   "short",
    567   "static",
    568   "super",
    569   "switch",
    570   "synchronized",
    571   "this",
    572   "throw",
    573   "throws",
    574   "transient",
    575   "true",
    576   "try",
    577   "typeof",
    578   "var",
    579   "void",
    580   "volatile",
    581   "while",
    582   "with",
    583   0
    584 };
    585 
    586 
    587 static void CheckInternalizedStrings(const char** strings) {
    588   Isolate* isolate = CcTest::i_isolate();
    589   Factory* factory = isolate->factory();
    590   for (const char* string = *strings; *strings != 0; string = *strings++) {
    591     HandleScope scope(isolate);
    592     Handle<String> a =
    593         isolate->factory()->InternalizeUtf8String(CStrVector(string));
    594     // InternalizeUtf8String may return a failure if a GC is needed.
    595     CHECK(a->IsInternalizedString());
    596     Handle<String> b = factory->InternalizeUtf8String(string);
    597     CHECK_EQ(*b, *a);
    598     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
    599     b = isolate->factory()->InternalizeUtf8String(CStrVector(string));
    600     CHECK_EQ(*b, *a);
    601     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
    602   }
    603 }
    604 
    605 
    606 TEST(StringTable) {
    607   CcTest::InitializeVM();
    608 
    609   v8::HandleScope sc(CcTest::isolate());
    610   CheckInternalizedStrings(not_so_random_string_table);
    611   CheckInternalizedStrings(not_so_random_string_table);
    612 }
    613 
    614 
    615 TEST(FunctionAllocation) {
    616   CcTest::InitializeVM();
    617   Isolate* isolate = CcTest::i_isolate();
    618   Factory* factory = isolate->factory();
    619 
    620   v8::HandleScope sc(CcTest::isolate());
    621   Handle<String> name = factory->InternalizeUtf8String("theFunction");
    622   Handle<JSFunction> function = factory->NewFunction(name);
    623 
    624   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
    625   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
    626 
    627   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
    628   Handle<JSObject> obj = factory->NewJSObject(function);
    629   JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check();
    630   CHECK_EQ(Smi::FromInt(23),
    631            *Object::GetProperty(obj, prop_name).ToHandleChecked());
    632   // Check that we can add properties to function objects.
    633   JSReceiver::SetProperty(
    634       function, prop_name, twenty_four, NONE, SLOPPY).Check();
    635   CHECK_EQ(Smi::FromInt(24),
    636            *Object::GetProperty(function, prop_name).ToHandleChecked());
    637 }
    638 
    639 
    640 TEST(ObjectProperties) {
    641   CcTest::InitializeVM();
    642   Isolate* isolate = CcTest::i_isolate();
    643   Factory* factory = isolate->factory();
    644 
    645   v8::HandleScope sc(CcTest::isolate());
    646   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
    647   Handle<Object> object = Object::GetProperty(
    648       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
    649   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
    650   Handle<JSObject> obj = factory->NewJSObject(constructor);
    651   Handle<String> first = factory->InternalizeUtf8String("first");
    652   Handle<String> second = factory->InternalizeUtf8String("second");
    653 
    654   Handle<Smi> one(Smi::FromInt(1), isolate);
    655   Handle<Smi> two(Smi::FromInt(2), isolate);
    656 
    657   // check for empty
    658   CHECK(!JSReceiver::HasOwnProperty(obj, first));
    659 
    660   // add first
    661   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
    662   CHECK(JSReceiver::HasOwnProperty(obj, first));
    663 
    664   // delete first
    665   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
    666   CHECK(!JSReceiver::HasOwnProperty(obj, first));
    667 
    668   // add first and then second
    669   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
    670   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
    671   CHECK(JSReceiver::HasOwnProperty(obj, first));
    672   CHECK(JSReceiver::HasOwnProperty(obj, second));
    673 
    674   // delete first and then second
    675   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
    676   CHECK(JSReceiver::HasOwnProperty(obj, second));
    677   JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
    678   CHECK(!JSReceiver::HasOwnProperty(obj, first));
    679   CHECK(!JSReceiver::HasOwnProperty(obj, second));
    680 
    681   // add first and then second
    682   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
    683   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
    684   CHECK(JSReceiver::HasOwnProperty(obj, first));
    685   CHECK(JSReceiver::HasOwnProperty(obj, second));
    686 
    687   // delete second and then first
    688   JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
    689   CHECK(JSReceiver::HasOwnProperty(obj, first));
    690   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
    691   CHECK(!JSReceiver::HasOwnProperty(obj, first));
    692   CHECK(!JSReceiver::HasOwnProperty(obj, second));
    693 
    694   // check string and internalized string match
    695   const char* string1 = "fisk";
    696   Handle<String> s1 = factory->NewStringFromAsciiChecked(string1);
    697   JSReceiver::SetProperty(obj, s1, one, NONE, SLOPPY).Check();
    698   Handle<String> s1_string = factory->InternalizeUtf8String(string1);
    699   CHECK(JSReceiver::HasOwnProperty(obj, s1_string));
    700 
    701   // check internalized string and string match
    702   const char* string2 = "fugl";
    703   Handle<String> s2_string = factory->InternalizeUtf8String(string2);
    704   JSReceiver::SetProperty(obj, s2_string, one, NONE, SLOPPY).Check();
    705   Handle<String> s2 = factory->NewStringFromAsciiChecked(string2);
    706   CHECK(JSReceiver::HasOwnProperty(obj, s2));
    707 }
    708 
    709 
    710 TEST(JSObjectMaps) {
    711   CcTest::InitializeVM();
    712   Isolate* isolate = CcTest::i_isolate();
    713   Factory* factory = isolate->factory();
    714 
    715   v8::HandleScope sc(CcTest::isolate());
    716   Handle<String> name = factory->InternalizeUtf8String("theFunction");
    717   Handle<JSFunction> function = factory->NewFunction(name);
    718 
    719   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
    720   Handle<JSObject> obj = factory->NewJSObject(function);
    721   Handle<Map> initial_map(function->initial_map());
    722 
    723   // Set a propery
    724   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
    725   JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check();
    726   CHECK_EQ(Smi::FromInt(23),
    727            *Object::GetProperty(obj, prop_name).ToHandleChecked());
    728 
    729   // Check the map has changed
    730   CHECK(*initial_map != obj->map());
    731 }
    732 
    733 
    734 TEST(JSArray) {
    735   CcTest::InitializeVM();
    736   Isolate* isolate = CcTest::i_isolate();
    737   Factory* factory = isolate->factory();
    738 
    739   v8::HandleScope sc(CcTest::isolate());
    740   Handle<String> name = factory->InternalizeUtf8String("Array");
    741   Handle<Object> fun_obj = Object::GetProperty(
    742       CcTest::i_isolate()->global_object(), name).ToHandleChecked();
    743   Handle<JSFunction> function = Handle<JSFunction>::cast(fun_obj);
    744 
    745   // Allocate the object.
    746   Handle<Object> element;
    747   Handle<JSObject> object = factory->NewJSObject(function);
    748   Handle<JSArray> array = Handle<JSArray>::cast(object);
    749   // We just initialized the VM, no heap allocation failure yet.
    750   JSArray::Initialize(array, 0);
    751 
    752   // Set array length to 0.
    753   JSArray::SetElementsLength(array, handle(Smi::FromInt(0), isolate)).Check();
    754   CHECK_EQ(Smi::FromInt(0), array->length());
    755   // Must be in fast mode.
    756   CHECK(array->HasFastSmiOrObjectElements());
    757 
    758   // array[length] = name.
    759   JSReceiver::SetElement(array, 0, name, NONE, SLOPPY).Check();
    760   CHECK_EQ(Smi::FromInt(1), array->length());
    761   element = i::Object::GetElement(isolate, array, 0).ToHandleChecked();
    762   CHECK_EQ(*element, *name);
    763 
    764   // Set array length with larger than smi value.
    765   Handle<Object> length =
    766       factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
    767   JSArray::SetElementsLength(array, length).Check();
    768 
    769   uint32_t int_length = 0;
    770   CHECK(length->ToArrayIndex(&int_length));
    771   CHECK_EQ(*length, array->length());
    772   CHECK(array->HasDictionaryElements());  // Must be in slow mode.
    773 
    774   // array[length] = name.
    775   JSReceiver::SetElement(array, int_length, name, NONE, SLOPPY).Check();
    776   uint32_t new_int_length = 0;
    777   CHECK(array->length()->ToArrayIndex(&new_int_length));
    778   CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
    779   element = Object::GetElement(isolate, array, int_length).ToHandleChecked();
    780   CHECK_EQ(*element, *name);
    781   element = Object::GetElement(isolate, array, 0).ToHandleChecked();
    782   CHECK_EQ(*element, *name);
    783 }
    784 
    785 
    786 TEST(JSObjectCopy) {
    787   CcTest::InitializeVM();
    788   Isolate* isolate = CcTest::i_isolate();
    789   Factory* factory = isolate->factory();
    790 
    791   v8::HandleScope sc(CcTest::isolate());
    792   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
    793   Handle<Object> object = Object::GetProperty(
    794       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
    795   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
    796   Handle<JSObject> obj = factory->NewJSObject(constructor);
    797   Handle<String> first = factory->InternalizeUtf8String("first");
    798   Handle<String> second = factory->InternalizeUtf8String("second");
    799 
    800   Handle<Smi> one(Smi::FromInt(1), isolate);
    801   Handle<Smi> two(Smi::FromInt(2), isolate);
    802 
    803   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
    804   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
    805 
    806   JSReceiver::SetElement(obj, 0, first, NONE, SLOPPY).Check();
    807   JSReceiver::SetElement(obj, 1, second, NONE, SLOPPY).Check();
    808 
    809   // Make the clone.
    810   Handle<Object> value1, value2;
    811   Handle<JSObject> clone = factory->CopyJSObject(obj);
    812   CHECK(!clone.is_identical_to(obj));
    813 
    814   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
    815   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
    816   CHECK_EQ(*value1, *value2);
    817   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
    818   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
    819   CHECK_EQ(*value1, *value2);
    820 
    821   value1 = Object::GetProperty(obj, first).ToHandleChecked();
    822   value2 = Object::GetProperty(clone, first).ToHandleChecked();
    823   CHECK_EQ(*value1, *value2);
    824   value1 = Object::GetProperty(obj, second).ToHandleChecked();
    825   value2 = Object::GetProperty(clone, second).ToHandleChecked();
    826   CHECK_EQ(*value1, *value2);
    827 
    828   // Flip the values.
    829   JSReceiver::SetProperty(clone, first, two, NONE, SLOPPY).Check();
    830   JSReceiver::SetProperty(clone, second, one, NONE, SLOPPY).Check();
    831 
    832   JSReceiver::SetElement(clone, 0, second, NONE, SLOPPY).Check();
    833   JSReceiver::SetElement(clone, 1, first, NONE, SLOPPY).Check();
    834 
    835   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
    836   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
    837   CHECK_EQ(*value1, *value2);
    838   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
    839   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
    840   CHECK_EQ(*value1, *value2);
    841 
    842   value1 = Object::GetProperty(obj, second).ToHandleChecked();
    843   value2 = Object::GetProperty(clone, first).ToHandleChecked();
    844   CHECK_EQ(*value1, *value2);
    845   value1 = Object::GetProperty(obj, first).ToHandleChecked();
    846   value2 = Object::GetProperty(clone, second).ToHandleChecked();
    847   CHECK_EQ(*value1, *value2);
    848 }
    849 
    850 
    851 TEST(StringAllocation) {
    852   CcTest::InitializeVM();
    853   Isolate* isolate = CcTest::i_isolate();
    854   Factory* factory = isolate->factory();
    855 
    856   const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
    857   for (int length = 0; length < 100; length++) {
    858     v8::HandleScope scope(CcTest::isolate());
    859     char* non_ascii = NewArray<char>(3 * length + 1);
    860     char* ascii = NewArray<char>(length + 1);
    861     non_ascii[3 * length] = 0;
    862     ascii[length] = 0;
    863     for (int i = 0; i < length; i++) {
    864       ascii[i] = 'a';
    865       non_ascii[3 * i] = chars[0];
    866       non_ascii[3 * i + 1] = chars[1];
    867       non_ascii[3 * i + 2] = chars[2];
    868     }
    869     Handle<String> non_ascii_sym =
    870         factory->InternalizeUtf8String(
    871             Vector<const char>(non_ascii, 3 * length));
    872     CHECK_EQ(length, non_ascii_sym->length());
    873     Handle<String> ascii_sym =
    874         factory->InternalizeOneByteString(OneByteVector(ascii, length));
    875     CHECK_EQ(length, ascii_sym->length());
    876     Handle<String> non_ascii_str = factory->NewStringFromUtf8(
    877         Vector<const char>(non_ascii, 3 * length)).ToHandleChecked();
    878     non_ascii_str->Hash();
    879     CHECK_EQ(length, non_ascii_str->length());
    880     Handle<String> ascii_str = factory->NewStringFromUtf8(
    881         Vector<const char>(ascii, length)).ToHandleChecked();
    882     ascii_str->Hash();
    883     CHECK_EQ(length, ascii_str->length());
    884     DeleteArray(non_ascii);
    885     DeleteArray(ascii);
    886   }
    887 }
    888 
    889 
    890 static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
    891   // Count the number of objects found in the heap.
    892   int found_count = 0;
    893   HeapIterator iterator(heap);
    894   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
    895     for (int i = 0; i < size; i++) {
    896       if (*objs[i] == obj) {
    897         found_count++;
    898       }
    899     }
    900   }
    901   return found_count;
    902 }
    903 
    904 
    905 TEST(Iteration) {
    906   CcTest::InitializeVM();
    907   Isolate* isolate = CcTest::i_isolate();
    908   Factory* factory = isolate->factory();
    909   v8::HandleScope scope(CcTest::isolate());
    910 
    911   // Array of objects to scan haep for.
    912   const int objs_count = 6;
    913   Handle<Object> objs[objs_count];
    914   int next_objs_index = 0;
    915 
    916   // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
    917   objs[next_objs_index++] = factory->NewJSArray(10);
    918   objs[next_objs_index++] = factory->NewJSArray(10,
    919                                                 FAST_HOLEY_ELEMENTS,
    920                                                 TENURED);
    921 
    922   // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
    923   objs[next_objs_index++] =
    924       factory->NewStringFromStaticAscii("abcdefghij");
    925   objs[next_objs_index++] =
    926       factory->NewStringFromStaticAscii("abcdefghij", TENURED);
    927 
    928   // Allocate a large string (for large object space).
    929   int large_size = Page::kMaxRegularHeapObjectSize + 1;
    930   char* str = new char[large_size];
    931   for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
    932   str[large_size - 1] = '\0';
    933   objs[next_objs_index++] = factory->NewStringFromAsciiChecked(str, TENURED);
    934   delete[] str;
    935 
    936   // Add a Map object to look for.
    937   objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
    938 
    939   CHECK_EQ(objs_count, next_objs_index);
    940   CHECK_EQ(objs_count, ObjectsFoundInHeap(CcTest::heap(), objs, objs_count));
    941 }
    942 
    943 
    944 TEST(EmptyHandleEscapeFrom) {
    945   CcTest::InitializeVM();
    946 
    947   v8::HandleScope scope(CcTest::isolate());
    948   Handle<JSObject> runaway;
    949 
    950   {
    951       v8::EscapableHandleScope nested(CcTest::isolate());
    952       Handle<JSObject> empty;
    953       runaway = empty.EscapeFrom(&nested);
    954   }
    955 
    956   CHECK(runaway.is_null());
    957 }
    958 
    959 
    960 static int LenFromSize(int size) {
    961   return (size - FixedArray::kHeaderSize) / kPointerSize;
    962 }
    963 
    964 
    965 TEST(Regression39128) {
    966   // Test case for crbug.com/39128.
    967   CcTest::InitializeVM();
    968   Isolate* isolate = CcTest::i_isolate();
    969   TestHeap* heap = CcTest::test_heap();
    970 
    971   // Increase the chance of 'bump-the-pointer' allocation in old space.
    972   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
    973 
    974   v8::HandleScope scope(CcTest::isolate());
    975 
    976   // The plan: create JSObject which references objects in new space.
    977   // Then clone this object (forcing it to go into old space) and check
    978   // that region dirty marks are updated correctly.
    979 
    980   // Step 1: prepare a map for the object.  We add 1 inobject property to it.
    981   Handle<JSFunction> object_ctor(
    982       CcTest::i_isolate()->native_context()->object_function());
    983   CHECK(object_ctor->has_initial_map());
    984   // Create a map with single inobject property.
    985   Handle<Map> my_map = Map::Create(object_ctor, 1);
    986   int n_properties = my_map->inobject_properties();
    987   CHECK_GT(n_properties, 0);
    988 
    989   int object_size = my_map->instance_size();
    990 
    991   // Step 2: allocate a lot of objects so to almost fill new space: we need
    992   // just enough room to allocate JSObject and thus fill the newspace.
    993 
    994   int allocation_amount = Min(FixedArray::kMaxSize,
    995                               Page::kMaxRegularHeapObjectSize + kPointerSize);
    996   int allocation_len = LenFromSize(allocation_amount);
    997   NewSpace* new_space = heap->new_space();
    998   Address* top_addr = new_space->allocation_top_address();
    999   Address* limit_addr = new_space->allocation_limit_address();
   1000   while ((*limit_addr - *top_addr) > allocation_amount) {
   1001     CHECK(!heap->always_allocate());
   1002     Object* array = heap->AllocateFixedArray(allocation_len).ToObjectChecked();
   1003     CHECK(new_space->Contains(array));
   1004   }
   1005 
   1006   // Step 3: now allocate fixed array and JSObject to fill the whole new space.
   1007   int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
   1008   int fixed_array_len = LenFromSize(to_fill);
   1009   CHECK(fixed_array_len < FixedArray::kMaxLength);
   1010 
   1011   CHECK(!heap->always_allocate());
   1012   Object* array = heap->AllocateFixedArray(fixed_array_len).ToObjectChecked();
   1013   CHECK(new_space->Contains(array));
   1014 
   1015   Object* object = heap->AllocateJSObjectFromMap(*my_map).ToObjectChecked();
   1016   CHECK(new_space->Contains(object));
   1017   JSObject* jsobject = JSObject::cast(object);
   1018   CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
   1019   CHECK_EQ(0, jsobject->properties()->length());
   1020   // Create a reference to object in new space in jsobject.
   1021   FieldIndex index = FieldIndex::ForInObjectOffset(
   1022       JSObject::kHeaderSize - kPointerSize);
   1023   jsobject->FastPropertyAtPut(index, array);
   1024 
   1025   CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
   1026 
   1027   // Step 4: clone jsobject, but force always allocate first to create a clone
   1028   // in old pointer space.
   1029   Address old_pointer_space_top = heap->old_pointer_space()->top();
   1030   AlwaysAllocateScope aa_scope(isolate);
   1031   Object* clone_obj = heap->CopyJSObject(jsobject).ToObjectChecked();
   1032   JSObject* clone = JSObject::cast(clone_obj);
   1033   if (clone->address() != old_pointer_space_top) {
   1034     // Alas, got allocated from free list, we cannot do checks.
   1035     return;
   1036   }
   1037   CHECK(heap->old_pointer_space()->Contains(clone->address()));
   1038 }
   1039 
   1040 
   1041 TEST(TestCodeFlushing) {
   1042   // If we do not flush code this test is invalid.
   1043   if (!FLAG_flush_code) return;
   1044   i::FLAG_allow_natives_syntax = true;
   1045   i::FLAG_optimize_for_size = false;
   1046   CcTest::InitializeVM();
   1047   Isolate* isolate = CcTest::i_isolate();
   1048   Factory* factory = isolate->factory();
   1049   v8::HandleScope scope(CcTest::isolate());
   1050   const char* source = "function foo() {"
   1051                        "  var x = 42;"
   1052                        "  var y = 42;"
   1053                        "  var z = x + y;"
   1054                        "};"
   1055                        "foo()";
   1056   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1057 
   1058   // This compile will add the code to the compilation cache.
   1059   { v8::HandleScope scope(CcTest::isolate());
   1060     CompileRun(source);
   1061   }
   1062 
   1063   // Check function is compiled.
   1064   Handle<Object> func_value = Object::GetProperty(
   1065       CcTest::i_isolate()->global_object(), foo_name).ToHandleChecked();
   1066   CHECK(func_value->IsJSFunction());
   1067   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1068   CHECK(function->shared()->is_compiled());
   1069 
   1070   // The code will survive at least two GCs.
   1071   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1072   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1073   CHECK(function->shared()->is_compiled());
   1074 
   1075   // Simulate several GCs that use full marking.
   1076   const int kAgingThreshold = 6;
   1077   for (int i = 0; i < kAgingThreshold; i++) {
   1078     CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1079   }
   1080 
   1081   // foo should no longer be in the compilation cache
   1082   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1083   CHECK(!function->is_compiled() || function->IsOptimized());
   1084   // Call foo to get it recompiled.
   1085   CompileRun("foo()");
   1086   CHECK(function->shared()->is_compiled());
   1087   CHECK(function->is_compiled());
   1088 }
   1089 
   1090 
   1091 TEST(TestCodeFlushingPreAged) {
   1092   // If we do not flush code this test is invalid.
   1093   if (!FLAG_flush_code) return;
   1094   i::FLAG_allow_natives_syntax = true;
   1095   i::FLAG_optimize_for_size = true;
   1096   CcTest::InitializeVM();
   1097   Isolate* isolate = CcTest::i_isolate();
   1098   Factory* factory = isolate->factory();
   1099   v8::HandleScope scope(CcTest::isolate());
   1100   const char* source = "function foo() {"
   1101                        "  var x = 42;"
   1102                        "  var y = 42;"
   1103                        "  var z = x + y;"
   1104                        "};"
   1105                        "foo()";
   1106   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1107 
   1108   // Compile foo, but don't run it.
   1109   { v8::HandleScope scope(CcTest::isolate());
   1110     CompileRun(source);
   1111   }
   1112 
   1113   // Check function is compiled.
   1114   Handle<Object> func_value =
   1115       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1116   CHECK(func_value->IsJSFunction());
   1117   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1118   CHECK(function->shared()->is_compiled());
   1119 
   1120   // The code has been run so will survive at least one GC.
   1121   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1122   CHECK(function->shared()->is_compiled());
   1123 
   1124   // The code was only run once, so it should be pre-aged and collected on the
   1125   // next GC.
   1126   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1127   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1128 
   1129   // Execute the function again twice, and ensure it is reset to the young age.
   1130   { v8::HandleScope scope(CcTest::isolate());
   1131     CompileRun("foo();"
   1132                "foo();");
   1133   }
   1134 
   1135   // The code will survive at least two GC now that it is young again.
   1136   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1137   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1138   CHECK(function->shared()->is_compiled());
   1139 
   1140   // Simulate several GCs that use full marking.
   1141   const int kAgingThreshold = 6;
   1142   for (int i = 0; i < kAgingThreshold; i++) {
   1143     CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1144   }
   1145 
   1146   // foo should no longer be in the compilation cache
   1147   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1148   CHECK(!function->is_compiled() || function->IsOptimized());
   1149   // Call foo to get it recompiled.
   1150   CompileRun("foo()");
   1151   CHECK(function->shared()->is_compiled());
   1152   CHECK(function->is_compiled());
   1153 }
   1154 
   1155 
   1156 TEST(TestCodeFlushingIncremental) {
   1157   // If we do not flush code this test is invalid.
   1158   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   1159   i::FLAG_allow_natives_syntax = true;
   1160   i::FLAG_optimize_for_size = false;
   1161   CcTest::InitializeVM();
   1162   Isolate* isolate = CcTest::i_isolate();
   1163   Factory* factory = isolate->factory();
   1164   v8::HandleScope scope(CcTest::isolate());
   1165   const char* source = "function foo() {"
   1166                        "  var x = 42;"
   1167                        "  var y = 42;"
   1168                        "  var z = x + y;"
   1169                        "};"
   1170                        "foo()";
   1171   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1172 
   1173   // This compile will add the code to the compilation cache.
   1174   { v8::HandleScope scope(CcTest::isolate());
   1175     CompileRun(source);
   1176   }
   1177 
   1178   // Check function is compiled.
   1179   Handle<Object> func_value =
   1180       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1181   CHECK(func_value->IsJSFunction());
   1182   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1183   CHECK(function->shared()->is_compiled());
   1184 
   1185   // The code will survive at least two GCs.
   1186   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1187   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1188   CHECK(function->shared()->is_compiled());
   1189 
   1190   // Simulate several GCs that use incremental marking.
   1191   const int kAgingThreshold = 6;
   1192   for (int i = 0; i < kAgingThreshold; i++) {
   1193     SimulateIncrementalMarking();
   1194     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1195   }
   1196   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1197   CHECK(!function->is_compiled() || function->IsOptimized());
   1198 
   1199   // This compile will compile the function again.
   1200   { v8::HandleScope scope(CcTest::isolate());
   1201     CompileRun("foo();");
   1202   }
   1203 
   1204   // Simulate several GCs that use incremental marking but make sure
   1205   // the loop breaks once the function is enqueued as a candidate.
   1206   for (int i = 0; i < kAgingThreshold; i++) {
   1207     SimulateIncrementalMarking();
   1208     if (!function->next_function_link()->IsUndefined()) break;
   1209     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1210   }
   1211 
   1212   // Force optimization while incremental marking is active and while
   1213   // the function is enqueued as a candidate.
   1214   { v8::HandleScope scope(CcTest::isolate());
   1215     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   1216   }
   1217 
   1218   // Simulate one final GC to make sure the candidate queue is sane.
   1219   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1220   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
   1221   CHECK(function->is_compiled() || !function->IsOptimized());
   1222 }
   1223 
   1224 
   1225 TEST(TestCodeFlushingIncrementalScavenge) {
   1226   // If we do not flush code this test is invalid.
   1227   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   1228   i::FLAG_allow_natives_syntax = true;
   1229   i::FLAG_optimize_for_size = false;
   1230   CcTest::InitializeVM();
   1231   Isolate* isolate = CcTest::i_isolate();
   1232   Factory* factory = isolate->factory();
   1233   v8::HandleScope scope(CcTest::isolate());
   1234   const char* source = "var foo = function() {"
   1235                        "  var x = 42;"
   1236                        "  var y = 42;"
   1237                        "  var z = x + y;"
   1238                        "};"
   1239                        "foo();"
   1240                        "var bar = function() {"
   1241                        "  var x = 23;"
   1242                        "};"
   1243                        "bar();";
   1244   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1245   Handle<String> bar_name = factory->InternalizeUtf8String("bar");
   1246 
   1247   // Perfrom one initial GC to enable code flushing.
   1248   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1249 
   1250   // This compile will add the code to the compilation cache.
   1251   { v8::HandleScope scope(CcTest::isolate());
   1252     CompileRun(source);
   1253   }
   1254 
   1255   // Check functions are compiled.
   1256   Handle<Object> func_value =
   1257       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1258   CHECK(func_value->IsJSFunction());
   1259   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1260   CHECK(function->shared()->is_compiled());
   1261   Handle<Object> func_value2 =
   1262       Object::GetProperty(isolate->global_object(), bar_name).ToHandleChecked();
   1263   CHECK(func_value2->IsJSFunction());
   1264   Handle<JSFunction> function2 = Handle<JSFunction>::cast(func_value2);
   1265   CHECK(function2->shared()->is_compiled());
   1266 
   1267   // Clear references to functions so that one of them can die.
   1268   { v8::HandleScope scope(CcTest::isolate());
   1269     CompileRun("foo = 0; bar = 0;");
   1270   }
   1271 
   1272   // Bump the code age so that flushing is triggered while the function
   1273   // object is still located in new-space.
   1274   const int kAgingThreshold = 6;
   1275   for (int i = 0; i < kAgingThreshold; i++) {
   1276     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1277     function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1278   }
   1279 
   1280   // Simulate incremental marking so that the functions are enqueued as
   1281   // code flushing candidates. Then kill one of the functions. Finally
   1282   // perform a scavenge while incremental marking is still running.
   1283   SimulateIncrementalMarking();
   1284   *function2.location() = NULL;
   1285   CcTest::heap()->CollectGarbage(NEW_SPACE, "test scavenge while marking");
   1286 
   1287   // Simulate one final GC to make sure the candidate queue is sane.
   1288   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1289   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1290   CHECK(!function->is_compiled() || function->IsOptimized());
   1291 }
   1292 
   1293 
   1294 TEST(TestCodeFlushingIncrementalAbort) {
   1295   // If we do not flush code this test is invalid.
   1296   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
   1297   i::FLAG_allow_natives_syntax = true;
   1298   i::FLAG_optimize_for_size = false;
   1299   CcTest::InitializeVM();
   1300   Isolate* isolate = CcTest::i_isolate();
   1301   Factory* factory = isolate->factory();
   1302   Heap* heap = isolate->heap();
   1303   v8::HandleScope scope(CcTest::isolate());
   1304   const char* source = "function foo() {"
   1305                        "  var x = 42;"
   1306                        "  var y = 42;"
   1307                        "  var z = x + y;"
   1308                        "};"
   1309                        "foo()";
   1310   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1311 
   1312   // This compile will add the code to the compilation cache.
   1313   { v8::HandleScope scope(CcTest::isolate());
   1314     CompileRun(source);
   1315   }
   1316 
   1317   // Check function is compiled.
   1318   Handle<Object> func_value =
   1319       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1320   CHECK(func_value->IsJSFunction());
   1321   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1322   CHECK(function->shared()->is_compiled());
   1323 
   1324   // The code will survive at least two GCs.
   1325   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1326   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   1327   CHECK(function->shared()->is_compiled());
   1328 
   1329   // Bump the code age so that flushing is triggered.
   1330   const int kAgingThreshold = 6;
   1331   for (int i = 0; i < kAgingThreshold; i++) {
   1332     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1333   }
   1334 
   1335   // Simulate incremental marking so that the function is enqueued as
   1336   // code flushing candidate.
   1337   SimulateIncrementalMarking();
   1338 
   1339   // Enable the debugger and add a breakpoint while incremental marking
   1340   // is running so that incremental marking aborts and code flushing is
   1341   // disabled.
   1342   int position = 0;
   1343   Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
   1344   isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
   1345   isolate->debug()->ClearAllBreakPoints();
   1346 
   1347   // Force optimization now that code flushing is disabled.
   1348   { v8::HandleScope scope(CcTest::isolate());
   1349     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   1350   }
   1351 
   1352   // Simulate one final GC to make sure the candidate queue is sane.
   1353   heap->CollectAllGarbage(Heap::kNoGCFlags);
   1354   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
   1355   CHECK(function->is_compiled() || !function->IsOptimized());
   1356 }
   1357 
   1358 
   1359 // Count the number of native contexts in the weak list of native contexts.
   1360 int CountNativeContexts() {
   1361   int count = 0;
   1362   Object* object = CcTest::heap()->native_contexts_list();
   1363   while (!object->IsUndefined()) {
   1364     count++;
   1365     object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
   1366   }
   1367   return count;
   1368 }
   1369 
   1370 
   1371 // Count the number of user functions in the weak list of optimized
   1372 // functions attached to a native context.
   1373 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
   1374   int count = 0;
   1375   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
   1376   Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
   1377   while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
   1378     count++;
   1379     object = JSFunction::cast(object)->next_function_link();
   1380   }
   1381   return count;
   1382 }
   1383 
   1384 
   1385 TEST(TestInternalWeakLists) {
   1386   v8::V8::Initialize();
   1387 
   1388   // Some flags turn Scavenge collections into Mark-sweep collections
   1389   // and hence are incompatible with this test case.
   1390   if (FLAG_gc_global || FLAG_stress_compaction) return;
   1391 
   1392   static const int kNumTestContexts = 10;
   1393 
   1394   Isolate* isolate = CcTest::i_isolate();
   1395   Heap* heap = isolate->heap();
   1396   HandleScope scope(isolate);
   1397   v8::Handle<v8::Context> ctx[kNumTestContexts];
   1398 
   1399   CHECK_EQ(0, CountNativeContexts());
   1400 
   1401   // Create a number of global contests which gets linked together.
   1402   for (int i = 0; i < kNumTestContexts; i++) {
   1403     ctx[i] = v8::Context::New(CcTest::isolate());
   1404 
   1405     // Collect garbage that might have been created by one of the
   1406     // installed extensions.
   1407     isolate->compilation_cache()->Clear();
   1408     heap->CollectAllGarbage(Heap::kNoGCFlags);
   1409 
   1410     bool opt = (FLAG_always_opt && isolate->use_crankshaft());
   1411 
   1412     CHECK_EQ(i + 1, CountNativeContexts());
   1413 
   1414     ctx[i]->Enter();
   1415 
   1416     // Create a handle scope so no function objects get stuch in the outer
   1417     // handle scope
   1418     HandleScope scope(isolate);
   1419     const char* source = "function f1() { };"
   1420                          "function f2() { };"
   1421                          "function f3() { };"
   1422                          "function f4() { };"
   1423                          "function f5() { };";
   1424     CompileRun(source);
   1425     CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
   1426     CompileRun("f1()");
   1427     CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
   1428     CompileRun("f2()");
   1429     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
   1430     CompileRun("f3()");
   1431     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
   1432     CompileRun("f4()");
   1433     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
   1434     CompileRun("f5()");
   1435     CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
   1436 
   1437     // Remove function f1, and
   1438     CompileRun("f1=null");
   1439 
   1440     // Scavenge treats these references as strong.
   1441     for (int j = 0; j < 10; j++) {
   1442       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1443       CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
   1444     }
   1445 
   1446     // Mark compact handles the weak references.
   1447     isolate->compilation_cache()->Clear();
   1448     heap->CollectAllGarbage(Heap::kNoGCFlags);
   1449     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
   1450 
   1451     // Get rid of f3 and f5 in the same way.
   1452     CompileRun("f3=null");
   1453     for (int j = 0; j < 10; j++) {
   1454       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1455       CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
   1456     }
   1457     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1458     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
   1459     CompileRun("f5=null");
   1460     for (int j = 0; j < 10; j++) {
   1461       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1462       CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
   1463     }
   1464     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1465     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
   1466 
   1467     ctx[i]->Exit();
   1468   }
   1469 
   1470   // Force compilation cache cleanup.
   1471   CcTest::heap()->NotifyContextDisposed();
   1472   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1473 
   1474   // Dispose the native contexts one by one.
   1475   for (int i = 0; i < kNumTestContexts; i++) {
   1476     // TODO(dcarney): is there a better way to do this?
   1477     i::Object** unsafe = reinterpret_cast<i::Object**>(*ctx[i]);
   1478     *unsafe = CcTest::heap()->undefined_value();
   1479     ctx[i].Clear();
   1480 
   1481     // Scavenge treats these references as strong.
   1482     for (int j = 0; j < 10; j++) {
   1483       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   1484       CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
   1485     }
   1486 
   1487     // Mark compact handles the weak references.
   1488     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1489     CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
   1490   }
   1491 
   1492   CHECK_EQ(0, CountNativeContexts());
   1493 }
   1494 
   1495 
   1496 // Count the number of native contexts in the weak list of native contexts
   1497 // causing a GC after the specified number of elements.
   1498 static int CountNativeContextsWithGC(Isolate* isolate, int n) {
   1499   Heap* heap = isolate->heap();
   1500   int count = 0;
   1501   Handle<Object> object(heap->native_contexts_list(), isolate);
   1502   while (!object->IsUndefined()) {
   1503     count++;
   1504     if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
   1505     object =
   1506         Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
   1507                        isolate);
   1508   }
   1509   return count;
   1510 }
   1511 
   1512 
   1513 // Count the number of user functions in the weak list of optimized
   1514 // functions attached to a native context causing a GC after the
   1515 // specified number of elements.
   1516 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
   1517                                              int n) {
   1518   int count = 0;
   1519   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
   1520   Isolate* isolate = icontext->GetIsolate();
   1521   Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
   1522                         isolate);
   1523   while (object->IsJSFunction() &&
   1524          !Handle<JSFunction>::cast(object)->IsBuiltin()) {
   1525     count++;
   1526     if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1527     object = Handle<Object>(
   1528         Object::cast(JSFunction::cast(*object)->next_function_link()),
   1529         isolate);
   1530   }
   1531   return count;
   1532 }
   1533 
   1534 
   1535 TEST(TestInternalWeakListsTraverseWithGC) {
   1536   v8::V8::Initialize();
   1537   Isolate* isolate = CcTest::i_isolate();
   1538 
   1539   static const int kNumTestContexts = 10;
   1540 
   1541   HandleScope scope(isolate);
   1542   v8::Handle<v8::Context> ctx[kNumTestContexts];
   1543 
   1544   CHECK_EQ(0, CountNativeContexts());
   1545 
   1546   // Create an number of contexts and check the length of the weak list both
   1547   // with and without GCs while iterating the list.
   1548   for (int i = 0; i < kNumTestContexts; i++) {
   1549     ctx[i] = v8::Context::New(CcTest::isolate());
   1550     CHECK_EQ(i + 1, CountNativeContexts());
   1551     CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
   1552   }
   1553 
   1554   bool opt = (FLAG_always_opt && isolate->use_crankshaft());
   1555 
   1556   // Compile a number of functions the length of the weak list of optimized
   1557   // functions both with and without GCs while iterating the list.
   1558   ctx[0]->Enter();
   1559   const char* source = "function f1() { };"
   1560                        "function f2() { };"
   1561                        "function f3() { };"
   1562                        "function f4() { };"
   1563                        "function f5() { };";
   1564   CompileRun(source);
   1565   CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
   1566   CompileRun("f1()");
   1567   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
   1568   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1569   CompileRun("f2()");
   1570   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
   1571   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1572   CompileRun("f3()");
   1573   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
   1574   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1575   CompileRun("f4()");
   1576   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
   1577   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
   1578   CompileRun("f5()");
   1579   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
   1580   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
   1581 
   1582   ctx[0]->Exit();
   1583 }
   1584 
   1585 
   1586 TEST(TestSizeOfObjects) {
   1587   v8::V8::Initialize();
   1588 
   1589   // Get initial heap size after several full GCs, which will stabilize
   1590   // the heap size and return with sweeping finished completely.
   1591   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1592   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1593   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1594   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1595   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1596   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
   1597   if (collector->IsConcurrentSweepingInProgress()) {
   1598     collector->WaitUntilSweepingCompleted();
   1599   }
   1600   int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
   1601 
   1602   {
   1603     // Allocate objects on several different old-space pages so that
   1604     // concurrent sweeper threads will be busy sweeping the old space on
   1605     // subsequent GC runs.
   1606     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   1607     int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
   1608     for (int i = 1; i <= 100; i++) {
   1609       CcTest::test_heap()->AllocateFixedArray(8192, TENURED).ToObjectChecked();
   1610       CHECK_EQ(initial_size + i * filler_size,
   1611                static_cast<int>(CcTest::heap()->SizeOfObjects()));
   1612     }
   1613   }
   1614 
   1615   // The heap size should go back to initial size after a full GC, even
   1616   // though sweeping didn't finish yet.
   1617   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1618 
   1619   // Normally sweeping would not be complete here, but no guarantees.
   1620 
   1621   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
   1622 
   1623   // Waiting for sweeper threads should not change heap size.
   1624   if (collector->IsConcurrentSweepingInProgress()) {
   1625     collector->WaitUntilSweepingCompleted();
   1626   }
   1627   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
   1628 }
   1629 
   1630 
   1631 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
   1632   CcTest::InitializeVM();
   1633   HeapIterator iterator(CcTest::heap());
   1634   intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects();
   1635   intptr_t size_of_objects_2 = 0;
   1636   for (HeapObject* obj = iterator.next();
   1637        obj != NULL;
   1638        obj = iterator.next()) {
   1639     if (!obj->IsFreeSpace()) {
   1640       size_of_objects_2 += obj->Size();
   1641     }
   1642   }
   1643   // Delta must be within 5% of the larger result.
   1644   // TODO(gc): Tighten this up by distinguishing between byte
   1645   // arrays that are real and those that merely mark free space
   1646   // on the heap.
   1647   if (size_of_objects_1 > size_of_objects_2) {
   1648     intptr_t delta = size_of_objects_1 - size_of_objects_2;
   1649     PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
   1650            "Iterator: %" V8_PTR_PREFIX "d, "
   1651            "delta: %" V8_PTR_PREFIX "d\n",
   1652            size_of_objects_1, size_of_objects_2, delta);
   1653     CHECK_GT(size_of_objects_1 / 20, delta);
   1654   } else {
   1655     intptr_t delta = size_of_objects_2 - size_of_objects_1;
   1656     PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
   1657            "Iterator: %" V8_PTR_PREFIX "d, "
   1658            "delta: %" V8_PTR_PREFIX "d\n",
   1659            size_of_objects_1, size_of_objects_2, delta);
   1660     CHECK_GT(size_of_objects_2 / 20, delta);
   1661   }
   1662 }
   1663 
   1664 
   1665 static void FillUpNewSpace(NewSpace* new_space) {
   1666   // Fill up new space to the point that it is completely full. Make sure
   1667   // that the scavenger does not undo the filling.
   1668   Heap* heap = new_space->heap();
   1669   Isolate* isolate = heap->isolate();
   1670   Factory* factory = isolate->factory();
   1671   HandleScope scope(isolate);
   1672   AlwaysAllocateScope always_allocate(isolate);
   1673   intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
   1674   intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
   1675   for (intptr_t i = 0; i < number_of_fillers; i++) {
   1676     CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
   1677   }
   1678 }
   1679 
   1680 
   1681 TEST(GrowAndShrinkNewSpace) {
   1682   CcTest::InitializeVM();
   1683   Heap* heap = CcTest::heap();
   1684   NewSpace* new_space = heap->new_space();
   1685 
   1686   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
   1687       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
   1688     // The max size cannot exceed the reserved size, since semispaces must be
   1689     // always within the reserved space.  We can't test new space growing and
   1690     // shrinking if the reserved size is the same as the minimum (initial) size.
   1691     return;
   1692   }
   1693 
   1694   // Explicitly growing should double the space capacity.
   1695   intptr_t old_capacity, new_capacity;
   1696   old_capacity = new_space->Capacity();
   1697   new_space->Grow();
   1698   new_capacity = new_space->Capacity();
   1699   CHECK(2 * old_capacity == new_capacity);
   1700 
   1701   old_capacity = new_space->Capacity();
   1702   FillUpNewSpace(new_space);
   1703   new_capacity = new_space->Capacity();
   1704   CHECK(old_capacity == new_capacity);
   1705 
   1706   // Explicitly shrinking should not affect space capacity.
   1707   old_capacity = new_space->Capacity();
   1708   new_space->Shrink();
   1709   new_capacity = new_space->Capacity();
   1710   CHECK(old_capacity == new_capacity);
   1711 
   1712   // Let the scavenger empty the new space.
   1713   heap->CollectGarbage(NEW_SPACE);
   1714   CHECK_LE(new_space->Size(), old_capacity);
   1715 
   1716   // Explicitly shrinking should halve the space capacity.
   1717   old_capacity = new_space->Capacity();
   1718   new_space->Shrink();
   1719   new_capacity = new_space->Capacity();
   1720   CHECK(old_capacity == 2 * new_capacity);
   1721 
   1722   // Consecutive shrinking should not affect space capacity.
   1723   old_capacity = new_space->Capacity();
   1724   new_space->Shrink();
   1725   new_space->Shrink();
   1726   new_space->Shrink();
   1727   new_capacity = new_space->Capacity();
   1728   CHECK(old_capacity == new_capacity);
   1729 }
   1730 
   1731 
   1732 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
   1733   CcTest::InitializeVM();
   1734   Heap* heap = CcTest::heap();
   1735   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
   1736       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
   1737     // The max size cannot exceed the reserved size, since semispaces must be
   1738     // always within the reserved space.  We can't test new space growing and
   1739     // shrinking if the reserved size is the same as the minimum (initial) size.
   1740     return;
   1741   }
   1742 
   1743   v8::HandleScope scope(CcTest::isolate());
   1744   NewSpace* new_space = heap->new_space();
   1745   intptr_t old_capacity, new_capacity;
   1746   old_capacity = new_space->Capacity();
   1747   new_space->Grow();
   1748   new_capacity = new_space->Capacity();
   1749   CHECK(2 * old_capacity == new_capacity);
   1750   FillUpNewSpace(new_space);
   1751   heap->CollectAllAvailableGarbage();
   1752   new_capacity = new_space->Capacity();
   1753   CHECK(old_capacity == new_capacity);
   1754 }
   1755 
   1756 
   1757 static int NumberOfGlobalObjects() {
   1758   int count = 0;
   1759   HeapIterator iterator(CcTest::heap());
   1760   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
   1761     if (obj->IsGlobalObject()) count++;
   1762   }
   1763   return count;
   1764 }
   1765 
   1766 
   1767 // Test that we don't embed maps from foreign contexts into
   1768 // optimized code.
   1769 TEST(LeakNativeContextViaMap) {
   1770   i::FLAG_allow_natives_syntax = true;
   1771   v8::Isolate* isolate = CcTest::isolate();
   1772   v8::HandleScope outer_scope(isolate);
   1773   v8::Persistent<v8::Context> ctx1p;
   1774   v8::Persistent<v8::Context> ctx2p;
   1775   {
   1776     v8::HandleScope scope(isolate);
   1777     ctx1p.Reset(isolate, v8::Context::New(isolate));
   1778     ctx2p.Reset(isolate, v8::Context::New(isolate));
   1779     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   1780   }
   1781 
   1782   CcTest::heap()->CollectAllAvailableGarbage();
   1783   CHECK_EQ(4, NumberOfGlobalObjects());
   1784 
   1785   {
   1786     v8::HandleScope inner_scope(isolate);
   1787     CompileRun("var v = {x: 42}");
   1788     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   1789     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   1790     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
   1791     ctx2->Enter();
   1792     ctx2->Global()->Set(v8_str("o"), v);
   1793     v8::Local<v8::Value> res = CompileRun(
   1794         "function f() { return o.x; }"
   1795         "for (var i = 0; i < 10; ++i) f();"
   1796         "%OptimizeFunctionOnNextCall(f);"
   1797         "f();");
   1798     CHECK_EQ(42, res->Int32Value());
   1799     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
   1800     ctx2->Exit();
   1801     v8::Local<v8::Context>::New(isolate, ctx1)->Exit();
   1802     ctx1p.Reset();
   1803     v8::V8::ContextDisposedNotification();
   1804   }
   1805   CcTest::heap()->CollectAllAvailableGarbage();
   1806   CHECK_EQ(2, NumberOfGlobalObjects());
   1807   ctx2p.Reset();
   1808   CcTest::heap()->CollectAllAvailableGarbage();
   1809   CHECK_EQ(0, NumberOfGlobalObjects());
   1810 }
   1811 
   1812 
   1813 // Test that we don't embed functions from foreign contexts into
   1814 // optimized code.
   1815 TEST(LeakNativeContextViaFunction) {
   1816   i::FLAG_allow_natives_syntax = true;
   1817   v8::Isolate* isolate = CcTest::isolate();
   1818   v8::HandleScope outer_scope(isolate);
   1819   v8::Persistent<v8::Context> ctx1p;
   1820   v8::Persistent<v8::Context> ctx2p;
   1821   {
   1822     v8::HandleScope scope(isolate);
   1823     ctx1p.Reset(isolate, v8::Context::New(isolate));
   1824     ctx2p.Reset(isolate, v8::Context::New(isolate));
   1825     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   1826   }
   1827 
   1828   CcTest::heap()->CollectAllAvailableGarbage();
   1829   CHECK_EQ(4, NumberOfGlobalObjects());
   1830 
   1831   {
   1832     v8::HandleScope inner_scope(isolate);
   1833     CompileRun("var v = function() { return 42; }");
   1834     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   1835     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   1836     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
   1837     ctx2->Enter();
   1838     ctx2->Global()->Set(v8_str("o"), v);
   1839     v8::Local<v8::Value> res = CompileRun(
   1840         "function f(x) { return x(); }"
   1841         "for (var i = 0; i < 10; ++i) f(o);"
   1842         "%OptimizeFunctionOnNextCall(f);"
   1843         "f(o);");
   1844     CHECK_EQ(42, res->Int32Value());
   1845     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
   1846     ctx2->Exit();
   1847     ctx1->Exit();
   1848     ctx1p.Reset();
   1849     v8::V8::ContextDisposedNotification();
   1850   }
   1851   CcTest::heap()->CollectAllAvailableGarbage();
   1852   CHECK_EQ(2, NumberOfGlobalObjects());
   1853   ctx2p.Reset();
   1854   CcTest::heap()->CollectAllAvailableGarbage();
   1855   CHECK_EQ(0, NumberOfGlobalObjects());
   1856 }
   1857 
   1858 
   1859 TEST(LeakNativeContextViaMapKeyed) {
   1860   i::FLAG_allow_natives_syntax = true;
   1861   v8::Isolate* isolate = CcTest::isolate();
   1862   v8::HandleScope outer_scope(isolate);
   1863   v8::Persistent<v8::Context> ctx1p;
   1864   v8::Persistent<v8::Context> ctx2p;
   1865   {
   1866     v8::HandleScope scope(isolate);
   1867     ctx1p.Reset(isolate, v8::Context::New(isolate));
   1868     ctx2p.Reset(isolate, v8::Context::New(isolate));
   1869     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   1870   }
   1871 
   1872   CcTest::heap()->CollectAllAvailableGarbage();
   1873   CHECK_EQ(4, NumberOfGlobalObjects());
   1874 
   1875   {
   1876     v8::HandleScope inner_scope(isolate);
   1877     CompileRun("var v = [42, 43]");
   1878     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   1879     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   1880     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
   1881     ctx2->Enter();
   1882     ctx2->Global()->Set(v8_str("o"), v);
   1883     v8::Local<v8::Value> res = CompileRun(
   1884         "function f() { return o[0]; }"
   1885         "for (var i = 0; i < 10; ++i) f();"
   1886         "%OptimizeFunctionOnNextCall(f);"
   1887         "f();");
   1888     CHECK_EQ(42, res->Int32Value());
   1889     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
   1890     ctx2->Exit();
   1891     ctx1->Exit();
   1892     ctx1p.Reset();
   1893     v8::V8::ContextDisposedNotification();
   1894   }
   1895   CcTest::heap()->CollectAllAvailableGarbage();
   1896   CHECK_EQ(2, NumberOfGlobalObjects());
   1897   ctx2p.Reset();
   1898   CcTest::heap()->CollectAllAvailableGarbage();
   1899   CHECK_EQ(0, NumberOfGlobalObjects());
   1900 }
   1901 
   1902 
   1903 TEST(LeakNativeContextViaMapProto) {
   1904   i::FLAG_allow_natives_syntax = true;
   1905   v8::Isolate* isolate = CcTest::isolate();
   1906   v8::HandleScope outer_scope(isolate);
   1907   v8::Persistent<v8::Context> ctx1p;
   1908   v8::Persistent<v8::Context> ctx2p;
   1909   {
   1910     v8::HandleScope scope(isolate);
   1911     ctx1p.Reset(isolate, v8::Context::New(isolate));
   1912     ctx2p.Reset(isolate, v8::Context::New(isolate));
   1913     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   1914   }
   1915 
   1916   CcTest::heap()->CollectAllAvailableGarbage();
   1917   CHECK_EQ(4, NumberOfGlobalObjects());
   1918 
   1919   {
   1920     v8::HandleScope inner_scope(isolate);
   1921     CompileRun("var v = { y: 42}");
   1922     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   1923     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   1924     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
   1925     ctx2->Enter();
   1926     ctx2->Global()->Set(v8_str("o"), v);
   1927     v8::Local<v8::Value> res = CompileRun(
   1928         "function f() {"
   1929         "  var p = {x: 42};"
   1930         "  p.__proto__ = o;"
   1931         "  return p.x;"
   1932         "}"
   1933         "for (var i = 0; i < 10; ++i) f();"
   1934         "%OptimizeFunctionOnNextCall(f);"
   1935         "f();");
   1936     CHECK_EQ(42, res->Int32Value());
   1937     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
   1938     ctx2->Exit();
   1939     ctx1->Exit();
   1940     ctx1p.Reset();
   1941     v8::V8::ContextDisposedNotification();
   1942   }
   1943   CcTest::heap()->CollectAllAvailableGarbage();
   1944   CHECK_EQ(2, NumberOfGlobalObjects());
   1945   ctx2p.Reset();
   1946   CcTest::heap()->CollectAllAvailableGarbage();
   1947   CHECK_EQ(0, NumberOfGlobalObjects());
   1948 }
   1949 
   1950 
   1951 TEST(InstanceOfStubWriteBarrier) {
   1952   i::FLAG_allow_natives_syntax = true;
   1953 #ifdef VERIFY_HEAP
   1954   i::FLAG_verify_heap = true;
   1955 #endif
   1956 
   1957   CcTest::InitializeVM();
   1958   if (!CcTest::i_isolate()->use_crankshaft()) return;
   1959   if (i::FLAG_force_marking_deque_overflows) return;
   1960   v8::HandleScope outer_scope(CcTest::isolate());
   1961 
   1962   {
   1963     v8::HandleScope scope(CcTest::isolate());
   1964     CompileRun(
   1965         "function foo () { }"
   1966         "function mkbar () { return new (new Function(\"\")) (); }"
   1967         "function f (x) { return (x instanceof foo); }"
   1968         "function g () { f(mkbar()); }"
   1969         "f(new foo()); f(new foo());"
   1970         "%OptimizeFunctionOnNextCall(f);"
   1971         "f(new foo()); g();");
   1972   }
   1973 
   1974   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   1975   marking->Abort();
   1976   marking->Start();
   1977 
   1978   Handle<JSFunction> f =
   1979       v8::Utils::OpenHandle(
   1980           *v8::Handle<v8::Function>::Cast(
   1981               CcTest::global()->Get(v8_str("f"))));
   1982 
   1983   CHECK(f->IsOptimized());
   1984 
   1985   while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
   1986          !marking->IsStopped()) {
   1987     // Discard any pending GC requests otherwise we will get GC when we enter
   1988     // code below.
   1989     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   1990   }
   1991 
   1992   CHECK(marking->IsMarking());
   1993 
   1994   {
   1995     v8::HandleScope scope(CcTest::isolate());
   1996     v8::Handle<v8::Object> global = CcTest::global();
   1997     v8::Handle<v8::Function> g =
   1998         v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
   1999     g->Call(global, 0, NULL);
   2000   }
   2001 
   2002   CcTest::heap()->incremental_marking()->set_should_hurry(true);
   2003   CcTest::heap()->CollectGarbage(OLD_POINTER_SPACE);
   2004 }
   2005 
   2006 
   2007 TEST(PrototypeTransitionClearing) {
   2008   if (FLAG_never_compact) return;
   2009   CcTest::InitializeVM();
   2010   Isolate* isolate = CcTest::i_isolate();
   2011   Factory* factory = isolate->factory();
   2012   v8::HandleScope scope(CcTest::isolate());
   2013 
   2014   CompileRun("var base = {};");
   2015   Handle<JSObject> baseObject =
   2016       v8::Utils::OpenHandle(
   2017           *v8::Handle<v8::Object>::Cast(
   2018               CcTest::global()->Get(v8_str("base"))));
   2019   int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
   2020 
   2021   CompileRun(
   2022       "var live = [];"
   2023       "for (var i = 0; i < 10; i++) {"
   2024       "  var object = {};"
   2025       "  var prototype = {};"
   2026       "  object.__proto__ = prototype;"
   2027       "  if (i >= 3) live.push(object, prototype);"
   2028       "}");
   2029 
   2030   // Verify that only dead prototype transitions are cleared.
   2031   CHECK_EQ(initialTransitions + 10,
   2032       baseObject->map()->NumberOfProtoTransitions());
   2033   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   2034   const int transitions = 10 - 3;
   2035   CHECK_EQ(initialTransitions + transitions,
   2036       baseObject->map()->NumberOfProtoTransitions());
   2037 
   2038   // Verify that prototype transitions array was compacted.
   2039   FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
   2040   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
   2041     int j = Map::kProtoTransitionHeaderSize +
   2042         i * Map::kProtoTransitionElementsPerEntry;
   2043     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
   2044     Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
   2045     CHECK(proto->IsJSObject());
   2046   }
   2047 
   2048   // Make sure next prototype is placed on an old-space evacuation candidate.
   2049   Handle<JSObject> prototype;
   2050   PagedSpace* space = CcTest::heap()->old_pointer_space();
   2051   {
   2052     AlwaysAllocateScope always_allocate(isolate);
   2053     SimulateFullSpace(space);
   2054     prototype = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
   2055   }
   2056 
   2057   // Add a prototype on an evacuation candidate and verify that transition
   2058   // clearing correctly records slots in prototype transition array.
   2059   i::FLAG_always_compact = true;
   2060   Handle<Map> map(baseObject->map());
   2061   CHECK(!space->LastPage()->Contains(
   2062       map->GetPrototypeTransitions()->address()));
   2063   CHECK(space->LastPage()->Contains(prototype->address()));
   2064 }
   2065 
   2066 
   2067 TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
   2068   i::FLAG_stress_compaction = false;
   2069   i::FLAG_allow_natives_syntax = true;
   2070 #ifdef VERIFY_HEAP
   2071   i::FLAG_verify_heap = true;
   2072 #endif
   2073 
   2074   CcTest::InitializeVM();
   2075   if (!CcTest::i_isolate()->use_crankshaft()) return;
   2076   v8::HandleScope outer_scope(CcTest::isolate());
   2077 
   2078   {
   2079     v8::HandleScope scope(CcTest::isolate());
   2080     CompileRun(
   2081         "function f () {"
   2082         "  var s = 0;"
   2083         "  for (var i = 0; i < 100; i++)  s += i;"
   2084         "  return s;"
   2085         "}"
   2086         "f(); f();"
   2087         "%OptimizeFunctionOnNextCall(f);"
   2088         "f();");
   2089   }
   2090   Handle<JSFunction> f =
   2091       v8::Utils::OpenHandle(
   2092           *v8::Handle<v8::Function>::Cast(
   2093               CcTest::global()->Get(v8_str("f"))));
   2094   CHECK(f->IsOptimized());
   2095 
   2096   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   2097   marking->Abort();
   2098   marking->Start();
   2099 
   2100   // The following two calls will increment CcTest::heap()->global_ic_age().
   2101   const int kLongIdlePauseInMs = 1000;
   2102   v8::V8::ContextDisposedNotification();
   2103   v8::V8::IdleNotification(kLongIdlePauseInMs);
   2104 
   2105   while (!marking->IsStopped() && !marking->IsComplete()) {
   2106     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   2107   }
   2108   if (!marking->IsStopped() || marking->should_hurry()) {
   2109     // We don't normally finish a GC via Step(), we normally finish by
   2110     // setting the stack guard and then do the final steps in the stack
   2111     // guard interrupt.  But here we didn't ask for that, and there is no
   2112     // JS code running to trigger the interrupt, so we explicitly finalize
   2113     // here.
   2114     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags,
   2115                             "Test finalizing incremental mark-sweep");
   2116   }
   2117 
   2118   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
   2119   CHECK_EQ(0, f->shared()->opt_count());
   2120   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
   2121 }
   2122 
   2123 
   2124 TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
   2125   i::FLAG_stress_compaction = false;
   2126   i::FLAG_allow_natives_syntax = true;
   2127 #ifdef VERIFY_HEAP
   2128   i::FLAG_verify_heap = true;
   2129 #endif
   2130 
   2131   CcTest::InitializeVM();
   2132   if (!CcTest::i_isolate()->use_crankshaft()) return;
   2133   v8::HandleScope outer_scope(CcTest::isolate());
   2134 
   2135   {
   2136     v8::HandleScope scope(CcTest::isolate());
   2137     CompileRun(
   2138         "function f () {"
   2139         "  var s = 0;"
   2140         "  for (var i = 0; i < 100; i++)  s += i;"
   2141         "  return s;"
   2142         "}"
   2143         "f(); f();"
   2144         "%OptimizeFunctionOnNextCall(f);"
   2145         "f();");
   2146   }
   2147   Handle<JSFunction> f =
   2148       v8::Utils::OpenHandle(
   2149           *v8::Handle<v8::Function>::Cast(
   2150               CcTest::global()->Get(v8_str("f"))));
   2151   CHECK(f->IsOptimized());
   2152 
   2153   CcTest::heap()->incremental_marking()->Abort();
   2154 
   2155   // The following two calls will increment CcTest::heap()->global_ic_age().
   2156   // Since incremental marking is off, IdleNotification will do full GC.
   2157   const int kLongIdlePauseInMs = 1000;
   2158   v8::V8::ContextDisposedNotification();
   2159   v8::V8::IdleNotification(kLongIdlePauseInMs);
   2160 
   2161   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
   2162   CHECK_EQ(0, f->shared()->opt_count());
   2163   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
   2164 }
   2165 
   2166 
   2167 // Test that HAllocateObject will always return an object in new-space.
   2168 TEST(OptimizedAllocationAlwaysInNewSpace) {
   2169   i::FLAG_allow_natives_syntax = true;
   2170   CcTest::InitializeVM();
   2171   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2172   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2173   v8::HandleScope scope(CcTest::isolate());
   2174 
   2175   SimulateFullSpace(CcTest::heap()->new_space());
   2176   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   2177   v8::Local<v8::Value> res = CompileRun(
   2178       "function c(x) {"
   2179       "  this.x = x;"
   2180       "  for (var i = 0; i < 32; i++) {"
   2181       "    this['x' + i] = x;"
   2182       "  }"
   2183       "}"
   2184       "function f(x) { return new c(x); };"
   2185       "f(1); f(2); f(3);"
   2186       "%OptimizeFunctionOnNextCall(f);"
   2187       "f(4);");
   2188   CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
   2189 
   2190   Handle<JSObject> o =
   2191       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2192 
   2193   CHECK(CcTest::heap()->InNewSpace(*o));
   2194 }
   2195 
   2196 
   2197 TEST(OptimizedPretenuringAllocationFolding) {
   2198   i::FLAG_allow_natives_syntax = true;
   2199   i::FLAG_expose_gc = true;
   2200   CcTest::InitializeVM();
   2201   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2202   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2203   v8::HandleScope scope(CcTest::isolate());
   2204 
   2205   // Grow new space unitl maximum capacity reached.
   2206   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2207     CcTest::heap()->new_space()->Grow();
   2208   }
   2209 
   2210   i::ScopedVector<char> source(1024);
   2211   i::SNPrintF(
   2212       source,
   2213       "var number_elements = %d;"
   2214       "var elements = new Array();"
   2215       "function f() {"
   2216       "  for (var i = 0; i < number_elements; i++) {"
   2217       "    elements[i] = [[{}], [1.1]];"
   2218       "  }"
   2219       "  return elements[number_elements-1]"
   2220       "};"
   2221       "f(); gc();"
   2222       "f(); f();"
   2223       "%%OptimizeFunctionOnNextCall(f);"
   2224       "f();",
   2225       AllocationSite::kPretenureMinimumCreated);
   2226 
   2227   v8::Local<v8::Value> res = CompileRun(source.start());
   2228 
   2229   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
   2230   Handle<JSObject> int_array_handle =
   2231       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
   2232   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
   2233   Handle<JSObject> double_array_handle =
   2234       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
   2235 
   2236   Handle<JSObject> o =
   2237       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2238   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2239   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
   2240   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
   2241   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
   2242   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
   2243 }
   2244 
   2245 
   2246 TEST(OptimizedPretenuringObjectArrayLiterals) {
   2247   i::FLAG_allow_natives_syntax = true;
   2248   i::FLAG_expose_gc = true;
   2249   CcTest::InitializeVM();
   2250   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2251   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2252   v8::HandleScope scope(CcTest::isolate());
   2253 
   2254   // Grow new space unitl maximum capacity reached.
   2255   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2256     CcTest::heap()->new_space()->Grow();
   2257   }
   2258 
   2259   i::ScopedVector<char> source(1024);
   2260   i::SNPrintF(
   2261       source,
   2262       "var number_elements = %d;"
   2263       "var elements = new Array(number_elements);"
   2264       "function f() {"
   2265       "  for (var i = 0; i < number_elements; i++) {"
   2266       "    elements[i] = [{}, {}, {}];"
   2267       "  }"
   2268       "  return elements[number_elements - 1];"
   2269       "};"
   2270       "f(); gc();"
   2271       "f(); f();"
   2272       "%%OptimizeFunctionOnNextCall(f);"
   2273       "f();",
   2274       AllocationSite::kPretenureMinimumCreated);
   2275 
   2276   v8::Local<v8::Value> res = CompileRun(source.start());
   2277 
   2278   Handle<JSObject> o =
   2279       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2280 
   2281   CHECK(CcTest::heap()->InOldPointerSpace(o->elements()));
   2282   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2283 }
   2284 
   2285 
   2286 TEST(OptimizedPretenuringMixedInObjectProperties) {
   2287   i::FLAG_allow_natives_syntax = true;
   2288   i::FLAG_expose_gc = true;
   2289   CcTest::InitializeVM();
   2290   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2291   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2292   v8::HandleScope scope(CcTest::isolate());
   2293 
   2294   // Grow new space unitl maximum capacity reached.
   2295   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2296     CcTest::heap()->new_space()->Grow();
   2297   }
   2298 
   2299 
   2300   i::ScopedVector<char> source(1024);
   2301   i::SNPrintF(
   2302       source,
   2303       "var number_elements = %d;"
   2304       "var elements = new Array(number_elements);"
   2305       "function f() {"
   2306       "  for (var i = 0; i < number_elements; i++) {"
   2307       "    elements[i] = {a: {c: 2.2, d: {}}, b: 1.1};"
   2308       "  }"
   2309       "  return elements[number_elements - 1];"
   2310       "};"
   2311       "f(); gc();"
   2312       "f(); f();"
   2313       "%%OptimizeFunctionOnNextCall(f);"
   2314       "f();",
   2315       AllocationSite::kPretenureMinimumCreated);
   2316 
   2317   v8::Local<v8::Value> res = CompileRun(source.start());
   2318 
   2319   Handle<JSObject> o =
   2320       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2321 
   2322   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2323   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
   2324   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
   2325   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
   2326   CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
   2327 
   2328   JSObject* inner_object =
   2329       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   2330   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
   2331   CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
   2332   CHECK(CcTest::heap()->InOldPointerSpace(
   2333       inner_object->RawFastPropertyAt(idx2)));
   2334 }
   2335 
   2336 
   2337 TEST(OptimizedPretenuringDoubleArrayProperties) {
   2338   i::FLAG_allow_natives_syntax = true;
   2339   i::FLAG_expose_gc = true;
   2340   CcTest::InitializeVM();
   2341   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2342   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2343   v8::HandleScope scope(CcTest::isolate());
   2344 
   2345   // Grow new space unitl maximum capacity reached.
   2346   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2347     CcTest::heap()->new_space()->Grow();
   2348   }
   2349 
   2350   i::ScopedVector<char> source(1024);
   2351   i::SNPrintF(
   2352       source,
   2353       "var number_elements = %d;"
   2354       "var elements = new Array(number_elements);"
   2355       "function f() {"
   2356       "  for (var i = 0; i < number_elements; i++) {"
   2357       "    elements[i] = {a: 1.1, b: 2.2};"
   2358       "  }"
   2359       "  return elements[i - 1];"
   2360       "};"
   2361       "f(); gc();"
   2362       "f(); f();"
   2363       "%%OptimizeFunctionOnNextCall(f);"
   2364       "f();",
   2365       AllocationSite::kPretenureMinimumCreated);
   2366 
   2367   v8::Local<v8::Value> res = CompileRun(source.start());
   2368 
   2369   Handle<JSObject> o =
   2370       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2371 
   2372   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2373   CHECK(CcTest::heap()->InOldDataSpace(o->properties()));
   2374 }
   2375 
   2376 
   2377 TEST(OptimizedPretenuringdoubleArrayLiterals) {
   2378   i::FLAG_allow_natives_syntax = true;
   2379   i::FLAG_expose_gc = true;
   2380   CcTest::InitializeVM();
   2381   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2382   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2383   v8::HandleScope scope(CcTest::isolate());
   2384 
   2385   // Grow new space unitl maximum capacity reached.
   2386   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2387     CcTest::heap()->new_space()->Grow();
   2388   }
   2389 
   2390   i::ScopedVector<char> source(1024);
   2391   i::SNPrintF(
   2392       source,
   2393       "var number_elements = %d;"
   2394       "var elements = new Array(number_elements);"
   2395       "function f() {"
   2396       "  for (var i = 0; i < number_elements; i++) {"
   2397       "    elements[i] = [1.1, 2.2, 3.3];"
   2398       "  }"
   2399       "  return elements[number_elements - 1];"
   2400       "};"
   2401       "f(); gc();"
   2402       "f(); f();"
   2403       "%%OptimizeFunctionOnNextCall(f);"
   2404       "f();",
   2405       AllocationSite::kPretenureMinimumCreated);
   2406 
   2407   v8::Local<v8::Value> res = CompileRun(source.start());
   2408 
   2409   Handle<JSObject> o =
   2410       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2411 
   2412   CHECK(CcTest::heap()->InOldDataSpace(o->elements()));
   2413   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2414 }
   2415 
   2416 
   2417 TEST(OptimizedPretenuringNestedMixedArrayLiterals) {
   2418   i::FLAG_allow_natives_syntax = true;
   2419   i::FLAG_expose_gc = true;
   2420   CcTest::InitializeVM();
   2421   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2422   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2423   v8::HandleScope scope(CcTest::isolate());
   2424 
   2425   // Grow new space unitl maximum capacity reached.
   2426   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2427     CcTest::heap()->new_space()->Grow();
   2428   }
   2429 
   2430   i::ScopedVector<char> source(1024);
   2431   i::SNPrintF(
   2432       source,
   2433       "var number_elements = 100;"
   2434       "var elements = new Array(number_elements);"
   2435       "function f() {"
   2436       "  for (var i = 0; i < number_elements; i++) {"
   2437       "    elements[i] = [[{}, {}, {}], [1.1, 2.2, 3.3]];"
   2438       "  }"
   2439       "  return elements[number_elements - 1];"
   2440       "};"
   2441       "f(); gc();"
   2442       "f(); f();"
   2443       "%%OptimizeFunctionOnNextCall(f);"
   2444       "f();");
   2445 
   2446   v8::Local<v8::Value> res = CompileRun(source.start());
   2447 
   2448   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
   2449   Handle<JSObject> int_array_handle =
   2450       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
   2451   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
   2452   Handle<JSObject> double_array_handle =
   2453       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
   2454 
   2455   Handle<JSObject> o =
   2456       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2457   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2458   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
   2459   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
   2460   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
   2461   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
   2462 }
   2463 
   2464 
   2465 TEST(OptimizedPretenuringNestedObjectLiterals) {
   2466   i::FLAG_allow_natives_syntax = true;
   2467   i::FLAG_expose_gc = true;
   2468   CcTest::InitializeVM();
   2469   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2470   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2471   v8::HandleScope scope(CcTest::isolate());
   2472 
   2473   // Grow new space unitl maximum capacity reached.
   2474   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2475     CcTest::heap()->new_space()->Grow();
   2476   }
   2477 
   2478   i::ScopedVector<char> source(1024);
   2479   i::SNPrintF(
   2480       source,
   2481       "var number_elements = %d;"
   2482       "var elements = new Array(number_elements);"
   2483       "function f() {"
   2484       "  for (var i = 0; i < number_elements; i++) {"
   2485       "    elements[i] = [[{}, {}, {}],[{}, {}, {}]];"
   2486       "  }"
   2487       "  return elements[number_elements - 1];"
   2488       "};"
   2489       "f(); gc();"
   2490       "f(); f();"
   2491       "%%OptimizeFunctionOnNextCall(f);"
   2492       "f();",
   2493       AllocationSite::kPretenureMinimumCreated);
   2494 
   2495   v8::Local<v8::Value> res = CompileRun(source.start());
   2496 
   2497   v8::Local<v8::Value> int_array_1 = v8::Object::Cast(*res)->Get(v8_str("0"));
   2498   Handle<JSObject> int_array_handle_1 =
   2499       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_1));
   2500   v8::Local<v8::Value> int_array_2 = v8::Object::Cast(*res)->Get(v8_str("1"));
   2501   Handle<JSObject> int_array_handle_2 =
   2502       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_2));
   2503 
   2504   Handle<JSObject> o =
   2505       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2506   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2507   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_1));
   2508   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_1->elements()));
   2509   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_2));
   2510   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_2->elements()));
   2511 }
   2512 
   2513 
   2514 TEST(OptimizedPretenuringNestedDoubleLiterals) {
   2515   i::FLAG_allow_natives_syntax = true;
   2516   i::FLAG_expose_gc = true;
   2517   CcTest::InitializeVM();
   2518   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2519   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2520   v8::HandleScope scope(CcTest::isolate());
   2521 
   2522   // Grow new space unitl maximum capacity reached.
   2523   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2524     CcTest::heap()->new_space()->Grow();
   2525   }
   2526 
   2527   i::ScopedVector<char> source(1024);
   2528   i::SNPrintF(
   2529       source,
   2530       "var number_elements = %d;"
   2531       "var elements = new Array(number_elements);"
   2532       "function f() {"
   2533       "  for (var i = 0; i < number_elements; i++) {"
   2534       "    elements[i] = [[1.1, 1.2, 1.3],[2.1, 2.2, 2.3]];"
   2535       "  }"
   2536       "  return elements[number_elements - 1];"
   2537       "};"
   2538       "f(); gc();"
   2539       "f(); f();"
   2540       "%%OptimizeFunctionOnNextCall(f);"
   2541       "f();",
   2542       AllocationSite::kPretenureMinimumCreated);
   2543 
   2544   v8::Local<v8::Value> res = CompileRun(source.start());
   2545 
   2546   v8::Local<v8::Value> double_array_1 =
   2547       v8::Object::Cast(*res)->Get(v8_str("0"));
   2548   Handle<JSObject> double_array_handle_1 =
   2549       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_1));
   2550   v8::Local<v8::Value> double_array_2 =
   2551       v8::Object::Cast(*res)->Get(v8_str("1"));
   2552   Handle<JSObject> double_array_handle_2 =
   2553       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_2));
   2554 
   2555   Handle<JSObject> o =
   2556       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2557   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2558   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_1));
   2559   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_1->elements()));
   2560   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_2));
   2561   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_2->elements()));
   2562 }
   2563 
   2564 
   2565 // Make sure pretenuring feedback is gathered for constructed objects as well
   2566 // as for literals.
   2567 TEST(OptimizedPretenuringConstructorCalls) {
   2568   if (!i::FLAG_pretenuring_call_new) {
   2569     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
   2570     return;
   2571   }
   2572   i::FLAG_allow_natives_syntax = true;
   2573   i::FLAG_expose_gc = true;
   2574   CcTest::InitializeVM();
   2575   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2576   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2577   v8::HandleScope scope(CcTest::isolate());
   2578 
   2579   // Grow new space unitl maximum capacity reached.
   2580   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2581     CcTest::heap()->new_space()->Grow();
   2582   }
   2583 
   2584   i::ScopedVector<char> source(1024);
   2585   // Call new is doing slack tracking for the first
   2586   // JSFunction::kGenerousAllocationCount allocations, and we can't find
   2587   // mementos during that time.
   2588   i::SNPrintF(
   2589       source,
   2590       "var number_elements = %d;"
   2591       "var elements = new Array(number_elements);"
   2592       "function foo() {"
   2593       "  this.a = 3;"
   2594       "  this.b = {};"
   2595       "}"
   2596       "function f() {"
   2597       "  for (var i = 0; i < number_elements; i++) {"
   2598       "    elements[i] = new foo();"
   2599       "  }"
   2600       "  return elements[number_elements - 1];"
   2601       "};"
   2602       "f(); gc();"
   2603       "f(); f();"
   2604       "%%OptimizeFunctionOnNextCall(f);"
   2605       "f();",
   2606       AllocationSite::kPretenureMinimumCreated +
   2607       JSFunction::kGenerousAllocationCount);
   2608 
   2609   v8::Local<v8::Value> res = CompileRun(source.start());
   2610 
   2611   Handle<JSObject> o =
   2612       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2613 
   2614   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2615 }
   2616 
   2617 
   2618 TEST(OptimizedPretenuringCallNew) {
   2619   if (!i::FLAG_pretenuring_call_new) {
   2620     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
   2621     return;
   2622   }
   2623   i::FLAG_allow_natives_syntax = true;
   2624   i::FLAG_expose_gc = true;
   2625   CcTest::InitializeVM();
   2626   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2627   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2628   v8::HandleScope scope(CcTest::isolate());
   2629 
   2630   // Grow new space unitl maximum capacity reached.
   2631   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2632     CcTest::heap()->new_space()->Grow();
   2633   }
   2634 
   2635   i::ScopedVector<char> source(1024);
   2636   // Call new is doing slack tracking for the first
   2637   // JSFunction::kGenerousAllocationCount allocations, and we can't find
   2638   // mementos during that time.
   2639   i::SNPrintF(
   2640       source,
   2641       "var number_elements = %d;"
   2642       "var elements = new Array(number_elements);"
   2643       "function g() { this.a = 0; }"
   2644       "function f() {"
   2645       "  for (var i = 0; i < number_elements; i++) {"
   2646       "    elements[i] = new g();"
   2647       "  }"
   2648       "  return elements[number_elements - 1];"
   2649       "};"
   2650       "f(); gc();"
   2651       "f(); f();"
   2652       "%%OptimizeFunctionOnNextCall(f);"
   2653       "f();",
   2654       AllocationSite::kPretenureMinimumCreated +
   2655       JSFunction::kGenerousAllocationCount);
   2656 
   2657   v8::Local<v8::Value> res = CompileRun(source.start());
   2658 
   2659   Handle<JSObject> o =
   2660       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2661   CHECK(CcTest::heap()->InOldPointerSpace(*o));
   2662 }
   2663 
   2664 
   2665 // Test regular array literals allocation.
   2666 TEST(OptimizedAllocationArrayLiterals) {
   2667   i::FLAG_allow_natives_syntax = true;
   2668   CcTest::InitializeVM();
   2669   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2670   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2671   v8::HandleScope scope(CcTest::isolate());
   2672 
   2673   v8::Local<v8::Value> res = CompileRun(
   2674       "function f() {"
   2675       "  var numbers = new Array(1, 2, 3);"
   2676       "  numbers[0] = 3.14;"
   2677       "  return numbers;"
   2678       "};"
   2679       "f(); f(); f();"
   2680       "%OptimizeFunctionOnNextCall(f);"
   2681       "f();");
   2682   CHECK_EQ(static_cast<int>(3.14),
   2683            v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
   2684 
   2685   Handle<JSObject> o =
   2686       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
   2687 
   2688   CHECK(CcTest::heap()->InNewSpace(o->elements()));
   2689 }
   2690 
   2691 
   2692 static int CountMapTransitions(Map* map) {
   2693   return map->transitions()->number_of_transitions();
   2694 }
   2695 
   2696 
   2697 // Test that map transitions are cleared and maps are collected with
   2698 // incremental marking as well.
   2699 TEST(Regress1465) {
   2700   i::FLAG_stress_compaction = false;
   2701   i::FLAG_allow_natives_syntax = true;
   2702   i::FLAG_trace_incremental_marking = true;
   2703   CcTest::InitializeVM();
   2704   v8::HandleScope scope(CcTest::isolate());
   2705   static const int transitions_count = 256;
   2706 
   2707   CompileRun("function F() {}");
   2708   {
   2709     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   2710     for (int i = 0; i < transitions_count; i++) {
   2711       EmbeddedVector<char, 64> buffer;
   2712       SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
   2713       CompileRun(buffer.start());
   2714     }
   2715     CompileRun("var root = new F;");
   2716   }
   2717 
   2718   Handle<JSObject> root =
   2719       v8::Utils::OpenHandle(
   2720           *v8::Handle<v8::Object>::Cast(
   2721               CcTest::global()->Get(v8_str("root"))));
   2722 
   2723   // Count number of live transitions before marking.
   2724   int transitions_before = CountMapTransitions(root->map());
   2725   CompileRun("%DebugPrint(root);");
   2726   CHECK_EQ(transitions_count, transitions_before);
   2727 
   2728   SimulateIncrementalMarking();
   2729   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   2730 
   2731   // Count number of live transitions after marking.  Note that one transition
   2732   // is left, because 'o' still holds an instance of one transition target.
   2733   int transitions_after = CountMapTransitions(root->map());
   2734   CompileRun("%DebugPrint(root);");
   2735   CHECK_EQ(1, transitions_after);
   2736 }
   2737 
   2738 
   2739 #ifdef DEBUG
   2740 static void AddTransitions(int transitions_count) {
   2741   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   2742   for (int i = 0; i < transitions_count; i++) {
   2743     EmbeddedVector<char, 64> buffer;
   2744     SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
   2745     CompileRun(buffer.start());
   2746   }
   2747 }
   2748 
   2749 
   2750 static Handle<JSObject> GetByName(const char* name) {
   2751   return v8::Utils::OpenHandle(
   2752       *v8::Handle<v8::Object>::Cast(
   2753           CcTest::global()->Get(v8_str(name))));
   2754 }
   2755 
   2756 
   2757 static void AddPropertyTo(
   2758     int gc_count, Handle<JSObject> object, const char* property_name) {
   2759   Isolate* isolate = CcTest::i_isolate();
   2760   Factory* factory = isolate->factory();
   2761   Handle<String> prop_name = factory->InternalizeUtf8String(property_name);
   2762   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
   2763   i::FLAG_gc_interval = gc_count;
   2764   i::FLAG_gc_global = true;
   2765   CcTest::heap()->set_allocation_timeout(gc_count);
   2766   JSReceiver::SetProperty(
   2767       object, prop_name, twenty_three, NONE, SLOPPY).Check();
   2768 }
   2769 
   2770 
   2771 TEST(TransitionArrayShrinksDuringAllocToZero) {
   2772   i::FLAG_stress_compaction = false;
   2773   i::FLAG_allow_natives_syntax = true;
   2774   CcTest::InitializeVM();
   2775   v8::HandleScope scope(CcTest::isolate());
   2776   static const int transitions_count = 10;
   2777   CompileRun("function F() { }");
   2778   AddTransitions(transitions_count);
   2779   CompileRun("var root = new F;");
   2780   Handle<JSObject> root = GetByName("root");
   2781 
   2782   // Count number of live transitions before marking.
   2783   int transitions_before = CountMapTransitions(root->map());
   2784   CHECK_EQ(transitions_count, transitions_before);
   2785 
   2786   // Get rid of o
   2787   CompileRun("o = new F;"
   2788              "root = new F");
   2789   root = GetByName("root");
   2790   AddPropertyTo(2, root, "funny");
   2791 
   2792   // Count number of live transitions after marking.  Note that one transition
   2793   // is left, because 'o' still holds an instance of one transition target.
   2794   int transitions_after = CountMapTransitions(
   2795       Map::cast(root->map()->GetBackPointer()));
   2796   CHECK_EQ(1, transitions_after);
   2797 }
   2798 
   2799 
   2800 TEST(TransitionArrayShrinksDuringAllocToOne) {
   2801   i::FLAG_stress_compaction = false;
   2802   i::FLAG_allow_natives_syntax = true;
   2803   CcTest::InitializeVM();
   2804   v8::HandleScope scope(CcTest::isolate());
   2805   static const int transitions_count = 10;
   2806   CompileRun("function F() {}");
   2807   AddTransitions(transitions_count);
   2808   CompileRun("var root = new F;");
   2809   Handle<JSObject> root = GetByName("root");
   2810 
   2811   // Count number of live transitions before marking.
   2812   int transitions_before = CountMapTransitions(root->map());
   2813   CHECK_EQ(transitions_count, transitions_before);
   2814 
   2815   root = GetByName("root");
   2816   AddPropertyTo(2, root, "funny");
   2817 
   2818   // Count number of live transitions after marking.  Note that one transition
   2819   // is left, because 'o' still holds an instance of one transition target.
   2820   int transitions_after = CountMapTransitions(
   2821       Map::cast(root->map()->GetBackPointer()));
   2822   CHECK_EQ(2, transitions_after);
   2823 }
   2824 
   2825 
   2826 TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
   2827   i::FLAG_stress_compaction = false;
   2828   i::FLAG_allow_natives_syntax = true;
   2829   CcTest::InitializeVM();
   2830   v8::HandleScope scope(CcTest::isolate());
   2831   static const int transitions_count = 10;
   2832   CompileRun("function F() {}");
   2833   AddTransitions(transitions_count);
   2834   CompileRun("var root = new F;");
   2835   Handle<JSObject> root = GetByName("root");
   2836 
   2837   // Count number of live transitions before marking.
   2838   int transitions_before = CountMapTransitions(root->map());
   2839   CHECK_EQ(transitions_count, transitions_before);
   2840 
   2841   root = GetByName("root");
   2842   AddPropertyTo(0, root, "prop9");
   2843 
   2844   // Count number of live transitions after marking.  Note that one transition
   2845   // is left, because 'o' still holds an instance of one transition target.
   2846   int transitions_after = CountMapTransitions(
   2847       Map::cast(root->map()->GetBackPointer()));
   2848   CHECK_EQ(1, transitions_after);
   2849 }
   2850 
   2851 
   2852 TEST(TransitionArraySimpleToFull) {
   2853   i::FLAG_stress_compaction = false;
   2854   i::FLAG_allow_natives_syntax = true;
   2855   CcTest::InitializeVM();
   2856   v8::HandleScope scope(CcTest::isolate());
   2857   static const int transitions_count = 1;
   2858   CompileRun("function F() {}");
   2859   AddTransitions(transitions_count);
   2860   CompileRun("var root = new F;");
   2861   Handle<JSObject> root = GetByName("root");
   2862 
   2863   // Count number of live transitions before marking.
   2864   int transitions_before = CountMapTransitions(root->map());
   2865   CHECK_EQ(transitions_count, transitions_before);
   2866 
   2867   CompileRun("o = new F;"
   2868              "root = new F");
   2869   root = GetByName("root");
   2870   ASSERT(root->map()->transitions()->IsSimpleTransition());
   2871   AddPropertyTo(2, root, "happy");
   2872 
   2873   // Count number of live transitions after marking.  Note that one transition
   2874   // is left, because 'o' still holds an instance of one transition target.
   2875   int transitions_after = CountMapTransitions(
   2876       Map::cast(root->map()->GetBackPointer()));
   2877   CHECK_EQ(1, transitions_after);
   2878 }
   2879 #endif  // DEBUG
   2880 
   2881 
   2882 TEST(Regress2143a) {
   2883   i::FLAG_collect_maps = true;
   2884   i::FLAG_incremental_marking = true;
   2885   CcTest::InitializeVM();
   2886   v8::HandleScope scope(CcTest::isolate());
   2887 
   2888   // Prepare a map transition from the root object together with a yet
   2889   // untransitioned root object.
   2890   CompileRun("var root = new Object;"
   2891              "root.foo = 0;"
   2892              "root = new Object;");
   2893 
   2894   SimulateIncrementalMarking();
   2895 
   2896   // Compile a StoreIC that performs the prepared map transition. This
   2897   // will restart incremental marking and should make sure the root is
   2898   // marked grey again.
   2899   CompileRun("function f(o) {"
   2900              "  o.foo = 0;"
   2901              "}"
   2902              "f(new Object);"
   2903              "f(root);");
   2904 
   2905   // This bug only triggers with aggressive IC clearing.
   2906   CcTest::heap()->AgeInlineCaches();
   2907 
   2908   // Explicitly request GC to perform final marking step and sweeping.
   2909   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   2910 
   2911   Handle<JSObject> root =
   2912       v8::Utils::OpenHandle(
   2913           *v8::Handle<v8::Object>::Cast(
   2914               CcTest::global()->Get(v8_str("root"))));
   2915 
   2916   // The root object should be in a sane state.
   2917   CHECK(root->IsJSObject());
   2918   CHECK(root->map()->IsMap());
   2919 }
   2920 
   2921 
   2922 TEST(Regress2143b) {
   2923   i::FLAG_collect_maps = true;
   2924   i::FLAG_incremental_marking = true;
   2925   i::FLAG_allow_natives_syntax = true;
   2926   CcTest::InitializeVM();
   2927   v8::HandleScope scope(CcTest::isolate());
   2928 
   2929   // Prepare a map transition from the root object together with a yet
   2930   // untransitioned root object.
   2931   CompileRun("var root = new Object;"
   2932              "root.foo = 0;"
   2933              "root = new Object;");
   2934 
   2935   SimulateIncrementalMarking();
   2936 
   2937   // Compile an optimized LStoreNamedField that performs the prepared
   2938   // map transition. This will restart incremental marking and should
   2939   // make sure the root is marked grey again.
   2940   CompileRun("function f(o) {"
   2941              "  o.foo = 0;"
   2942              "}"
   2943              "f(new Object);"
   2944              "f(new Object);"
   2945              "%OptimizeFunctionOnNextCall(f);"
   2946              "f(root);"
   2947              "%DeoptimizeFunction(f);");
   2948 
   2949   // This bug only triggers with aggressive IC clearing.
   2950   CcTest::heap()->AgeInlineCaches();
   2951 
   2952   // Explicitly request GC to perform final marking step and sweeping.
   2953   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   2954 
   2955   Handle<JSObject> root =
   2956       v8::Utils::OpenHandle(
   2957           *v8::Handle<v8::Object>::Cast(
   2958               CcTest::global()->Get(v8_str("root"))));
   2959 
   2960   // The root object should be in a sane state.
   2961   CHECK(root->IsJSObject());
   2962   CHECK(root->map()->IsMap());
   2963 }
   2964 
   2965 
   2966 TEST(ReleaseOverReservedPages) {
   2967   if (FLAG_never_compact) return;
   2968   i::FLAG_trace_gc = true;
   2969   // The optimizer can allocate stuff, messing up the test.
   2970   i::FLAG_crankshaft = false;
   2971   i::FLAG_always_opt = false;
   2972   CcTest::InitializeVM();
   2973   Isolate* isolate = CcTest::i_isolate();
   2974   Factory* factory = isolate->factory();
   2975   Heap* heap = isolate->heap();
   2976   v8::HandleScope scope(CcTest::isolate());
   2977   static const int number_of_test_pages = 20;
   2978 
   2979   // Prepare many pages with low live-bytes count.
   2980   PagedSpace* old_pointer_space = heap->old_pointer_space();
   2981   CHECK_EQ(1, old_pointer_space->CountTotalPages());
   2982   for (int i = 0; i < number_of_test_pages; i++) {
   2983     AlwaysAllocateScope always_allocate(isolate);
   2984     SimulateFullSpace(old_pointer_space);
   2985     factory->NewFixedArray(1, TENURED);
   2986   }
   2987   CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
   2988 
   2989   // Triggering one GC will cause a lot of garbage to be discovered but
   2990   // even spread across all allocated pages.
   2991   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
   2992   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
   2993 
   2994   // Triggering subsequent GCs should cause at least half of the pages
   2995   // to be released to the OS after at most two cycles.
   2996   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
   2997   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
   2998   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
   2999   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
   3000 
   3001   // Triggering a last-resort GC should cause all pages to be released to the
   3002   // OS so that other processes can seize the memory.  If we get a failure here
   3003   // where there are 2 pages left instead of 1, then we should increase the
   3004   // size of the first page a little in SizeOfFirstPage in spaces.cc.  The
   3005   // first page should be small in order to reduce memory used when the VM
   3006   // boots, but if the 20 small arrays don't fit on the first page then that's
   3007   // an indication that it is too small.
   3008   heap->CollectAllAvailableGarbage("triggered really hard");
   3009   CHECK_EQ(1, old_pointer_space->CountTotalPages());
   3010 }
   3011 
   3012 
   3013 TEST(Regress2237) {
   3014   i::FLAG_stress_compaction = false;
   3015   CcTest::InitializeVM();
   3016   Isolate* isolate = CcTest::i_isolate();
   3017   Factory* factory = isolate->factory();
   3018   v8::HandleScope scope(CcTest::isolate());
   3019   Handle<String> slice(CcTest::heap()->empty_string());
   3020 
   3021   {
   3022     // Generate a parent that lives in new-space.
   3023     v8::HandleScope inner_scope(CcTest::isolate());
   3024     const char* c = "This text is long enough to trigger sliced strings.";
   3025     Handle<String> s = factory->NewStringFromAsciiChecked(c);
   3026     CHECK(s->IsSeqOneByteString());
   3027     CHECK(CcTest::heap()->InNewSpace(*s));
   3028 
   3029     // Generate a sliced string that is based on the above parent and
   3030     // lives in old-space.
   3031     SimulateFullSpace(CcTest::heap()->new_space());
   3032     AlwaysAllocateScope always_allocate(isolate);
   3033     Handle<String> t = factory->NewProperSubString(s, 5, 35);
   3034     CHECK(t->IsSlicedString());
   3035     CHECK(!CcTest::heap()->InNewSpace(*t));
   3036     *slice.location() = *t.location();
   3037   }
   3038 
   3039   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
   3040   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   3041   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
   3042 }
   3043 
   3044 
   3045 #ifdef OBJECT_PRINT
   3046 TEST(PrintSharedFunctionInfo) {
   3047   CcTest::InitializeVM();
   3048   v8::HandleScope scope(CcTest::isolate());
   3049   const char* source = "f = function() { return 987654321; }\n"
   3050                        "g = function() { return 123456789; }\n";
   3051   CompileRun(source);
   3052   Handle<JSFunction> g =
   3053       v8::Utils::OpenHandle(
   3054           *v8::Handle<v8::Function>::Cast(
   3055               CcTest::global()->Get(v8_str("g"))));
   3056 
   3057   DisallowHeapAllocation no_allocation;
   3058   g->shared()->PrintLn();
   3059 }
   3060 #endif  // OBJECT_PRINT
   3061 
   3062 
   3063 TEST(Regress2211) {
   3064   CcTest::InitializeVM();
   3065   v8::HandleScope scope(CcTest::isolate());
   3066 
   3067   v8::Handle<v8::String> value = v8_str("val string");
   3068   Smi* hash = Smi::FromInt(321);
   3069   Factory* factory = CcTest::i_isolate()->factory();
   3070 
   3071   for (int i = 0; i < 2; i++) {
   3072     // Store identity hash first and common hidden property second.
   3073     v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
   3074     Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
   3075     CHECK(internal_obj->HasFastProperties());
   3076 
   3077     // In the first iteration, set hidden value first and identity hash second.
   3078     // In the second iteration, reverse the order.
   3079     if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
   3080     JSObject::SetIdentityHash(internal_obj, handle(hash, CcTest::i_isolate()));
   3081     if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
   3082 
   3083     // Check values.
   3084     CHECK_EQ(hash,
   3085              internal_obj->GetHiddenProperty(factory->identity_hash_string()));
   3086     CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
   3087 
   3088     // Check size.
   3089     FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0);
   3090     ObjectHashTable* hashtable = ObjectHashTable::cast(
   3091         internal_obj->RawFastPropertyAt(index));
   3092     // HashTable header (5) and 4 initial entries (8).
   3093     CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
   3094   }
   3095 }
   3096 
   3097 
   3098 TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
   3099   if (i::FLAG_always_opt) return;
   3100   CcTest::InitializeVM();
   3101   v8::HandleScope scope(CcTest::isolate());
   3102   v8::Local<v8::Value> fun1, fun2;
   3103 
   3104   {
   3105     LocalContext env;
   3106     CompileRun("function fun() {};");
   3107     fun1 = env->Global()->Get(v8_str("fun"));
   3108   }
   3109 
   3110   {
   3111     LocalContext env;
   3112     CompileRun("function fun() {};");
   3113     fun2 = env->Global()->Get(v8_str("fun"));
   3114   }
   3115 
   3116   // Prepare function f that contains type feedback for closures
   3117   // originating from two different native contexts.
   3118   CcTest::global()->Set(v8_str("fun1"), fun1);
   3119   CcTest::global()->Set(v8_str("fun2"), fun2);
   3120   CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
   3121 
   3122   Handle<JSFunction> f =
   3123       v8::Utils::OpenHandle(
   3124           *v8::Handle<v8::Function>::Cast(
   3125               CcTest::global()->Get(v8_str("f"))));
   3126 
   3127   Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
   3128 
   3129   CHECK_EQ(2, feedback_vector->length());
   3130   CHECK(feedback_vector->get(0)->IsJSFunction());
   3131   CHECK(feedback_vector->get(1)->IsJSFunction());
   3132 
   3133   SimulateIncrementalMarking();
   3134   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   3135 
   3136   CHECK_EQ(2, feedback_vector->length());
   3137   CHECK_EQ(feedback_vector->get(0),
   3138            *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate()));
   3139   CHECK_EQ(feedback_vector->get(1),
   3140            *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate()));
   3141 }
   3142 
   3143 
   3144 static Code* FindFirstIC(Code* code, Code::Kind kind) {
   3145   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
   3146              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
   3147              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
   3148   for (RelocIterator it(code, mask); !it.done(); it.next()) {
   3149     RelocInfo* info = it.rinfo();
   3150     Code* target = Code::GetCodeFromTargetAddress(info->target_address());
   3151     if (target->is_inline_cache_stub() && target->kind() == kind) {
   3152       return target;
   3153     }
   3154   }
   3155   return NULL;
   3156 }
   3157 
   3158 
   3159 TEST(IncrementalMarkingPreservesMonomorphicIC) {
   3160   if (i::FLAG_always_opt) return;
   3161   CcTest::InitializeVM();
   3162   v8::HandleScope scope(CcTest::isolate());
   3163 
   3164   // Prepare function f that contains a monomorphic IC for object
   3165   // originating from the same native context.
   3166   CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
   3167              "function f(o) { return o.x; } f(obj); f(obj);");
   3168   Handle<JSFunction> f =
   3169       v8::Utils::OpenHandle(
   3170           *v8::Handle<v8::Function>::Cast(
   3171               CcTest::global()->Get(v8_str("f"))));
   3172 
   3173   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3174   CHECK(ic_before->ic_state() == MONOMORPHIC);
   3175 
   3176   SimulateIncrementalMarking();
   3177   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   3178 
   3179   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3180   CHECK(ic_after->ic_state() == MONOMORPHIC);
   3181 }
   3182 
   3183 
   3184 TEST(IncrementalMarkingClearsMonomorphicIC) {
   3185   if (i::FLAG_always_opt) return;
   3186   CcTest::InitializeVM();
   3187   v8::HandleScope scope(CcTest::isolate());
   3188   v8::Local<v8::Value> obj1;
   3189 
   3190   {
   3191     LocalContext env;
   3192     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
   3193     obj1 = env->Global()->Get(v8_str("obj"));
   3194   }
   3195 
   3196   // Prepare function f that contains a monomorphic IC for object
   3197   // originating from a different native context.
   3198   CcTest::global()->Set(v8_str("obj1"), obj1);
   3199   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
   3200   Handle<JSFunction> f =
   3201       v8::Utils::OpenHandle(
   3202           *v8::Handle<v8::Function>::Cast(
   3203               CcTest::global()->Get(v8_str("f"))));
   3204 
   3205   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3206   CHECK(ic_before->ic_state() == MONOMORPHIC);
   3207 
   3208   // Fire context dispose notification.
   3209   v8::V8::ContextDisposedNotification();
   3210   SimulateIncrementalMarking();
   3211   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   3212 
   3213   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3214   CHECK(IC::IsCleared(ic_after));
   3215 }
   3216 
   3217 
   3218 TEST(IncrementalMarkingClearsPolymorphicIC) {
   3219   if (i::FLAG_always_opt) return;
   3220   CcTest::InitializeVM();
   3221   v8::HandleScope scope(CcTest::isolate());
   3222   v8::Local<v8::Value> obj1, obj2;
   3223 
   3224   {
   3225     LocalContext env;
   3226     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
   3227     obj1 = env->Global()->Get(v8_str("obj"));
   3228   }
   3229 
   3230   {
   3231     LocalContext env;
   3232     CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
   3233     obj2 = env->Global()->Get(v8_str("obj"));
   3234   }
   3235 
   3236   // Prepare function f that contains a polymorphic IC for objects
   3237   // originating from two different native contexts.
   3238   CcTest::global()->Set(v8_str("obj1"), obj1);
   3239   CcTest::global()->Set(v8_str("obj2"), obj2);
   3240   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
   3241   Handle<JSFunction> f =
   3242       v8::Utils::OpenHandle(
   3243           *v8::Handle<v8::Function>::Cast(
   3244               CcTest::global()->Get(v8_str("f"))));
   3245 
   3246   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3247   CHECK(ic_before->ic_state() == POLYMORPHIC);
   3248 
   3249   // Fire context dispose notification.
   3250   v8::V8::ContextDisposedNotification();
   3251   SimulateIncrementalMarking();
   3252   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   3253 
   3254   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
   3255   CHECK(IC::IsCleared(ic_after));
   3256 }
   3257 
   3258 
   3259 class SourceResource: public v8::String::ExternalAsciiStringResource {
   3260  public:
   3261   explicit SourceResource(const char* data)
   3262     : data_(data), length_(strlen(data)) { }
   3263 
   3264   virtual void Dispose() {
   3265     i::DeleteArray(data_);
   3266     data_ = NULL;
   3267   }
   3268 
   3269   const char* data() const { return data_; }
   3270 
   3271   size_t length() const { return length_; }
   3272 
   3273   bool IsDisposed() { return data_ == NULL; }
   3274 
   3275  private:
   3276   const char* data_;
   3277   size_t length_;
   3278 };
   3279 
   3280 
   3281 void ReleaseStackTraceDataTest(const char* source, const char* accessor) {
   3282   // Test that the data retained by the Error.stack accessor is released
   3283   // after the first time the accessor is fired.  We use external string
   3284   // to check whether the data is being released since the external string
   3285   // resource's callback is fired when the external string is GC'ed.
   3286   v8::HandleScope scope(CcTest::isolate());
   3287   SourceResource* resource = new SourceResource(i::StrDup(source));
   3288   {
   3289     v8::HandleScope scope(CcTest::isolate());
   3290     v8::Handle<v8::String> source_string =
   3291         v8::String::NewExternal(CcTest::isolate(), resource);
   3292     CcTest::heap()->CollectAllAvailableGarbage();
   3293     v8::Script::Compile(source_string)->Run();
   3294     CHECK(!resource->IsDisposed());
   3295   }
   3296   // CcTest::heap()->CollectAllAvailableGarbage();
   3297   CHECK(!resource->IsDisposed());
   3298 
   3299   CompileRun(accessor);
   3300   CcTest::heap()->CollectAllAvailableGarbage();
   3301 
   3302   // External source has been released.
   3303   CHECK(resource->IsDisposed());
   3304   delete resource;
   3305 }
   3306 
   3307 
   3308 TEST(ReleaseStackTraceData) {
   3309   if (i::FLAG_always_opt) {
   3310     // TODO(ulan): Remove this once the memory leak via code_next_link is fixed.
   3311     // See: https://codereview.chromium.org/181833004/
   3312     return;
   3313   }
   3314   FLAG_use_ic = false;  // ICs retain objects.
   3315   FLAG_concurrent_recompilation = false;
   3316   CcTest::InitializeVM();
   3317   static const char* source1 = "var error = null;            "
   3318   /* Normal Error */           "try {                        "
   3319                                "  throw new Error();         "
   3320                                "} catch (e) {                "
   3321                                "  error = e;                 "
   3322                                "}                            ";
   3323   static const char* source2 = "var error = null;            "
   3324   /* Stack overflow */         "try {                        "
   3325                                "  (function f() { f(); })(); "
   3326                                "} catch (e) {                "
   3327                                "  error = e;                 "
   3328                                "}                            ";
   3329   static const char* source3 = "var error = null;            "
   3330   /* Normal Error */           "try {                        "
   3331   /* as prototype */           "  throw new Error();         "
   3332                                "} catch (e) {                "
   3333                                "  error = {};                "
   3334                                "  error.__proto__ = e;       "
   3335                                "}                            ";
   3336   static const char* source4 = "var error = null;            "
   3337   /* Stack overflow */         "try {                        "
   3338   /* as prototype   */         "  (function f() { f(); })(); "
   3339                                "} catch (e) {                "
   3340                                "  error = {};                "
   3341                                "  error.__proto__ = e;       "
   3342                                "}                            ";
   3343   static const char* getter = "error.stack";
   3344   static const char* setter = "error.stack = 0";
   3345 
   3346   ReleaseStackTraceDataTest(source1, setter);
   3347   ReleaseStackTraceDataTest(source2, setter);
   3348   // We do not test source3 and source4 with setter, since the setter is
   3349   // supposed to (untypically) write to the receiver, not the holder.  This is
   3350   // to emulate the behavior of a data property.
   3351 
   3352   ReleaseStackTraceDataTest(source1, getter);
   3353   ReleaseStackTraceDataTest(source2, getter);
   3354   ReleaseStackTraceDataTest(source3, getter);
   3355   ReleaseStackTraceDataTest(source4, getter);
   3356 }
   3357 
   3358 
   3359 TEST(Regress159140) {
   3360   i::FLAG_allow_natives_syntax = true;
   3361   i::FLAG_flush_code_incrementally = true;
   3362   CcTest::InitializeVM();
   3363   Isolate* isolate = CcTest::i_isolate();
   3364   Heap* heap = isolate->heap();
   3365   HandleScope scope(isolate);
   3366 
   3367   // Perform one initial GC to enable code flushing.
   3368   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3369 
   3370   // Prepare several closures that are all eligible for code flushing
   3371   // because all reachable ones are not optimized. Make sure that the
   3372   // optimized code object is directly reachable through a handle so
   3373   // that it is marked black during incremental marking.
   3374   Handle<Code> code;
   3375   {
   3376     HandleScope inner_scope(isolate);
   3377     CompileRun("function h(x) {}"
   3378                "function mkClosure() {"
   3379                "  return function(x) { return x + 1; };"
   3380                "}"
   3381                "var f = mkClosure();"
   3382                "var g = mkClosure();"
   3383                "f(1); f(2);"
   3384                "g(1); g(2);"
   3385                "h(1); h(2);"
   3386                "%OptimizeFunctionOnNextCall(f); f(3);"
   3387                "%OptimizeFunctionOnNextCall(h); h(3);");
   3388 
   3389     Handle<JSFunction> f =
   3390         v8::Utils::OpenHandle(
   3391             *v8::Handle<v8::Function>::Cast(
   3392                 CcTest::global()->Get(v8_str("f"))));
   3393     CHECK(f->is_compiled());
   3394     CompileRun("f = null;");
   3395 
   3396     Handle<JSFunction> g =
   3397         v8::Utils::OpenHandle(
   3398             *v8::Handle<v8::Function>::Cast(
   3399                 CcTest::global()->Get(v8_str("g"))));
   3400     CHECK(g->is_compiled());
   3401     const int kAgingThreshold = 6;
   3402     for (int i = 0; i < kAgingThreshold; i++) {
   3403       g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3404     }
   3405 
   3406     code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
   3407   }
   3408 
   3409   // Simulate incremental marking so that the functions are enqueued as
   3410   // code flushing candidates. Then optimize one function. Finally
   3411   // finish the GC to complete code flushing.
   3412   SimulateIncrementalMarking();
   3413   CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
   3414   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3415 
   3416   // Unoptimized code is missing and the deoptimizer will go ballistic.
   3417   CompileRun("g('bozo');");
   3418 }
   3419 
   3420 
   3421 TEST(Regress165495) {
   3422   i::FLAG_allow_natives_syntax = true;
   3423   i::FLAG_flush_code_incrementally = true;
   3424   CcTest::InitializeVM();
   3425   Isolate* isolate = CcTest::i_isolate();
   3426   Heap* heap = isolate->heap();
   3427   HandleScope scope(isolate);
   3428 
   3429   // Perform one initial GC to enable code flushing.
   3430   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3431 
   3432   // Prepare an optimized closure that the optimized code map will get
   3433   // populated. Then age the unoptimized code to trigger code flushing
   3434   // but make sure the optimized code is unreachable.
   3435   {
   3436     HandleScope inner_scope(isolate);
   3437     CompileRun("function mkClosure() {"
   3438                "  return function(x) { return x + 1; };"
   3439                "}"
   3440                "var f = mkClosure();"
   3441                "f(1); f(2);"
   3442                "%OptimizeFunctionOnNextCall(f); f(3);");
   3443 
   3444     Handle<JSFunction> f =
   3445         v8::Utils::OpenHandle(
   3446             *v8::Handle<v8::Function>::Cast(
   3447                 CcTest::global()->Get(v8_str("f"))));
   3448     CHECK(f->is_compiled());
   3449     const int kAgingThreshold = 6;
   3450     for (int i = 0; i < kAgingThreshold; i++) {
   3451       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3452     }
   3453 
   3454     CompileRun("f = null;");
   3455   }
   3456 
   3457   // Simulate incremental marking so that unoptimized code is flushed
   3458   // even though it still is cached in the optimized code map.
   3459   SimulateIncrementalMarking();
   3460   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3461 
   3462   // Make a new closure that will get code installed from the code map.
   3463   // Unoptimized code is missing and the deoptimizer will go ballistic.
   3464   CompileRun("var g = mkClosure(); g('bozo');");
   3465 }
   3466 
   3467 
   3468 TEST(Regress169209) {
   3469   i::FLAG_stress_compaction = false;
   3470   i::FLAG_allow_natives_syntax = true;
   3471   i::FLAG_flush_code_incrementally = true;
   3472 
   3473   CcTest::InitializeVM();
   3474   Isolate* isolate = CcTest::i_isolate();
   3475   Heap* heap = isolate->heap();
   3476   HandleScope scope(isolate);
   3477 
   3478   // Perform one initial GC to enable code flushing.
   3479   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3480 
   3481   // Prepare a shared function info eligible for code flushing for which
   3482   // the unoptimized code will be replaced during optimization.
   3483   Handle<SharedFunctionInfo> shared1;
   3484   {
   3485     HandleScope inner_scope(isolate);
   3486     CompileRun("function f() { return 'foobar'; }"
   3487                "function g(x) { if (x) f(); }"
   3488                "f();"
   3489                "g(false);"
   3490                "g(false);");
   3491 
   3492     Handle<JSFunction> f =
   3493         v8::Utils::OpenHandle(
   3494             *v8::Handle<v8::Function>::Cast(
   3495                 CcTest::global()->Get(v8_str("f"))));
   3496     CHECK(f->is_compiled());
   3497     const int kAgingThreshold = 6;
   3498     for (int i = 0; i < kAgingThreshold; i++) {
   3499       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3500     }
   3501 
   3502     shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   3503   }
   3504 
   3505   // Prepare a shared function info eligible for code flushing that will
   3506   // represent the dangling tail of the candidate list.
   3507   Handle<SharedFunctionInfo> shared2;
   3508   {
   3509     HandleScope inner_scope(isolate);
   3510     CompileRun("function flushMe() { return 0; }"
   3511                "flushMe(1);");
   3512 
   3513     Handle<JSFunction> f =
   3514         v8::Utils::OpenHandle(
   3515             *v8::Handle<v8::Function>::Cast(
   3516                 CcTest::global()->Get(v8_str("flushMe"))));
   3517     CHECK(f->is_compiled());
   3518     const int kAgingThreshold = 6;
   3519     for (int i = 0; i < kAgingThreshold; i++) {
   3520       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3521     }
   3522 
   3523     shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   3524   }
   3525 
   3526   // Simulate incremental marking and collect code flushing candidates.
   3527   SimulateIncrementalMarking();
   3528   CHECK(shared1->code()->gc_metadata() != NULL);
   3529 
   3530   // Optimize function and make sure the unoptimized code is replaced.
   3531 #ifdef DEBUG
   3532   FLAG_stop_at = "f";
   3533 #endif
   3534   CompileRun("%OptimizeFunctionOnNextCall(g);"
   3535              "g(false);");
   3536 
   3537   // Finish garbage collection cycle.
   3538   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3539   CHECK(shared1->code()->gc_metadata() == NULL);
   3540 }
   3541 
   3542 
   3543 // Helper function that simulates a fill new-space in the heap.
   3544 static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
   3545                                         int extra_bytes) {
   3546   int space_remaining = static_cast<int>(
   3547       *space->allocation_limit_address() - *space->allocation_top_address());
   3548   CHECK(space_remaining >= extra_bytes);
   3549   int new_linear_size = space_remaining - extra_bytes;
   3550   v8::internal::AllocationResult allocation =
   3551       space->AllocateRaw(new_linear_size);
   3552   v8::internal::FreeListNode* node =
   3553       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
   3554   node->set_size(space->heap(), new_linear_size);
   3555 }
   3556 
   3557 
   3558 TEST(Regress169928) {
   3559   i::FLAG_allow_natives_syntax = true;
   3560   i::FLAG_crankshaft = false;
   3561   CcTest::InitializeVM();
   3562   Isolate* isolate = CcTest::i_isolate();
   3563   Factory* factory = isolate->factory();
   3564   v8::HandleScope scope(CcTest::isolate());
   3565 
   3566   // Some flags turn Scavenge collections into Mark-sweep collections
   3567   // and hence are incompatible with this test case.
   3568   if (FLAG_gc_global || FLAG_stress_compaction) return;
   3569 
   3570   // Prepare the environment
   3571   CompileRun("function fastliteralcase(literal, value) {"
   3572              "    literal[0] = value;"
   3573              "    return literal;"
   3574              "}"
   3575              "function get_standard_literal() {"
   3576              "    var literal = [1, 2, 3];"
   3577              "    return literal;"
   3578              "}"
   3579              "obj = fastliteralcase(get_standard_literal(), 1);"
   3580              "obj = fastliteralcase(get_standard_literal(), 1.5);"
   3581              "obj = fastliteralcase(get_standard_literal(), 2);");
   3582 
   3583   // prepare the heap
   3584   v8::Local<v8::String> mote_code_string =
   3585       v8_str("fastliteralcase(mote, 2.5);");
   3586 
   3587   v8::Local<v8::String> array_name = v8_str("mote");
   3588   CcTest::global()->Set(array_name, v8::Int32::New(CcTest::isolate(), 0));
   3589 
   3590   // First make sure we flip spaces
   3591   CcTest::heap()->CollectGarbage(NEW_SPACE);
   3592 
   3593   // Allocate the object.
   3594   Handle<FixedArray> array_data = factory->NewFixedArray(2, NOT_TENURED);
   3595   array_data->set(0, Smi::FromInt(1));
   3596   array_data->set(1, Smi::FromInt(2));
   3597 
   3598   AllocateAllButNBytes(CcTest::heap()->new_space(),
   3599                        JSArray::kSize + AllocationMemento::kSize +
   3600                        kPointerSize);
   3601 
   3602   Handle<JSArray> array = factory->NewJSArrayWithElements(array_data,
   3603                                                           FAST_SMI_ELEMENTS,
   3604                                                           NOT_TENURED);
   3605 
   3606   CHECK_EQ(Smi::FromInt(2), array->length());
   3607   CHECK(array->HasFastSmiOrObjectElements());
   3608 
   3609   // We need filler the size of AllocationMemento object, plus an extra
   3610   // fill pointer value.
   3611   HeapObject* obj = NULL;
   3612   AllocationResult allocation = CcTest::heap()->new_space()->AllocateRaw(
   3613       AllocationMemento::kSize + kPointerSize);
   3614   CHECK(allocation.To(&obj));
   3615   Address addr_obj = obj->address();
   3616   CcTest::heap()->CreateFillerObjectAt(
   3617       addr_obj, AllocationMemento::kSize + kPointerSize);
   3618 
   3619   // Give the array a name, making sure not to allocate strings.
   3620   v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
   3621   CcTest::global()->Set(array_name, array_obj);
   3622 
   3623   // This should crash with a protection violation if we are running a build
   3624   // with the bug.
   3625   AlwaysAllocateScope aa_scope(isolate);
   3626   v8::Script::Compile(mote_code_string)->Run();
   3627 }
   3628 
   3629 
   3630 TEST(Regress168801) {
   3631   if (i::FLAG_never_compact) return;
   3632   i::FLAG_always_compact = true;
   3633   i::FLAG_cache_optimized_code = false;
   3634   i::FLAG_allow_natives_syntax = true;
   3635   i::FLAG_flush_code_incrementally = true;
   3636   CcTest::InitializeVM();
   3637   Isolate* isolate = CcTest::i_isolate();
   3638   Heap* heap = isolate->heap();
   3639   HandleScope scope(isolate);
   3640 
   3641   // Perform one initial GC to enable code flushing.
   3642   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3643 
   3644   // Ensure the code ends up on an evacuation candidate.
   3645   SimulateFullSpace(heap->code_space());
   3646 
   3647   // Prepare an unoptimized function that is eligible for code flushing.
   3648   Handle<JSFunction> function;
   3649   {
   3650     HandleScope inner_scope(isolate);
   3651     CompileRun("function mkClosure() {"
   3652                "  return function(x) { return x + 1; };"
   3653                "}"
   3654                "var f = mkClosure();"
   3655                "f(1); f(2);");
   3656 
   3657     Handle<JSFunction> f =
   3658         v8::Utils::OpenHandle(
   3659             *v8::Handle<v8::Function>::Cast(
   3660                 CcTest::global()->Get(v8_str("f"))));
   3661     CHECK(f->is_compiled());
   3662     const int kAgingThreshold = 6;
   3663     for (int i = 0; i < kAgingThreshold; i++) {
   3664       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3665     }
   3666 
   3667     function = inner_scope.CloseAndEscape(handle(*f, isolate));
   3668   }
   3669 
   3670   // Simulate incremental marking so that unoptimized function is enqueued as a
   3671   // candidate for code flushing. The shared function info however will not be
   3672   // explicitly enqueued.
   3673   SimulateIncrementalMarking();
   3674 
   3675   // Now optimize the function so that it is taken off the candidate list.
   3676   {
   3677     HandleScope inner_scope(isolate);
   3678     CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
   3679   }
   3680 
   3681   // This cycle will bust the heap and subsequent cycles will go ballistic.
   3682   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3683   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3684 }
   3685 
   3686 
   3687 TEST(Regress173458) {
   3688   if (i::FLAG_never_compact) return;
   3689   i::FLAG_always_compact = true;
   3690   i::FLAG_cache_optimized_code = false;
   3691   i::FLAG_allow_natives_syntax = true;
   3692   i::FLAG_flush_code_incrementally = true;
   3693   CcTest::InitializeVM();
   3694   Isolate* isolate = CcTest::i_isolate();
   3695   Heap* heap = isolate->heap();
   3696   HandleScope scope(isolate);
   3697 
   3698   // Perform one initial GC to enable code flushing.
   3699   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3700 
   3701   // Ensure the code ends up on an evacuation candidate.
   3702   SimulateFullSpace(heap->code_space());
   3703 
   3704   // Prepare an unoptimized function that is eligible for code flushing.
   3705   Handle<JSFunction> function;
   3706   {
   3707     HandleScope inner_scope(isolate);
   3708     CompileRun("function mkClosure() {"
   3709                "  return function(x) { return x + 1; };"
   3710                "}"
   3711                "var f = mkClosure();"
   3712                "f(1); f(2);");
   3713 
   3714     Handle<JSFunction> f =
   3715         v8::Utils::OpenHandle(
   3716             *v8::Handle<v8::Function>::Cast(
   3717                 CcTest::global()->Get(v8_str("f"))));
   3718     CHECK(f->is_compiled());
   3719     const int kAgingThreshold = 6;
   3720     for (int i = 0; i < kAgingThreshold; i++) {
   3721       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   3722     }
   3723 
   3724     function = inner_scope.CloseAndEscape(handle(*f, isolate));
   3725   }
   3726 
   3727   // Simulate incremental marking so that unoptimized function is enqueued as a
   3728   // candidate for code flushing. The shared function info however will not be
   3729   // explicitly enqueued.
   3730   SimulateIncrementalMarking();
   3731 
   3732   // Now enable the debugger which in turn will disable code flushing.
   3733   CHECK(isolate->debug()->Load());
   3734 
   3735   // This cycle will bust the heap and subsequent cycles will go ballistic.
   3736   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3737   heap->CollectAllGarbage(Heap::kNoGCFlags);
   3738 }
   3739 
   3740 
   3741 class DummyVisitor : public ObjectVisitor {
   3742  public:
   3743   void VisitPointers(Object** start, Object** end) { }
   3744 };
   3745 
   3746 
   3747 TEST(DeferredHandles) {
   3748   CcTest::InitializeVM();
   3749   Isolate* isolate = CcTest::i_isolate();
   3750   Heap* heap = isolate->heap();
   3751   v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
   3752   HandleScopeData* data = isolate->handle_scope_data();
   3753   Handle<Object> init(heap->empty_string(), isolate);
   3754   while (data->next < data->limit) {
   3755     Handle<Object> obj(heap->empty_string(), isolate);
   3756   }
   3757   // An entire block of handles has been filled.
   3758   // Next handle would require a new block.
   3759   ASSERT(data->next == data->limit);
   3760 
   3761   DeferredHandleScope deferred(isolate);
   3762   DummyVisitor visitor;
   3763   isolate->handle_scope_implementer()->Iterate(&visitor);
   3764   delete deferred.Detach();
   3765 }
   3766 
   3767 
   3768 TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
   3769   CcTest::InitializeVM();
   3770   v8::HandleScope scope(CcTest::isolate());
   3771   CompileRun("function f(n) {"
   3772              "    var a = new Array(n);"
   3773              "    for (var i = 0; i < n; i += 100) a[i] = i;"
   3774              "};"
   3775              "f(10 * 1024 * 1024);");
   3776   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   3777   if (marking->IsStopped()) marking->Start();
   3778   // This big step should be sufficient to mark the whole array.
   3779   marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   3780   ASSERT(marking->IsComplete());
   3781 }
   3782 
   3783 
   3784 TEST(DisableInlineAllocation) {
   3785   i::FLAG_allow_natives_syntax = true;
   3786   CcTest::InitializeVM();
   3787   v8::HandleScope scope(CcTest::isolate());
   3788   CompileRun("function test() {"
   3789              "  var x = [];"
   3790              "  for (var i = 0; i < 10; i++) {"
   3791              "    x[i] = [ {}, [1,2,3], [1,x,3] ];"
   3792              "  }"
   3793              "}"
   3794              "function run() {"
   3795              "  %OptimizeFunctionOnNextCall(test);"
   3796              "  test();"
   3797              "  %DeoptimizeFunction(test);"
   3798              "}");
   3799 
   3800   // Warm-up with inline allocation enabled.
   3801   CompileRun("test(); test(); run();");
   3802 
   3803   // Run test with inline allocation disabled.
   3804   CcTest::heap()->DisableInlineAllocation();
   3805   CompileRun("run()");
   3806 
   3807   // Run test with inline allocation re-enabled.
   3808   CcTest::heap()->EnableInlineAllocation();
   3809   CompileRun("run()");
   3810 }
   3811 
   3812 
   3813 static int AllocationSitesCount(Heap* heap) {
   3814   int count = 0;
   3815   for (Object* site = heap->allocation_sites_list();
   3816        !(site->IsUndefined());
   3817        site = AllocationSite::cast(site)->weak_next()) {
   3818     count++;
   3819   }
   3820   return count;
   3821 }
   3822 
   3823 
   3824 TEST(EnsureAllocationSiteDependentCodesProcessed) {
   3825   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   3826   i::FLAG_allow_natives_syntax = true;
   3827   CcTest::InitializeVM();
   3828   Isolate* isolate = CcTest::i_isolate();
   3829   v8::internal::Heap* heap = CcTest::heap();
   3830   GlobalHandles* global_handles = isolate->global_handles();
   3831 
   3832   if (!isolate->use_crankshaft()) return;
   3833 
   3834   // The allocation site at the head of the list is ours.
   3835   Handle<AllocationSite> site;
   3836   {
   3837     LocalContext context;
   3838     v8::HandleScope scope(context->GetIsolate());
   3839 
   3840     int count = AllocationSitesCount(heap);
   3841     CompileRun("var bar = function() { return (new Array()); };"
   3842                "var a = bar();"
   3843                "bar();"
   3844                "bar();");
   3845 
   3846     // One allocation site should have been created.
   3847     int new_count = AllocationSitesCount(heap);
   3848     CHECK_EQ(new_count, (count + 1));
   3849     site = Handle<AllocationSite>::cast(
   3850         global_handles->Create(
   3851             AllocationSite::cast(heap->allocation_sites_list())));
   3852 
   3853     CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
   3854 
   3855     DependentCode::GroupStartIndexes starts(site->dependent_code());
   3856     CHECK_GE(starts.number_of_entries(), 1);
   3857     int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
   3858     CHECK(site->dependent_code()->is_code_at(index));
   3859     Code* function_bar = site->dependent_code()->code_at(index);
   3860     Handle<JSFunction> bar_handle =
   3861         v8::Utils::OpenHandle(
   3862             *v8::Handle<v8::Function>::Cast(
   3863                 CcTest::global()->Get(v8_str("bar"))));
   3864     CHECK_EQ(bar_handle->code(), function_bar);
   3865   }
   3866 
   3867   // Now make sure that a gc should get rid of the function, even though we
   3868   // still have the allocation site alive.
   3869   for (int i = 0; i < 4; i++) {
   3870     heap->CollectAllGarbage(Heap::kNoGCFlags);
   3871   }
   3872 
   3873   // The site still exists because of our global handle, but the code is no
   3874   // longer referred to by dependent_code().
   3875   DependentCode::GroupStartIndexes starts(site->dependent_code());
   3876   int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
   3877   CHECK(!(site->dependent_code()->is_code_at(index)));
   3878 }
   3879 
   3880 
   3881 TEST(CellsInOptimizedCodeAreWeak) {
   3882   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   3883   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   3884   i::FLAG_allow_natives_syntax = true;
   3885   CcTest::InitializeVM();
   3886   Isolate* isolate = CcTest::i_isolate();
   3887   v8::internal::Heap* heap = CcTest::heap();
   3888 
   3889   if (!isolate->use_crankshaft()) return;
   3890   HandleScope outer_scope(heap->isolate());
   3891   Handle<Code> code;
   3892   {
   3893     LocalContext context;
   3894     HandleScope scope(heap->isolate());
   3895 
   3896     CompileRun("bar = (function() {"
   3897                "  function bar() {"
   3898                "    return foo(1);"
   3899                "  };"
   3900                "  var foo = function(x) { with (x) { return 1 + x; } };"
   3901                "  bar(foo);"
   3902                "  bar(foo);"
   3903                "  bar(foo);"
   3904                "  %OptimizeFunctionOnNextCall(bar);"
   3905                "  bar(foo);"
   3906                "  return bar;})();");
   3907 
   3908     Handle<JSFunction> bar =
   3909         v8::Utils::OpenHandle(
   3910             *v8::Handle<v8::Function>::Cast(
   3911                 CcTest::global()->Get(v8_str("bar"))));
   3912     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
   3913   }
   3914 
   3915   // Now make sure that a gc should get rid of the function
   3916   for (int i = 0; i < 4; i++) {
   3917     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3918   }
   3919 
   3920   ASSERT(code->marked_for_deoptimization());
   3921 }
   3922 
   3923 
   3924 TEST(ObjectsInOptimizedCodeAreWeak) {
   3925   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   3926   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   3927   i::FLAG_allow_natives_syntax = true;
   3928   CcTest::InitializeVM();
   3929   Isolate* isolate = CcTest::i_isolate();
   3930   v8::internal::Heap* heap = CcTest::heap();
   3931 
   3932   if (!isolate->use_crankshaft()) return;
   3933   HandleScope outer_scope(heap->isolate());
   3934   Handle<Code> code;
   3935   {
   3936     LocalContext context;
   3937     HandleScope scope(heap->isolate());
   3938 
   3939     CompileRun("function bar() {"
   3940                "  return foo(1);"
   3941                "};"
   3942                "function foo(x) { with (x) { return 1 + x; } };"
   3943                "bar();"
   3944                "bar();"
   3945                "bar();"
   3946                "%OptimizeFunctionOnNextCall(bar);"
   3947                "bar();");
   3948 
   3949     Handle<JSFunction> bar =
   3950         v8::Utils::OpenHandle(
   3951             *v8::Handle<v8::Function>::Cast(
   3952                 CcTest::global()->Get(v8_str("bar"))));
   3953     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
   3954   }
   3955 
   3956   // Now make sure that a gc should get rid of the function
   3957   for (int i = 0; i < 4; i++) {
   3958     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   3959   }
   3960 
   3961   ASSERT(code->marked_for_deoptimization());
   3962 }
   3963 
   3964 
   3965 TEST(NoWeakHashTableLeakWithIncrementalMarking) {
   3966   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   3967   if (!i::FLAG_incremental_marking) return;
   3968   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   3969   i::FLAG_allow_natives_syntax = true;
   3970   i::FLAG_compilation_cache = false;
   3971   CcTest::InitializeVM();
   3972   Isolate* isolate = CcTest::i_isolate();
   3973   v8::internal::Heap* heap = CcTest::heap();
   3974 
   3975   if (!isolate->use_crankshaft()) return;
   3976   HandleScope outer_scope(heap->isolate());
   3977   for (int i = 0; i < 3; i++) {
   3978     SimulateIncrementalMarking();
   3979     {
   3980       LocalContext context;
   3981       HandleScope scope(heap->isolate());
   3982       EmbeddedVector<char, 256> source;
   3983       SNPrintF(source,
   3984                "function bar%d() {"
   3985                "  return foo%d(1);"
   3986                "};"
   3987                "function foo%d(x) { with (x) { return 1 + x; } };"
   3988                "bar%d();"
   3989                "bar%d();"
   3990                "bar%d();"
   3991                "%%OptimizeFunctionOnNextCall(bar%d);"
   3992                "bar%d();", i, i, i, i, i, i, i, i);
   3993       CompileRun(source.start());
   3994     }
   3995     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   3996   }
   3997   int elements = 0;
   3998   if (heap->weak_object_to_code_table()->IsHashTable()) {
   3999     WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table());
   4000     elements = t->NumberOfElements();
   4001   }
   4002   CHECK_EQ(0, elements);
   4003 }
   4004 
   4005 
   4006 static Handle<JSFunction> OptimizeDummyFunction(const char* name) {
   4007   EmbeddedVector<char, 256> source;
   4008   SNPrintF(source,
   4009           "function %s() { return 0; }"
   4010           "%s(); %s();"
   4011           "%%OptimizeFunctionOnNextCall(%s);"
   4012           "%s();", name, name, name, name, name);
   4013   CompileRun(source.start());
   4014   Handle<JSFunction> fun =
   4015       v8::Utils::OpenHandle(
   4016           *v8::Handle<v8::Function>::Cast(
   4017               CcTest::global()->Get(v8_str(name))));
   4018   return fun;
   4019 }
   4020 
   4021 
   4022 static int GetCodeChainLength(Code* code) {
   4023   int result = 0;
   4024   while (code->next_code_link()->IsCode()) {
   4025     result++;
   4026     code = Code::cast(code->next_code_link());
   4027   }
   4028   return result;
   4029 }
   4030 
   4031 
   4032 TEST(NextCodeLinkIsWeak) {
   4033   i::FLAG_allow_natives_syntax = true;
   4034   CcTest::InitializeVM();
   4035   Isolate* isolate = CcTest::i_isolate();
   4036   v8::internal::Heap* heap = CcTest::heap();
   4037 
   4038   if (!isolate->use_crankshaft()) return;
   4039   HandleScope outer_scope(heap->isolate());
   4040   Handle<Code> code;
   4041   heap->CollectAllAvailableGarbage();
   4042   int code_chain_length_before, code_chain_length_after;
   4043   {
   4044     HandleScope scope(heap->isolate());
   4045     Handle<JSFunction> mortal = OptimizeDummyFunction("mortal");
   4046     Handle<JSFunction> immortal = OptimizeDummyFunction("immortal");
   4047     CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
   4048     code_chain_length_before = GetCodeChainLength(immortal->code());
   4049     // Keep the immortal code and let the mortal code die.
   4050     code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
   4051     CompileRun("mortal = null; immortal = null;");
   4052   }
   4053   heap->CollectAllAvailableGarbage();
   4054   // Now mortal code should be dead.
   4055   code_chain_length_after = GetCodeChainLength(*code);
   4056   CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
   4057 }
   4058 
   4059 
   4060 static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
   4061   i::byte buffer[i::Assembler::kMinimalBufferSize];
   4062   MacroAssembler masm(isolate, buffer, sizeof(buffer));
   4063   CodeDesc desc;
   4064   masm.Push(isolate->factory()->undefined_value());
   4065   masm.Drop(1);
   4066   masm.GetCode(&desc);
   4067   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
   4068   Handle<Code> code = isolate->factory()->NewCode(
   4069       desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
   4070   CHECK(code->IsCode());
   4071   return code;
   4072 }
   4073 
   4074 
   4075 TEST(NextCodeLinkIsWeak2) {
   4076   i::FLAG_allow_natives_syntax = true;
   4077   CcTest::InitializeVM();
   4078   Isolate* isolate = CcTest::i_isolate();
   4079   v8::internal::Heap* heap = CcTest::heap();
   4080 
   4081   if (!isolate->use_crankshaft()) return;
   4082   HandleScope outer_scope(heap->isolate());
   4083   heap->CollectAllAvailableGarbage();
   4084   Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
   4085   Handle<Code> new_head;
   4086   Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
   4087   {
   4088     HandleScope scope(heap->isolate());
   4089     Handle<Code> immortal = DummyOptimizedCode(isolate);
   4090     Handle<Code> mortal = DummyOptimizedCode(isolate);
   4091     mortal->set_next_code_link(*old_head);
   4092     immortal->set_next_code_link(*mortal);
   4093     context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
   4094     new_head = scope.CloseAndEscape(immortal);
   4095   }
   4096   heap->CollectAllAvailableGarbage();
   4097   // Now mortal code should be dead.
   4098   CHECK_EQ(*old_head, new_head->next_code_link());
   4099 }
   4100 
   4101 
   4102 static bool weak_ic_cleared = false;
   4103 
   4104 static void ClearWeakIC(const v8::WeakCallbackData<v8::Object, void>& data) {
   4105   printf("clear weak is called\n");
   4106   weak_ic_cleared = true;
   4107   v8::Persistent<v8::Value>* p =
   4108       reinterpret_cast<v8::Persistent<v8::Value>*>(data.GetParameter());
   4109   CHECK(p->IsNearDeath());
   4110   p->Reset();
   4111 }
   4112 
   4113 
   4114 // Checks that the value returned by execution of the source is weak.
   4115 void CheckWeakness(const char* source) {
   4116   i::FLAG_stress_compaction = false;
   4117   CcTest::InitializeVM();
   4118   v8::Isolate* isolate = CcTest::isolate();
   4119   v8::HandleScope scope(isolate);
   4120   v8::Persistent<v8::Object> garbage;
   4121   {
   4122     v8::HandleScope scope(isolate);
   4123     garbage.Reset(isolate, CompileRun(source)->ToObject());
   4124   }
   4125   weak_ic_cleared = false;
   4126   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
   4127   Heap* heap = CcTest::i_isolate()->heap();
   4128   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   4129   CHECK(weak_ic_cleared);
   4130 }
   4131 
   4132 
   4133 // Each of the following "weak IC" tests creates an IC that embeds a map with
   4134 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
   4135 TEST(WeakMapInMonomorphicLoadIC) {
   4136   CheckWeakness("function loadIC(obj) {"
   4137                 "  return obj.name;"
   4138                 "}"
   4139                 " (function() {"
   4140                 "   var proto = {'name' : 'weak'};"
   4141                 "   var obj = Object.create(proto);"
   4142                 "   loadIC(obj);"
   4143                 "   loadIC(obj);"
   4144                 "   loadIC(obj);"
   4145                 "   return proto;"
   4146                 " })();");
   4147 }
   4148 
   4149 
   4150 TEST(WeakMapInMonomorphicKeyedLoadIC) {
   4151   CheckWeakness("function keyedLoadIC(obj, field) {"
   4152                 "  return obj[field];"
   4153                 "}"
   4154                 " (function() {"
   4155                 "   var proto = {'name' : 'weak'};"
   4156                 "   var obj = Object.create(proto);"
   4157                 "   keyedLoadIC(obj, 'name');"
   4158                 "   keyedLoadIC(obj, 'name');"
   4159                 "   keyedLoadIC(obj, 'name');"
   4160                 "   return proto;"
   4161                 " })();");
   4162 }
   4163 
   4164 
   4165 TEST(WeakMapInMonomorphicStoreIC) {
   4166   CheckWeakness("function storeIC(obj, value) {"
   4167                 "  obj.name = value;"
   4168                 "}"
   4169                 " (function() {"
   4170                 "   var proto = {'name' : 'weak'};"
   4171                 "   var obj = Object.create(proto);"
   4172                 "   storeIC(obj, 'x');"
   4173                 "   storeIC(obj, 'x');"
   4174                 "   storeIC(obj, 'x');"
   4175                 "   return proto;"
   4176                 " })();");
   4177 }
   4178 
   4179 
   4180 TEST(WeakMapInMonomorphicKeyedStoreIC) {
   4181   CheckWeakness("function keyedStoreIC(obj, field, value) {"
   4182                 "  obj[field] = value;"
   4183                 "}"
   4184                 " (function() {"
   4185                 "   var proto = {'name' : 'weak'};"
   4186                 "   var obj = Object.create(proto);"
   4187                 "   keyedStoreIC(obj, 'x');"
   4188                 "   keyedStoreIC(obj, 'x');"
   4189                 "   keyedStoreIC(obj, 'x');"
   4190                 "   return proto;"
   4191                 " })();");
   4192 }
   4193 
   4194 
   4195 TEST(WeakMapInMonomorphicCompareNilIC) {
   4196   CheckWeakness("function compareNilIC(obj) {"
   4197                 "  return obj == null;"
   4198                 "}"
   4199                 " (function() {"
   4200                 "   var proto = {'name' : 'weak'};"
   4201                 "   var obj = Object.create(proto);"
   4202                 "   compareNilIC(obj);"
   4203                 "   compareNilIC(obj);"
   4204                 "   compareNilIC(obj);"
   4205                 "   return proto;"
   4206                 " })();");
   4207 }
   4208 
   4209 
   4210 #ifdef DEBUG
   4211 TEST(AddInstructionChangesNewSpacePromotion) {
   4212   i::FLAG_allow_natives_syntax = true;
   4213   i::FLAG_expose_gc = true;
   4214   i::FLAG_stress_compaction = true;
   4215   i::FLAG_gc_interval = 1000;
   4216   CcTest::InitializeVM();
   4217   if (!i::FLAG_allocation_site_pretenuring) return;
   4218   v8::HandleScope scope(CcTest::isolate());
   4219   Isolate* isolate = CcTest::i_isolate();
   4220   Heap* heap = isolate->heap();
   4221 
   4222   CompileRun(
   4223       "function add(a, b) {"
   4224       "  return a + b;"
   4225       "}"
   4226       "add(1, 2);"
   4227       "add(\"a\", \"b\");"
   4228       "var oldSpaceObject;"
   4229       "gc();"
   4230       "function crash(x) {"
   4231       "  var object = {a: null, b: null};"
   4232       "  var result = add(1.5, x | 0);"
   4233       "  object.a = result;"
   4234       "  oldSpaceObject = object;"
   4235       "  return object;"
   4236       "}"
   4237       "crash(1);"
   4238       "crash(1);"
   4239       "%OptimizeFunctionOnNextCall(crash);"
   4240       "crash(1);");
   4241 
   4242   v8::Handle<v8::Object> global = CcTest::global();
   4243     v8::Handle<v8::Function> g =
   4244         v8::Handle<v8::Function>::Cast(global->Get(v8_str("crash")));
   4245   v8::Handle<v8::Value> args1[] = { v8_num(1) };
   4246   heap->DisableInlineAllocation();
   4247   heap->set_allocation_timeout(1);
   4248   g->Call(global, 1, args1);
   4249   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   4250 }
   4251 
   4252 
   4253 void OnFatalErrorExpectOOM(const char* location, const char* message) {
   4254   // Exit with 0 if the location matches our expectation.
   4255   exit(strcmp(location, "CALL_AND_RETRY_LAST"));
   4256 }
   4257 
   4258 
   4259 TEST(CEntryStubOOM) {
   4260   i::FLAG_allow_natives_syntax = true;
   4261   CcTest::InitializeVM();
   4262   v8::HandleScope scope(CcTest::isolate());
   4263   v8::V8::SetFatalErrorHandler(OnFatalErrorExpectOOM);
   4264 
   4265   v8::Handle<v8::Value> result = CompileRun(
   4266       "%SetFlags('--gc-interval=1');"
   4267       "var a = [];"
   4268       "a.__proto__ = [];"
   4269       "a.unshift(1)");
   4270 
   4271   CHECK(result->IsNumber());
   4272 }
   4273 
   4274 #endif  // DEBUG
   4275 
   4276 
   4277 static void InterruptCallback357137(v8::Isolate* isolate, void* data) { }
   4278 
   4279 
   4280 static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4281   CcTest::isolate()->RequestInterrupt(&InterruptCallback357137, NULL);
   4282 }
   4283 
   4284 
   4285 TEST(Regress357137) {
   4286   CcTest::InitializeVM();
   4287   v8::Isolate* isolate = CcTest::isolate();
   4288   v8::HandleScope hscope(isolate);
   4289   v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
   4290   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
   4291               v8::FunctionTemplate::New(isolate, RequestInterrupt));
   4292   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
   4293   ASSERT(!context.IsEmpty());
   4294   v8::Context::Scope cscope(context);
   4295 
   4296   v8::Local<v8::Value> result = CompileRun(
   4297       "var locals = '';"
   4298       "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';"
   4299       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
   4300       "interrupt();"  // This triggers a fake stack overflow in f.
   4301       "f()()");
   4302   CHECK_EQ(42.0, result->ToNumber()->Value());
   4303 }
   4304 
   4305 
   4306 TEST(ArrayShiftSweeping) {
   4307   i::FLAG_expose_gc = true;
   4308   CcTest::InitializeVM();
   4309   v8::HandleScope scope(CcTest::isolate());
   4310   Isolate* isolate = CcTest::i_isolate();
   4311   Heap* heap = isolate->heap();
   4312 
   4313   v8::Local<v8::Value> result = CompileRun(
   4314       "var array = new Array(40000);"
   4315       "var tmp = new Array(100000);"
   4316       "array[0] = 10;"
   4317       "gc();"
   4318       "array.shift();"
   4319       "array;");
   4320 
   4321   Handle<JSObject> o =
   4322       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
   4323   CHECK(heap->InOldPointerSpace(o->elements()));
   4324   CHECK(heap->InOldPointerSpace(*o));
   4325   Page* page = Page::FromAddress(o->elements()->address());
   4326   CHECK(page->WasSwept() ||
   4327         Marking::IsBlack(Marking::MarkBitFrom(o->elements())));
   4328 }
   4329 
   4330 
   4331 #ifdef DEBUG
   4332 TEST(PathTracer) {
   4333   CcTest::InitializeVM();
   4334   v8::HandleScope scope(CcTest::isolate());
   4335 
   4336   v8::Local<v8::Value> result = CompileRun("'abc'");
   4337   Handle<Object> o = v8::Utils::OpenHandle(*result);
   4338   CcTest::i_isolate()->heap()->TracePathToObject(*o);
   4339 }
   4340 #endif  // DEBUG
   4341