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