Home | History | Annotate | Download | only in heap
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <stdlib.h>
     29 #include <utility>
     30 
     31 #include "src/compilation-cache.h"
     32 #include "src/context-measure.h"
     33 #include "src/deoptimizer.h"
     34 #include "src/elements.h"
     35 #include "src/execution.h"
     36 #include "src/factory.h"
     37 #include "src/field-type.h"
     38 #include "src/global-handles.h"
     39 #include "src/heap/gc-tracer.h"
     40 #include "src/heap/memory-reducer.h"
     41 #include "src/ic/ic.h"
     42 #include "src/macro-assembler.h"
     43 #include "src/regexp/jsregexp.h"
     44 #include "src/snapshot/snapshot.h"
     45 #include "test/cctest/cctest.h"
     46 #include "test/cctest/heap/heap-tester.h"
     47 #include "test/cctest/heap/heap-utils.h"
     48 #include "test/cctest/test-feedback-vector.h"
     49 
     50 
     51 namespace v8 {
     52 namespace internal {
     53 
     54 static void CheckMap(Map* map, int type, int instance_size) {
     55   CHECK(map->IsHeapObject());
     56 #ifdef DEBUG
     57   CHECK(CcTest::heap()->Contains(map));
     58 #endif
     59   CHECK_EQ(CcTest::heap()->meta_map(), map->map());
     60   CHECK_EQ(type, map->instance_type());
     61   CHECK_EQ(instance_size, map->instance_size());
     62 }
     63 
     64 
     65 TEST(HeapMaps) {
     66   CcTest::InitializeVM();
     67   Heap* heap = CcTest::heap();
     68   CheckMap(heap->meta_map(), MAP_TYPE, Map::kSize);
     69   CheckMap(heap->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
     70 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
     71   CheckMap(heap->type##_map(), SIMD128_VALUE_TYPE, Type::kSize);
     72   SIMD128_TYPES(SIMD128_TYPE)
     73 #undef SIMD128_TYPE
     74   CheckMap(heap->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
     75   CheckMap(heap->string_map(), STRING_TYPE, kVariableSizeSentinel);
     76 }
     77 
     78 
     79 static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
     80   CHECK(obj->IsOddball());
     81   Handle<Object> handle(obj, isolate);
     82   Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
     83   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
     84 }
     85 
     86 
     87 static void CheckSmi(Isolate* isolate, int value, const char* string) {
     88   Handle<Object> handle(Smi::FromInt(value), isolate);
     89   Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
     90   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
     91 }
     92 
     93 
     94 static void CheckNumber(Isolate* isolate, double value, const char* string) {
     95   Handle<Object> number = isolate->factory()->NewNumber(value);
     96   CHECK(number->IsNumber());
     97   Handle<Object> print_string =
     98       Object::ToString(isolate, number).ToHandleChecked();
     99   CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
    100 }
    101 
    102 
    103 static void CheckFindCodeObject(Isolate* isolate) {
    104   // Test FindCodeObject
    105 #define __ assm.
    106 
    107   Assembler assm(isolate, NULL, 0);
    108 
    109   __ nop();  // supported on all architectures
    110 
    111   CodeDesc desc;
    112   assm.GetCode(&desc);
    113   Handle<Code> code = isolate->factory()->NewCode(
    114       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
    115   CHECK(code->IsCode());
    116 
    117   HeapObject* obj = HeapObject::cast(*code);
    118   Address obj_addr = obj->address();
    119 
    120   for (int i = 0; i < obj->Size(); i += kPointerSize) {
    121     Object* found = isolate->FindCodeObject(obj_addr + i);
    122     CHECK_EQ(*code, found);
    123   }
    124 
    125   Handle<Code> copy = isolate->factory()->NewCode(
    126       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
    127   HeapObject* obj_copy = HeapObject::cast(*copy);
    128   Object* not_right = isolate->FindCodeObject(obj_copy->address() +
    129                                               obj_copy->Size() / 2);
    130   CHECK(not_right != *code);
    131 }
    132 
    133 
    134 TEST(HandleNull) {
    135   CcTest::InitializeVM();
    136   Isolate* isolate = CcTest::i_isolate();
    137   HandleScope outer_scope(isolate);
    138   LocalContext context;
    139   Handle<Object> n(static_cast<Object*>(nullptr), isolate);
    140   CHECK(!n.is_null());
    141 }
    142 
    143 
    144 TEST(HeapObjects) {
    145   CcTest::InitializeVM();
    146   Isolate* isolate = CcTest::i_isolate();
    147   Factory* factory = isolate->factory();
    148   Heap* heap = isolate->heap();
    149 
    150   HandleScope sc(isolate);
    151   Handle<Object> value = factory->NewNumber(1.000123);
    152   CHECK(value->IsHeapNumber());
    153   CHECK(value->IsNumber());
    154   CHECK_EQ(1.000123, value->Number());
    155 
    156   value = factory->NewNumber(1.0);
    157   CHECK(value->IsSmi());
    158   CHECK(value->IsNumber());
    159   CHECK_EQ(1.0, value->Number());
    160 
    161   value = factory->NewNumberFromInt(1024);
    162   CHECK(value->IsSmi());
    163   CHECK(value->IsNumber());
    164   CHECK_EQ(1024.0, value->Number());
    165 
    166   value = factory->NewNumberFromInt(Smi::kMinValue);
    167   CHECK(value->IsSmi());
    168   CHECK(value->IsNumber());
    169   CHECK_EQ(Smi::kMinValue, Handle<Smi>::cast(value)->value());
    170 
    171   value = factory->NewNumberFromInt(Smi::kMaxValue);
    172   CHECK(value->IsSmi());
    173   CHECK(value->IsNumber());
    174   CHECK_EQ(Smi::kMaxValue, Handle<Smi>::cast(value)->value());
    175 
    176 #if !defined(V8_TARGET_ARCH_64_BIT)
    177   // TODO(lrn): We need a NumberFromIntptr function in order to test this.
    178   value = factory->NewNumberFromInt(Smi::kMinValue - 1);
    179   CHECK(value->IsHeapNumber());
    180   CHECK(value->IsNumber());
    181   CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
    182 #endif
    183 
    184   value = factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
    185   CHECK(value->IsHeapNumber());
    186   CHECK(value->IsNumber());
    187   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
    188            value->Number());
    189 
    190   value = factory->NewNumberFromUint(static_cast<uint32_t>(1) << 31);
    191   CHECK(value->IsHeapNumber());
    192   CHECK(value->IsNumber());
    193   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
    194            value->Number());
    195 
    196   // nan oddball checks
    197   CHECK(factory->nan_value()->IsNumber());
    198   CHECK(std::isnan(factory->nan_value()->Number()));
    199 
    200   Handle<String> s = factory->NewStringFromStaticChars("fisk hest ");
    201   CHECK(s->IsString());
    202   CHECK_EQ(10, s->length());
    203 
    204   Handle<String> object_string = Handle<String>::cast(factory->Object_string());
    205   Handle<JSGlobalObject> global(
    206       CcTest::i_isolate()->context()->global_object());
    207   CHECK(Just(true) == JSReceiver::HasOwnProperty(global, object_string));
    208 
    209   // Check ToString for oddballs
    210   CheckOddball(isolate, heap->true_value(), "true");
    211   CheckOddball(isolate, heap->false_value(), "false");
    212   CheckOddball(isolate, heap->null_value(), "null");
    213   CheckOddball(isolate, heap->undefined_value(), "undefined");
    214 
    215   // Check ToString for Smis
    216   CheckSmi(isolate, 0, "0");
    217   CheckSmi(isolate, 42, "42");
    218   CheckSmi(isolate, -42, "-42");
    219 
    220   // Check ToString for Numbers
    221   CheckNumber(isolate, 1.1, "1.1");
    222 
    223   CheckFindCodeObject(isolate);
    224 }
    225 
    226 
    227 template <typename T, typename LANE_TYPE, int LANES>
    228 static void CheckSimdValue(T* value, LANE_TYPE lane_values[LANES],
    229                            LANE_TYPE other_value) {
    230   // Check against lane_values, and check that all lanes can be set to
    231   // other_value without disturbing the other lanes.
    232   for (int i = 0; i < LANES; i++) {
    233     CHECK_EQ(lane_values[i], value->get_lane(i));
    234   }
    235   for (int i = 0; i < LANES; i++) {
    236     value->set_lane(i, other_value);  // change the value
    237     for (int j = 0; j < LANES; j++) {
    238       if (i != j)
    239         CHECK_EQ(lane_values[j], value->get_lane(j));
    240       else
    241         CHECK_EQ(other_value, value->get_lane(j));
    242     }
    243     value->set_lane(i, lane_values[i]);  // restore the lane
    244   }
    245   CHECK(value->BooleanValue());  // SIMD values are 'true'.
    246 }
    247 
    248 
    249 TEST(SimdObjects) {
    250   CcTest::InitializeVM();
    251   Isolate* isolate = CcTest::i_isolate();
    252   Factory* factory = isolate->factory();
    253 
    254   HandleScope sc(isolate);
    255 
    256   // Float32x4
    257   {
    258     float lanes[4] = {1, 2, 3, 4};
    259     float quiet_NaN = std::numeric_limits<float>::quiet_NaN();
    260     float signaling_NaN = std::numeric_limits<float>::signaling_NaN();
    261 
    262     Handle<Float32x4> value = factory->NewFloat32x4(lanes);
    263     CHECK(value->IsFloat32x4());
    264     CheckSimdValue<Float32x4, float, 4>(*value, lanes, 3.14f);
    265 
    266     // Check special lane values.
    267     value->set_lane(1, -0.0);
    268     CHECK_EQ(-0.0f, value->get_lane(1));
    269     CHECK(std::signbit(value->get_lane(1)));  // Sign bit should be preserved.
    270     value->set_lane(2, quiet_NaN);
    271     CHECK(std::isnan(value->get_lane(2)));
    272     value->set_lane(3, signaling_NaN);
    273     CHECK(std::isnan(value->get_lane(3)));
    274 
    275 #ifdef OBJECT_PRINT
    276     // Check value printing.
    277     {
    278       value = factory->NewFloat32x4(lanes);
    279       std::ostringstream os;
    280       value->Float32x4Print(os);
    281       CHECK_EQ("1, 2, 3, 4", os.str());
    282     }
    283     {
    284       float special_lanes[4] = {0, -0.0, quiet_NaN, signaling_NaN};
    285       value = factory->NewFloat32x4(special_lanes);
    286       std::ostringstream os;
    287       value->Float32x4Print(os);
    288       // Value printing doesn't preserve signed zeroes.
    289       CHECK_EQ("0, 0, NaN, NaN", os.str());
    290     }
    291 #endif  // OBJECT_PRINT
    292   }
    293   // Int32x4
    294   {
    295     int32_t lanes[4] = {1, 2, 3, 4};
    296 
    297     Handle<Int32x4> value = factory->NewInt32x4(lanes);
    298     CHECK(value->IsInt32x4());
    299     CheckSimdValue<Int32x4, int32_t, 4>(*value, lanes, 3);
    300 
    301 #ifdef OBJECT_PRINT
    302     std::ostringstream os;
    303     value->Int32x4Print(os);
    304     CHECK_EQ("1, 2, 3, 4", os.str());
    305 #endif  // OBJECT_PRINT
    306   }
    307   // Uint32x4
    308   {
    309     uint32_t lanes[4] = {1, 2, 3, 4};
    310 
    311     Handle<Uint32x4> value = factory->NewUint32x4(lanes);
    312     CHECK(value->IsUint32x4());
    313     CheckSimdValue<Uint32x4, uint32_t, 4>(*value, lanes, 3);
    314 
    315 #ifdef OBJECT_PRINT
    316     std::ostringstream os;
    317     value->Uint32x4Print(os);
    318     CHECK_EQ("1, 2, 3, 4", os.str());
    319 #endif  // OBJECT_PRINT
    320   }
    321   // Bool32x4
    322   {
    323     bool lanes[4] = {true, false, true, false};
    324 
    325     Handle<Bool32x4> value = factory->NewBool32x4(lanes);
    326     CHECK(value->IsBool32x4());
    327     CheckSimdValue<Bool32x4, bool, 4>(*value, lanes, false);
    328 
    329 #ifdef OBJECT_PRINT
    330     std::ostringstream os;
    331     value->Bool32x4Print(os);
    332     CHECK_EQ("true, false, true, false", os.str());
    333 #endif  // OBJECT_PRINT
    334   }
    335   // Int16x8
    336   {
    337     int16_t lanes[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    338 
    339     Handle<Int16x8> value = factory->NewInt16x8(lanes);
    340     CHECK(value->IsInt16x8());
    341     CheckSimdValue<Int16x8, int16_t, 8>(*value, lanes, 32767);
    342 
    343 #ifdef OBJECT_PRINT
    344     std::ostringstream os;
    345     value->Int16x8Print(os);
    346     CHECK_EQ("1, 2, 3, 4, 5, 6, 7, 8", os.str());
    347 #endif  // OBJECT_PRINT
    348   }
    349   // Uint16x8
    350   {
    351     uint16_t lanes[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    352 
    353     Handle<Uint16x8> value = factory->NewUint16x8(lanes);
    354     CHECK(value->IsUint16x8());
    355     CheckSimdValue<Uint16x8, uint16_t, 8>(*value, lanes, 32767);
    356 
    357 #ifdef OBJECT_PRINT
    358     std::ostringstream os;
    359     value->Uint16x8Print(os);
    360     CHECK_EQ("1, 2, 3, 4, 5, 6, 7, 8", os.str());
    361 #endif  // OBJECT_PRINT
    362   }
    363   // Bool16x8
    364   {
    365     bool lanes[8] = {true, false, true, false, true, false, true, false};
    366 
    367     Handle<Bool16x8> value = factory->NewBool16x8(lanes);
    368     CHECK(value->IsBool16x8());
    369     CheckSimdValue<Bool16x8, bool, 8>(*value, lanes, false);
    370 
    371 #ifdef OBJECT_PRINT
    372     std::ostringstream os;
    373     value->Bool16x8Print(os);
    374     CHECK_EQ("true, false, true, false, true, false, true, false", os.str());
    375 #endif  // OBJECT_PRINT
    376   }
    377   // Int8x16
    378   {
    379     int8_t lanes[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
    380 
    381     Handle<Int8x16> value = factory->NewInt8x16(lanes);
    382     CHECK(value->IsInt8x16());
    383     CheckSimdValue<Int8x16, int8_t, 16>(*value, lanes, 127);
    384 
    385 #ifdef OBJECT_PRINT
    386     std::ostringstream os;
    387     value->Int8x16Print(os);
    388     CHECK_EQ("1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16", os.str());
    389 #endif  // OBJECT_PRINT
    390   }
    391   // Uint8x16
    392   {
    393     uint8_t lanes[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
    394 
    395     Handle<Uint8x16> value = factory->NewUint8x16(lanes);
    396     CHECK(value->IsUint8x16());
    397     CheckSimdValue<Uint8x16, uint8_t, 16>(*value, lanes, 127);
    398 
    399 #ifdef OBJECT_PRINT
    400     std::ostringstream os;
    401     value->Uint8x16Print(os);
    402     CHECK_EQ("1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16", os.str());
    403 #endif  // OBJECT_PRINT
    404   }
    405   // Bool8x16
    406   {
    407     bool lanes[16] = {true, false, true, false, true, false, true, false,
    408                       true, false, true, false, true, false, true, false};
    409 
    410     Handle<Bool8x16> value = factory->NewBool8x16(lanes);
    411     CHECK(value->IsBool8x16());
    412     CheckSimdValue<Bool8x16, bool, 16>(*value, lanes, false);
    413 
    414 #ifdef OBJECT_PRINT
    415     std::ostringstream os;
    416     value->Bool8x16Print(os);
    417     CHECK_EQ(
    418         "true, false, true, false, true, false, true, false, true, false, "
    419         "true, false, true, false, true, false",
    420         os.str());
    421 #endif  // OBJECT_PRINT
    422   }
    423 }
    424 
    425 
    426 TEST(Tagging) {
    427   CcTest::InitializeVM();
    428   int request = 24;
    429   CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
    430   CHECK(Smi::FromInt(42)->IsSmi());
    431   CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
    432   CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
    433 }
    434 
    435 
    436 TEST(GarbageCollection) {
    437   CcTest::InitializeVM();
    438   Isolate* isolate = CcTest::i_isolate();
    439   Heap* heap = isolate->heap();
    440   Factory* factory = isolate->factory();
    441 
    442   HandleScope sc(isolate);
    443   // Check GC.
    444   heap->CollectGarbage(NEW_SPACE);
    445 
    446   Handle<JSGlobalObject> global(
    447       CcTest::i_isolate()->context()->global_object());
    448   Handle<String> name = factory->InternalizeUtf8String("theFunction");
    449   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
    450   Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
    451   Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
    452   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
    453   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
    454 
    455   {
    456     HandleScope inner_scope(isolate);
    457     // Allocate a function and keep it in global object's property.
    458     Handle<JSFunction> function = factory->NewFunction(name);
    459     JSReceiver::SetProperty(global, name, function, SLOPPY).Check();
    460     // Allocate an object.  Unrooted after leaving the scope.
    461     Handle<JSObject> obj = factory->NewJSObject(function);
    462     JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check();
    463     JSReceiver::SetProperty(obj, prop_namex, twenty_four, SLOPPY).Check();
    464 
    465     CHECK_EQ(Smi::FromInt(23),
    466              *Object::GetProperty(obj, prop_name).ToHandleChecked());
    467     CHECK_EQ(Smi::FromInt(24),
    468              *Object::GetProperty(obj, prop_namex).ToHandleChecked());
    469   }
    470 
    471   heap->CollectGarbage(NEW_SPACE);
    472 
    473   // Function should be alive.
    474   CHECK(Just(true) == JSReceiver::HasOwnProperty(global, name));
    475   // Check function is retained.
    476   Handle<Object> func_value =
    477       Object::GetProperty(global, name).ToHandleChecked();
    478   CHECK(func_value->IsJSFunction());
    479   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
    480 
    481   {
    482     HandleScope inner_scope(isolate);
    483     // Allocate another object, make it reachable from global.
    484     Handle<JSObject> obj = factory->NewJSObject(function);
    485     JSReceiver::SetProperty(global, obj_name, obj, SLOPPY).Check();
    486     JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check();
    487   }
    488 
    489   // After gc, it should survive.
    490   heap->CollectGarbage(NEW_SPACE);
    491 
    492   CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name));
    493   Handle<Object> obj =
    494       Object::GetProperty(global, obj_name).ToHandleChecked();
    495   CHECK(obj->IsJSObject());
    496   CHECK_EQ(Smi::FromInt(23),
    497            *Object::GetProperty(obj, prop_name).ToHandleChecked());
    498 }
    499 
    500 
    501 static void VerifyStringAllocation(Isolate* isolate, const char* string) {
    502   HandleScope scope(isolate);
    503   Handle<String> s = isolate->factory()->NewStringFromUtf8(
    504       CStrVector(string)).ToHandleChecked();
    505   CHECK_EQ(StrLength(string), s->length());
    506   for (int index = 0; index < s->length(); index++) {
    507     CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
    508   }
    509 }
    510 
    511 
    512 TEST(String) {
    513   CcTest::InitializeVM();
    514   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
    515 
    516   VerifyStringAllocation(isolate, "a");
    517   VerifyStringAllocation(isolate, "ab");
    518   VerifyStringAllocation(isolate, "abc");
    519   VerifyStringAllocation(isolate, "abcd");
    520   VerifyStringAllocation(isolate, "fiskerdrengen er paa havet");
    521 }
    522 
    523 
    524 TEST(LocalHandles) {
    525   CcTest::InitializeVM();
    526   Isolate* isolate = CcTest::i_isolate();
    527   Factory* factory = isolate->factory();
    528 
    529   v8::HandleScope scope(CcTest::isolate());
    530   const char* name = "Kasper the spunky";
    531   Handle<String> string = factory->NewStringFromAsciiChecked(name);
    532   CHECK_EQ(StrLength(name), string->length());
    533 }
    534 
    535 
    536 TEST(GlobalHandles) {
    537   CcTest::InitializeVM();
    538   Isolate* isolate = CcTest::i_isolate();
    539   Heap* heap = isolate->heap();
    540   Factory* factory = isolate->factory();
    541   GlobalHandles* global_handles = isolate->global_handles();
    542 
    543   Handle<Object> h1;
    544   Handle<Object> h2;
    545   Handle<Object> h3;
    546   Handle<Object> h4;
    547 
    548   {
    549     HandleScope scope(isolate);
    550 
    551     Handle<Object> i = factory->NewStringFromStaticChars("fisk");
    552     Handle<Object> u = factory->NewNumber(1.12344);
    553 
    554     h1 = global_handles->Create(*i);
    555     h2 = global_handles->Create(*u);
    556     h3 = global_handles->Create(*i);
    557     h4 = global_handles->Create(*u);
    558   }
    559 
    560   // after gc, it should survive
    561   heap->CollectGarbage(NEW_SPACE);
    562 
    563   CHECK((*h1)->IsString());
    564   CHECK((*h2)->IsHeapNumber());
    565   CHECK((*h3)->IsString());
    566   CHECK((*h4)->IsHeapNumber());
    567 
    568   CHECK_EQ(*h3, *h1);
    569   GlobalHandles::Destroy(h1.location());
    570   GlobalHandles::Destroy(h3.location());
    571 
    572   CHECK_EQ(*h4, *h2);
    573   GlobalHandles::Destroy(h2.location());
    574   GlobalHandles::Destroy(h4.location());
    575 }
    576 
    577 
    578 static bool WeakPointerCleared = false;
    579 
    580 static void TestWeakGlobalHandleCallback(
    581     const v8::WeakCallbackInfo<void>& data) {
    582   std::pair<v8::Persistent<v8::Value>*, int>* p =
    583       reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>(
    584           data.GetParameter());
    585   if (p->second == 1234) WeakPointerCleared = true;
    586   p->first->Reset();
    587 }
    588 
    589 
    590 TEST(WeakGlobalHandlesScavenge) {
    591   i::FLAG_stress_compaction = false;
    592   CcTest::InitializeVM();
    593   Isolate* isolate = CcTest::i_isolate();
    594   Heap* heap = isolate->heap();
    595   Factory* factory = isolate->factory();
    596   GlobalHandles* global_handles = isolate->global_handles();
    597 
    598   WeakPointerCleared = false;
    599 
    600   Handle<Object> h1;
    601   Handle<Object> h2;
    602 
    603   {
    604     HandleScope scope(isolate);
    605 
    606     Handle<Object> i = factory->NewStringFromStaticChars("fisk");
    607     Handle<Object> u = factory->NewNumber(1.12344);
    608 
    609     h1 = global_handles->Create(*i);
    610     h2 = global_handles->Create(*u);
    611   }
    612 
    613   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
    614   GlobalHandles::MakeWeak(
    615       h2.location(), reinterpret_cast<void*>(&handle_and_id),
    616       &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter);
    617 
    618   // Scavenge treats weak pointers as normal roots.
    619   heap->CollectGarbage(NEW_SPACE);
    620 
    621   CHECK((*h1)->IsString());
    622   CHECK((*h2)->IsHeapNumber());
    623 
    624   CHECK(!WeakPointerCleared);
    625   CHECK(!global_handles->IsNearDeath(h2.location()));
    626   CHECK(!global_handles->IsNearDeath(h1.location()));
    627 
    628   GlobalHandles::Destroy(h1.location());
    629   GlobalHandles::Destroy(h2.location());
    630 }
    631 
    632 
    633 TEST(WeakGlobalHandlesMark) {
    634   CcTest::InitializeVM();
    635   Isolate* isolate = CcTest::i_isolate();
    636   Heap* heap = isolate->heap();
    637   Factory* factory = isolate->factory();
    638   GlobalHandles* global_handles = isolate->global_handles();
    639 
    640   WeakPointerCleared = false;
    641 
    642   Handle<Object> h1;
    643   Handle<Object> h2;
    644 
    645   {
    646     HandleScope scope(isolate);
    647 
    648     Handle<Object> i = factory->NewStringFromStaticChars("fisk");
    649     Handle<Object> u = factory->NewNumber(1.12344);
    650 
    651     h1 = global_handles->Create(*i);
    652     h2 = global_handles->Create(*u);
    653   }
    654 
    655   // Make sure the objects are promoted.
    656   heap->CollectGarbage(OLD_SPACE);
    657   heap->CollectGarbage(NEW_SPACE);
    658   CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
    659 
    660   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
    661   GlobalHandles::MakeWeak(
    662       h2.location(), reinterpret_cast<void*>(&handle_and_id),
    663       &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter);
    664   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
    665   CHECK(!GlobalHandles::IsNearDeath(h2.location()));
    666 
    667   // Incremental marking potentially marked handles before they turned weak.
    668   heap->CollectAllGarbage();
    669 
    670   CHECK((*h1)->IsString());
    671 
    672   CHECK(WeakPointerCleared);
    673   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
    674 
    675   GlobalHandles::Destroy(h1.location());
    676 }
    677 
    678 
    679 TEST(DeleteWeakGlobalHandle) {
    680   i::FLAG_stress_compaction = false;
    681   CcTest::InitializeVM();
    682   Isolate* isolate = CcTest::i_isolate();
    683   Heap* heap = isolate->heap();
    684   Factory* factory = isolate->factory();
    685   GlobalHandles* global_handles = isolate->global_handles();
    686 
    687   WeakPointerCleared = false;
    688 
    689   Handle<Object> h;
    690 
    691   {
    692     HandleScope scope(isolate);
    693 
    694     Handle<Object> i = factory->NewStringFromStaticChars("fisk");
    695     h = global_handles->Create(*i);
    696   }
    697 
    698   std::pair<Handle<Object>*, int> handle_and_id(&h, 1234);
    699   GlobalHandles::MakeWeak(h.location(), reinterpret_cast<void*>(&handle_and_id),
    700                           &TestWeakGlobalHandleCallback,
    701                           v8::WeakCallbackType::kParameter);
    702 
    703   // Scanvenge does not recognize weak reference.
    704   heap->CollectGarbage(NEW_SPACE);
    705 
    706   CHECK(!WeakPointerCleared);
    707 
    708   // Mark-compact treats weak reference properly.
    709   heap->CollectGarbage(OLD_SPACE);
    710 
    711   CHECK(WeakPointerCleared);
    712 }
    713 
    714 TEST(DoNotPromoteWhiteObjectsOnScavenge) {
    715   CcTest::InitializeVM();
    716   Isolate* isolate = CcTest::i_isolate();
    717   Heap* heap = isolate->heap();
    718   Factory* factory = isolate->factory();
    719 
    720   HandleScope scope(isolate);
    721   Handle<Object> white = factory->NewStringFromStaticChars("white");
    722 
    723   CHECK(Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(*white))));
    724 
    725   heap->CollectGarbage(NEW_SPACE);
    726 
    727   CHECK(heap->InNewSpace(*white));
    728 }
    729 
    730 TEST(PromoteGreyOrBlackObjectsOnScavenge) {
    731   CcTest::InitializeVM();
    732   Isolate* isolate = CcTest::i_isolate();
    733   Heap* heap = isolate->heap();
    734   Factory* factory = isolate->factory();
    735 
    736   HandleScope scope(isolate);
    737   Handle<Object> marked = factory->NewStringFromStaticChars("marked");
    738 
    739   IncrementalMarking* marking = heap->incremental_marking();
    740   marking->Stop();
    741   heap->StartIncrementalMarking();
    742   while (Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(*marked)))) {
    743     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
    744                   IncrementalMarking::FORCE_MARKING,
    745                   IncrementalMarking::DO_NOT_FORCE_COMPLETION);
    746   }
    747 
    748   heap->CollectGarbage(NEW_SPACE);
    749 
    750   CHECK(!heap->InNewSpace(*marked));
    751 }
    752 
    753 TEST(BytecodeArray) {
    754   static const uint8_t kRawBytes[] = {0xc3, 0x7e, 0xa5, 0x5a};
    755   static const int kRawBytesSize = sizeof(kRawBytes);
    756   static const int kFrameSize = 32;
    757   static const int kParameterCount = 2;
    758 
    759   i::FLAG_manual_evacuation_candidates_selection = true;
    760   CcTest::InitializeVM();
    761   Isolate* isolate = CcTest::i_isolate();
    762   Heap* heap = isolate->heap();
    763   Factory* factory = isolate->factory();
    764   HandleScope scope(isolate);
    765 
    766   heap::SimulateFullSpace(heap->old_space());
    767   Handle<FixedArray> constant_pool = factory->NewFixedArray(5, TENURED);
    768   for (int i = 0; i < 5; i++) {
    769     Handle<Object> number = factory->NewHeapNumber(i);
    770     constant_pool->set(i, *number);
    771   }
    772 
    773   // Allocate and initialize BytecodeArray
    774   Handle<BytecodeArray> array = factory->NewBytecodeArray(
    775       kRawBytesSize, kRawBytes, kFrameSize, kParameterCount, constant_pool);
    776 
    777   CHECK(array->IsBytecodeArray());
    778   CHECK_EQ(array->length(), (int)sizeof(kRawBytes));
    779   CHECK_EQ(array->frame_size(), kFrameSize);
    780   CHECK_EQ(array->parameter_count(), kParameterCount);
    781   CHECK_EQ(array->constant_pool(), *constant_pool);
    782   CHECK_LE(array->address(), array->GetFirstBytecodeAddress());
    783   CHECK_GE(array->address() + array->BytecodeArraySize(),
    784            array->GetFirstBytecodeAddress() + array->length());
    785   for (int i = 0; i < kRawBytesSize; i++) {
    786     CHECK_EQ(array->GetFirstBytecodeAddress()[i], kRawBytes[i]);
    787     CHECK_EQ(array->get(i), kRawBytes[i]);
    788   }
    789 
    790   FixedArray* old_constant_pool_address = *constant_pool;
    791 
    792   // Perform a full garbage collection and force the constant pool to be on an
    793   // evacuation candidate.
    794   Page* evac_page = Page::FromAddress(constant_pool->address());
    795   evac_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
    796   heap->CollectAllGarbage();
    797 
    798   // BytecodeArray should survive.
    799   CHECK_EQ(array->length(), kRawBytesSize);
    800   CHECK_EQ(array->frame_size(), kFrameSize);
    801   for (int i = 0; i < kRawBytesSize; i++) {
    802     CHECK_EQ(array->get(i), kRawBytes[i]);
    803     CHECK_EQ(array->GetFirstBytecodeAddress()[i], kRawBytes[i]);
    804   }
    805 
    806   // Constant pool should have been migrated.
    807   CHECK_EQ(array->constant_pool(), *constant_pool);
    808   CHECK_NE(array->constant_pool(), old_constant_pool_address);
    809 }
    810 
    811 
    812 static const char* not_so_random_string_table[] = {
    813   "abstract",
    814   "boolean",
    815   "break",
    816   "byte",
    817   "case",
    818   "catch",
    819   "char",
    820   "class",
    821   "const",
    822   "continue",
    823   "debugger",
    824   "default",
    825   "delete",
    826   "do",
    827   "double",
    828   "else",
    829   "enum",
    830   "export",
    831   "extends",
    832   "false",
    833   "final",
    834   "finally",
    835   "float",
    836   "for",
    837   "function",
    838   "goto",
    839   "if",
    840   "implements",
    841   "import",
    842   "in",
    843   "instanceof",
    844   "int",
    845   "interface",
    846   "long",
    847   "native",
    848   "new",
    849   "null",
    850   "package",
    851   "private",
    852   "protected",
    853   "public",
    854   "return",
    855   "short",
    856   "static",
    857   "super",
    858   "switch",
    859   "synchronized",
    860   "this",
    861   "throw",
    862   "throws",
    863   "transient",
    864   "true",
    865   "try",
    866   "typeof",
    867   "var",
    868   "void",
    869   "volatile",
    870   "while",
    871   "with",
    872   0
    873 };
    874 
    875 
    876 static void CheckInternalizedStrings(const char** strings) {
    877   Isolate* isolate = CcTest::i_isolate();
    878   Factory* factory = isolate->factory();
    879   for (const char* string = *strings; *strings != 0; string = *strings++) {
    880     HandleScope scope(isolate);
    881     Handle<String> a =
    882         isolate->factory()->InternalizeUtf8String(CStrVector(string));
    883     // InternalizeUtf8String may return a failure if a GC is needed.
    884     CHECK(a->IsInternalizedString());
    885     Handle<String> b = factory->InternalizeUtf8String(string);
    886     CHECK_EQ(*b, *a);
    887     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
    888     b = isolate->factory()->InternalizeUtf8String(CStrVector(string));
    889     CHECK_EQ(*b, *a);
    890     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
    891   }
    892 }
    893 
    894 
    895 TEST(StringTable) {
    896   CcTest::InitializeVM();
    897 
    898   v8::HandleScope sc(CcTest::isolate());
    899   CheckInternalizedStrings(not_so_random_string_table);
    900   CheckInternalizedStrings(not_so_random_string_table);
    901 }
    902 
    903 
    904 TEST(FunctionAllocation) {
    905   CcTest::InitializeVM();
    906   Isolate* isolate = CcTest::i_isolate();
    907   Factory* factory = isolate->factory();
    908 
    909   v8::HandleScope sc(CcTest::isolate());
    910   Handle<String> name = factory->InternalizeUtf8String("theFunction");
    911   Handle<JSFunction> function = factory->NewFunction(name);
    912 
    913   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
    914   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
    915 
    916   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
    917   Handle<JSObject> obj = factory->NewJSObject(function);
    918   JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check();
    919   CHECK_EQ(Smi::FromInt(23),
    920            *Object::GetProperty(obj, prop_name).ToHandleChecked());
    921   // Check that we can add properties to function objects.
    922   JSReceiver::SetProperty(function, prop_name, twenty_four, SLOPPY).Check();
    923   CHECK_EQ(Smi::FromInt(24),
    924            *Object::GetProperty(function, prop_name).ToHandleChecked());
    925 }
    926 
    927 
    928 TEST(ObjectProperties) {
    929   CcTest::InitializeVM();
    930   Isolate* isolate = CcTest::i_isolate();
    931   Factory* factory = isolate->factory();
    932 
    933   v8::HandleScope sc(CcTest::isolate());
    934   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
    935   Handle<Object> object = Object::GetProperty(
    936       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
    937   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
    938   Handle<JSObject> obj = factory->NewJSObject(constructor);
    939   Handle<String> first = factory->InternalizeUtf8String("first");
    940   Handle<String> second = factory->InternalizeUtf8String("second");
    941 
    942   Handle<Smi> one(Smi::FromInt(1), isolate);
    943   Handle<Smi> two(Smi::FromInt(2), isolate);
    944 
    945   // check for empty
    946   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
    947 
    948   // add first
    949   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
    950   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
    951 
    952   // delete first
    953   CHECK(Just(true) == JSReceiver::DeleteProperty(obj, first, SLOPPY));
    954   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
    955 
    956   // add first and then second
    957   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
    958   JSReceiver::SetProperty(obj, second, two, SLOPPY).Check();
    959   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
    960   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
    961 
    962   // delete first and then second
    963   CHECK(Just(true) == JSReceiver::DeleteProperty(obj, first, SLOPPY));
    964   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
    965   CHECK(Just(true) == JSReceiver::DeleteProperty(obj, second, SLOPPY));
    966   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
    967   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second));
    968 
    969   // add first and then second
    970   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
    971   JSReceiver::SetProperty(obj, second, two, SLOPPY).Check();
    972   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
    973   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
    974 
    975   // delete second and then first
    976   CHECK(Just(true) == JSReceiver::DeleteProperty(obj, second, SLOPPY));
    977   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
    978   CHECK(Just(true) == JSReceiver::DeleteProperty(obj, first, SLOPPY));
    979   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
    980   CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second));
    981 
    982   // check string and internalized string match
    983   const char* string1 = "fisk";
    984   Handle<String> s1 = factory->NewStringFromAsciiChecked(string1);
    985   JSReceiver::SetProperty(obj, s1, one, SLOPPY).Check();
    986   Handle<String> s1_string = factory->InternalizeUtf8String(string1);
    987   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s1_string));
    988 
    989   // check internalized string and string match
    990   const char* string2 = "fugl";
    991   Handle<String> s2_string = factory->InternalizeUtf8String(string2);
    992   JSReceiver::SetProperty(obj, s2_string, one, SLOPPY).Check();
    993   Handle<String> s2 = factory->NewStringFromAsciiChecked(string2);
    994   CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s2));
    995 }
    996 
    997 
    998 TEST(JSObjectMaps) {
    999   CcTest::InitializeVM();
   1000   Isolate* isolate = CcTest::i_isolate();
   1001   Factory* factory = isolate->factory();
   1002 
   1003   v8::HandleScope sc(CcTest::isolate());
   1004   Handle<String> name = factory->InternalizeUtf8String("theFunction");
   1005   Handle<JSFunction> function = factory->NewFunction(name);
   1006 
   1007   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
   1008   Handle<JSObject> obj = factory->NewJSObject(function);
   1009   Handle<Map> initial_map(function->initial_map());
   1010 
   1011   // Set a propery
   1012   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
   1013   JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check();
   1014   CHECK_EQ(Smi::FromInt(23),
   1015            *Object::GetProperty(obj, prop_name).ToHandleChecked());
   1016 
   1017   // Check the map has changed
   1018   CHECK(*initial_map != obj->map());
   1019 }
   1020 
   1021 
   1022 TEST(JSArray) {
   1023   CcTest::InitializeVM();
   1024   Isolate* isolate = CcTest::i_isolate();
   1025   Factory* factory = isolate->factory();
   1026 
   1027   v8::HandleScope sc(CcTest::isolate());
   1028   Handle<String> name = factory->InternalizeUtf8String("Array");
   1029   Handle<Object> fun_obj = Object::GetProperty(
   1030       CcTest::i_isolate()->global_object(), name).ToHandleChecked();
   1031   Handle<JSFunction> function = Handle<JSFunction>::cast(fun_obj);
   1032 
   1033   // Allocate the object.
   1034   Handle<Object> element;
   1035   Handle<JSObject> object = factory->NewJSObject(function);
   1036   Handle<JSArray> array = Handle<JSArray>::cast(object);
   1037   // We just initialized the VM, no heap allocation failure yet.
   1038   JSArray::Initialize(array, 0);
   1039 
   1040   // Set array length to 0.
   1041   JSArray::SetLength(array, 0);
   1042   CHECK_EQ(Smi::FromInt(0), array->length());
   1043   // Must be in fast mode.
   1044   CHECK(array->HasFastSmiOrObjectElements());
   1045 
   1046   // array[length] = name.
   1047   JSReceiver::SetElement(isolate, array, 0, name, SLOPPY).Check();
   1048   CHECK_EQ(Smi::FromInt(1), array->length());
   1049   element = i::Object::GetElement(isolate, array, 0).ToHandleChecked();
   1050   CHECK_EQ(*element, *name);
   1051 
   1052   // Set array length with larger than smi value.
   1053   JSArray::SetLength(array, static_cast<uint32_t>(Smi::kMaxValue) + 1);
   1054 
   1055   uint32_t int_length = 0;
   1056   CHECK(array->length()->ToArrayIndex(&int_length));
   1057   CHECK_EQ(static_cast<uint32_t>(Smi::kMaxValue) + 1, int_length);
   1058   CHECK(array->HasDictionaryElements());  // Must be in slow mode.
   1059 
   1060   // array[length] = name.
   1061   JSReceiver::SetElement(isolate, array, int_length, name, SLOPPY).Check();
   1062   uint32_t new_int_length = 0;
   1063   CHECK(array->length()->ToArrayIndex(&new_int_length));
   1064   CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
   1065   element = Object::GetElement(isolate, array, int_length).ToHandleChecked();
   1066   CHECK_EQ(*element, *name);
   1067   element = Object::GetElement(isolate, array, 0).ToHandleChecked();
   1068   CHECK_EQ(*element, *name);
   1069 }
   1070 
   1071 
   1072 TEST(JSObjectCopy) {
   1073   CcTest::InitializeVM();
   1074   Isolate* isolate = CcTest::i_isolate();
   1075   Factory* factory = isolate->factory();
   1076 
   1077   v8::HandleScope sc(CcTest::isolate());
   1078   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
   1079   Handle<Object> object = Object::GetProperty(
   1080       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
   1081   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
   1082   Handle<JSObject> obj = factory->NewJSObject(constructor);
   1083   Handle<String> first = factory->InternalizeUtf8String("first");
   1084   Handle<String> second = factory->InternalizeUtf8String("second");
   1085 
   1086   Handle<Smi> one(Smi::FromInt(1), isolate);
   1087   Handle<Smi> two(Smi::FromInt(2), isolate);
   1088 
   1089   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
   1090   JSReceiver::SetProperty(obj, second, two, SLOPPY).Check();
   1091 
   1092   JSReceiver::SetElement(isolate, obj, 0, first, SLOPPY).Check();
   1093   JSReceiver::SetElement(isolate, obj, 1, second, SLOPPY).Check();
   1094 
   1095   // Make the clone.
   1096   Handle<Object> value1, value2;
   1097   Handle<JSObject> clone = factory->CopyJSObject(obj);
   1098   CHECK(!clone.is_identical_to(obj));
   1099 
   1100   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
   1101   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
   1102   CHECK_EQ(*value1, *value2);
   1103   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
   1104   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
   1105   CHECK_EQ(*value1, *value2);
   1106 
   1107   value1 = Object::GetProperty(obj, first).ToHandleChecked();
   1108   value2 = Object::GetProperty(clone, first).ToHandleChecked();
   1109   CHECK_EQ(*value1, *value2);
   1110   value1 = Object::GetProperty(obj, second).ToHandleChecked();
   1111   value2 = Object::GetProperty(clone, second).ToHandleChecked();
   1112   CHECK_EQ(*value1, *value2);
   1113 
   1114   // Flip the values.
   1115   JSReceiver::SetProperty(clone, first, two, SLOPPY).Check();
   1116   JSReceiver::SetProperty(clone, second, one, SLOPPY).Check();
   1117 
   1118   JSReceiver::SetElement(isolate, clone, 0, second, SLOPPY).Check();
   1119   JSReceiver::SetElement(isolate, clone, 1, first, SLOPPY).Check();
   1120 
   1121   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
   1122   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
   1123   CHECK_EQ(*value1, *value2);
   1124   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
   1125   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
   1126   CHECK_EQ(*value1, *value2);
   1127 
   1128   value1 = Object::GetProperty(obj, second).ToHandleChecked();
   1129   value2 = Object::GetProperty(clone, first).ToHandleChecked();
   1130   CHECK_EQ(*value1, *value2);
   1131   value1 = Object::GetProperty(obj, first).ToHandleChecked();
   1132   value2 = Object::GetProperty(clone, second).ToHandleChecked();
   1133   CHECK_EQ(*value1, *value2);
   1134 }
   1135 
   1136 
   1137 TEST(StringAllocation) {
   1138   CcTest::InitializeVM();
   1139   Isolate* isolate = CcTest::i_isolate();
   1140   Factory* factory = isolate->factory();
   1141 
   1142   const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
   1143   for (int length = 0; length < 100; length++) {
   1144     v8::HandleScope scope(CcTest::isolate());
   1145     char* non_one_byte = NewArray<char>(3 * length + 1);
   1146     char* one_byte = NewArray<char>(length + 1);
   1147     non_one_byte[3 * length] = 0;
   1148     one_byte[length] = 0;
   1149     for (int i = 0; i < length; i++) {
   1150       one_byte[i] = 'a';
   1151       non_one_byte[3 * i] = chars[0];
   1152       non_one_byte[3 * i + 1] = chars[1];
   1153       non_one_byte[3 * i + 2] = chars[2];
   1154     }
   1155     Handle<String> non_one_byte_sym = factory->InternalizeUtf8String(
   1156         Vector<const char>(non_one_byte, 3 * length));
   1157     CHECK_EQ(length, non_one_byte_sym->length());
   1158     Handle<String> one_byte_sym =
   1159         factory->InternalizeOneByteString(OneByteVector(one_byte, length));
   1160     CHECK_EQ(length, one_byte_sym->length());
   1161     Handle<String> non_one_byte_str =
   1162         factory->NewStringFromUtf8(Vector<const char>(non_one_byte, 3 * length))
   1163             .ToHandleChecked();
   1164     non_one_byte_str->Hash();
   1165     CHECK_EQ(length, non_one_byte_str->length());
   1166     Handle<String> one_byte_str =
   1167         factory->NewStringFromUtf8(Vector<const char>(one_byte, length))
   1168             .ToHandleChecked();
   1169     one_byte_str->Hash();
   1170     CHECK_EQ(length, one_byte_str->length());
   1171     DeleteArray(non_one_byte);
   1172     DeleteArray(one_byte);
   1173   }
   1174 }
   1175 
   1176 
   1177 static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
   1178   // Count the number of objects found in the heap.
   1179   int found_count = 0;
   1180   HeapIterator iterator(heap);
   1181   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
   1182     for (int i = 0; i < size; i++) {
   1183       if (*objs[i] == obj) {
   1184         found_count++;
   1185       }
   1186     }
   1187   }
   1188   return found_count;
   1189 }
   1190 
   1191 
   1192 TEST(Iteration) {
   1193   CcTest::InitializeVM();
   1194   Isolate* isolate = CcTest::i_isolate();
   1195   Factory* factory = isolate->factory();
   1196   v8::HandleScope scope(CcTest::isolate());
   1197 
   1198   // Array of objects to scan haep for.
   1199   const int objs_count = 6;
   1200   Handle<Object> objs[objs_count];
   1201   int next_objs_index = 0;
   1202 
   1203   // Allocate a JS array to OLD_SPACE and NEW_SPACE
   1204   objs[next_objs_index++] = factory->NewJSArray(10);
   1205   objs[next_objs_index++] =
   1206       factory->NewJSArray(10, FAST_HOLEY_ELEMENTS, TENURED);
   1207 
   1208   // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
   1209   objs[next_objs_index++] = factory->NewStringFromStaticChars("abcdefghij");
   1210   objs[next_objs_index++] =
   1211       factory->NewStringFromStaticChars("abcdefghij", TENURED);
   1212 
   1213   // Allocate a large string (for large object space).
   1214   int large_size = Page::kMaxRegularHeapObjectSize + 1;
   1215   char* str = new char[large_size];
   1216   for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
   1217   str[large_size - 1] = '\0';
   1218   objs[next_objs_index++] = factory->NewStringFromAsciiChecked(str, TENURED);
   1219   delete[] str;
   1220 
   1221   // Add a Map object to look for.
   1222   objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
   1223 
   1224   CHECK_EQ(objs_count, next_objs_index);
   1225   CHECK_EQ(objs_count, ObjectsFoundInHeap(CcTest::heap(), objs, objs_count));
   1226 }
   1227 
   1228 
   1229 UNINITIALIZED_TEST(TestCodeFlushing) {
   1230   // If we do not flush code this test is invalid.
   1231   if (!FLAG_flush_code) return;
   1232   i::FLAG_allow_natives_syntax = true;
   1233   i::FLAG_optimize_for_size = false;
   1234   v8::Isolate::CreateParams create_params;
   1235   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
   1236   v8::Isolate* isolate = v8::Isolate::New(create_params);
   1237   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   1238   isolate->Enter();
   1239   Factory* factory = i_isolate->factory();
   1240   {
   1241     v8::HandleScope scope(isolate);
   1242     v8::Context::New(isolate)->Enter();
   1243     const char* source =
   1244         "function foo() {"
   1245         "  var x = 42;"
   1246         "  var y = 42;"
   1247         "  var z = x + y;"
   1248         "};"
   1249         "foo()";
   1250     Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1251 
   1252     // This compile will add the code to the compilation cache.
   1253     {
   1254       v8::HandleScope scope(isolate);
   1255       CompileRun(source);
   1256     }
   1257 
   1258     // Check function is compiled.
   1259     Handle<Object> func_value = Object::GetProperty(i_isolate->global_object(),
   1260                                                     foo_name).ToHandleChecked();
   1261     CHECK(func_value->IsJSFunction());
   1262     Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1263     CHECK(function->shared()->is_compiled());
   1264 
   1265     // The code will survive at least two GCs.
   1266     i_isolate->heap()->CollectAllGarbage();
   1267     i_isolate->heap()->CollectAllGarbage();
   1268     CHECK(function->shared()->is_compiled());
   1269 
   1270     // Simulate several GCs that use full marking.
   1271     const int kAgingThreshold = 6;
   1272     for (int i = 0; i < kAgingThreshold; i++) {
   1273       i_isolate->heap()->CollectAllGarbage();
   1274     }
   1275 
   1276     // foo should no longer be in the compilation cache
   1277     CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1278     CHECK(!function->is_compiled() || function->IsOptimized());
   1279     // Call foo to get it recompiled.
   1280     CompileRun("foo()");
   1281     CHECK(function->shared()->is_compiled());
   1282     CHECK(function->is_compiled());
   1283   }
   1284   isolate->Exit();
   1285   isolate->Dispose();
   1286 }
   1287 
   1288 
   1289 TEST(TestCodeFlushingPreAged) {
   1290   // If we do not flush code this test is invalid.
   1291   if (!FLAG_flush_code) return;
   1292   i::FLAG_allow_natives_syntax = true;
   1293   i::FLAG_optimize_for_size = true;
   1294   CcTest::InitializeVM();
   1295   Isolate* isolate = CcTest::i_isolate();
   1296   Factory* factory = isolate->factory();
   1297   v8::HandleScope scope(CcTest::isolate());
   1298   const char* source = "function foo() {"
   1299                        "  var x = 42;"
   1300                        "  var y = 42;"
   1301                        "  var z = x + y;"
   1302                        "};"
   1303                        "foo()";
   1304   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1305 
   1306   // Compile foo, but don't run it.
   1307   { v8::HandleScope scope(CcTest::isolate());
   1308     CompileRun(source);
   1309   }
   1310 
   1311   // Check function is compiled.
   1312   Handle<Object> func_value =
   1313       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1314   CHECK(func_value->IsJSFunction());
   1315   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1316   CHECK(function->shared()->is_compiled());
   1317 
   1318   // The code has been run so will survive at least one GC.
   1319   CcTest::heap()->CollectAllGarbage();
   1320   CHECK(function->shared()->is_compiled());
   1321 
   1322   // The code was only run once, so it should be pre-aged and collected on the
   1323   // next GC.
   1324   CcTest::heap()->CollectAllGarbage();
   1325   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1326 
   1327   // Execute the function again twice, and ensure it is reset to the young age.
   1328   { v8::HandleScope scope(CcTest::isolate());
   1329     CompileRun("foo();"
   1330                "foo();");
   1331   }
   1332 
   1333   // The code will survive at least two GC now that it is young again.
   1334   CcTest::heap()->CollectAllGarbage();
   1335   CcTest::heap()->CollectAllGarbage();
   1336   CHECK(function->shared()->is_compiled());
   1337 
   1338   // Simulate several GCs that use full marking.
   1339   const int kAgingThreshold = 6;
   1340   for (int i = 0; i < kAgingThreshold; i++) {
   1341     CcTest::heap()->CollectAllGarbage();
   1342   }
   1343 
   1344   // foo should no longer be in the compilation cache
   1345   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1346   CHECK(!function->is_compiled() || function->IsOptimized());
   1347   // Call foo to get it recompiled.
   1348   CompileRun("foo()");
   1349   CHECK(function->shared()->is_compiled());
   1350   CHECK(function->is_compiled());
   1351 }
   1352 
   1353 
   1354 TEST(TestCodeFlushingIncremental) {
   1355   // If we do not flush code this test is invalid.
   1356   if (!FLAG_flush_code) return;
   1357   i::FLAG_allow_natives_syntax = true;
   1358   i::FLAG_optimize_for_size = false;
   1359   CcTest::InitializeVM();
   1360   Isolate* isolate = CcTest::i_isolate();
   1361   Factory* factory = isolate->factory();
   1362   v8::HandleScope scope(CcTest::isolate());
   1363   const char* source = "function foo() {"
   1364                        "  var x = 42;"
   1365                        "  var y = 42;"
   1366                        "  var z = x + y;"
   1367                        "};"
   1368                        "foo()";
   1369   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1370 
   1371   // This compile will add the code to the compilation cache.
   1372   { v8::HandleScope scope(CcTest::isolate());
   1373     CompileRun(source);
   1374   }
   1375 
   1376   // Check function is compiled.
   1377   Handle<Object> func_value =
   1378       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1379   CHECK(func_value->IsJSFunction());
   1380   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1381   CHECK(function->shared()->is_compiled());
   1382 
   1383   // The code will survive at least two GCs.
   1384   CcTest::heap()->CollectAllGarbage();
   1385   CcTest::heap()->CollectAllGarbage();
   1386   CHECK(function->shared()->is_compiled());
   1387 
   1388   // Simulate several GCs that use incremental marking.
   1389   const int kAgingThreshold = 6;
   1390   for (int i = 0; i < kAgingThreshold; i++) {
   1391     heap::SimulateIncrementalMarking(CcTest::heap());
   1392     CcTest::heap()->CollectAllGarbage();
   1393   }
   1394   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1395   CHECK(!function->is_compiled() || function->IsOptimized());
   1396 
   1397   // This compile will compile the function again.
   1398   { v8::HandleScope scope(CcTest::isolate());
   1399     CompileRun("foo();");
   1400   }
   1401 
   1402   // Simulate several GCs that use incremental marking but make sure
   1403   // the loop breaks once the function is enqueued as a candidate.
   1404   for (int i = 0; i < kAgingThreshold; i++) {
   1405     heap::SimulateIncrementalMarking(CcTest::heap());
   1406     if (!function->next_function_link()->IsUndefined(CcTest::i_isolate()))
   1407       break;
   1408     CcTest::heap()->CollectAllGarbage();
   1409   }
   1410 
   1411   // Force optimization while incremental marking is active and while
   1412   // the function is enqueued as a candidate.
   1413   { v8::HandleScope scope(CcTest::isolate());
   1414     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   1415   }
   1416 
   1417   // Simulate one final GC to make sure the candidate queue is sane.
   1418   CcTest::heap()->CollectAllGarbage();
   1419   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
   1420   CHECK(function->is_compiled() || !function->IsOptimized());
   1421 }
   1422 
   1423 
   1424 TEST(TestCodeFlushingIncrementalScavenge) {
   1425   // If we do not flush code this test is invalid.
   1426   if (!FLAG_flush_code) return;
   1427   i::FLAG_allow_natives_syntax = true;
   1428   i::FLAG_optimize_for_size = false;
   1429   CcTest::InitializeVM();
   1430   Isolate* isolate = CcTest::i_isolate();
   1431   Factory* factory = isolate->factory();
   1432   v8::HandleScope scope(CcTest::isolate());
   1433   const char* source = "var foo = function() {"
   1434                        "  var x = 42;"
   1435                        "  var y = 42;"
   1436                        "  var z = x + y;"
   1437                        "};"
   1438                        "foo();"
   1439                        "var bar = function() {"
   1440                        "  var x = 23;"
   1441                        "};"
   1442                        "bar();";
   1443   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1444   Handle<String> bar_name = factory->InternalizeUtf8String("bar");
   1445 
   1446   // Perfrom one initial GC to enable code flushing.
   1447   CcTest::heap()->CollectAllGarbage();
   1448 
   1449   // This compile will add the code to the compilation cache.
   1450   { v8::HandleScope scope(CcTest::isolate());
   1451     CompileRun(source);
   1452   }
   1453 
   1454   // Check functions are compiled.
   1455   Handle<Object> func_value =
   1456       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1457   CHECK(func_value->IsJSFunction());
   1458   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1459   CHECK(function->shared()->is_compiled());
   1460   Handle<Object> func_value2 =
   1461       Object::GetProperty(isolate->global_object(), bar_name).ToHandleChecked();
   1462   CHECK(func_value2->IsJSFunction());
   1463   Handle<JSFunction> function2 = Handle<JSFunction>::cast(func_value2);
   1464   CHECK(function2->shared()->is_compiled());
   1465 
   1466   // Clear references to functions so that one of them can die.
   1467   { v8::HandleScope scope(CcTest::isolate());
   1468     CompileRun("foo = 0; bar = 0;");
   1469   }
   1470 
   1471   // Bump the code age so that flushing is triggered while the function
   1472   // object is still located in new-space.
   1473   const int kAgingThreshold = 6;
   1474   for (int i = 0; i < kAgingThreshold; i++) {
   1475     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1476     function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1477   }
   1478 
   1479   // Simulate incremental marking so that the functions are enqueued as
   1480   // code flushing candidates. Then kill one of the functions. Finally
   1481   // perform a scavenge while incremental marking is still running.
   1482   heap::SimulateIncrementalMarking(CcTest::heap());
   1483   *function2.location() = NULL;
   1484   CcTest::heap()->CollectGarbage(NEW_SPACE, "test scavenge while marking");
   1485 
   1486   // Simulate one final GC to make sure the candidate queue is sane.
   1487   CcTest::heap()->CollectAllGarbage();
   1488   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   1489   CHECK(!function->is_compiled() || function->IsOptimized());
   1490 }
   1491 
   1492 
   1493 TEST(TestCodeFlushingIncrementalAbort) {
   1494   // If we do not flush code this test is invalid.
   1495   if (!FLAG_flush_code) return;
   1496   i::FLAG_allow_natives_syntax = true;
   1497   i::FLAG_optimize_for_size = false;
   1498   CcTest::InitializeVM();
   1499   Isolate* isolate = CcTest::i_isolate();
   1500   Factory* factory = isolate->factory();
   1501   Heap* heap = isolate->heap();
   1502   v8::HandleScope scope(CcTest::isolate());
   1503   const char* source = "function foo() {"
   1504                        "  var x = 42;"
   1505                        "  var y = 42;"
   1506                        "  var z = x + y;"
   1507                        "};"
   1508                        "foo()";
   1509   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
   1510 
   1511   // This compile will add the code to the compilation cache.
   1512   { v8::HandleScope scope(CcTest::isolate());
   1513     CompileRun(source);
   1514   }
   1515 
   1516   // Check function is compiled.
   1517   Handle<Object> func_value =
   1518       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
   1519   CHECK(func_value->IsJSFunction());
   1520   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
   1521   CHECK(function->shared()->is_compiled());
   1522 
   1523   // The code will survive at least two GCs.
   1524   heap->CollectAllGarbage();
   1525   heap->CollectAllGarbage();
   1526   CHECK(function->shared()->is_compiled());
   1527 
   1528   // Bump the code age so that flushing is triggered.
   1529   const int kAgingThreshold = 6;
   1530   for (int i = 0; i < kAgingThreshold; i++) {
   1531     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   1532   }
   1533 
   1534   // Simulate incremental marking so that the function is enqueued as
   1535   // code flushing candidate.
   1536   heap::SimulateIncrementalMarking(heap);
   1537 
   1538   // Enable the debugger and add a breakpoint while incremental marking
   1539   // is running so that incremental marking aborts and code flushing is
   1540   // disabled.
   1541   int position = 0;
   1542   Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
   1543   EnableDebugger(CcTest::isolate());
   1544   isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
   1545   isolate->debug()->ClearAllBreakPoints();
   1546   DisableDebugger(CcTest::isolate());
   1547 
   1548   // Force optimization now that code flushing is disabled.
   1549   { v8::HandleScope scope(CcTest::isolate());
   1550     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   1551   }
   1552 
   1553   // Simulate one final GC to make sure the candidate queue is sane.
   1554   heap->CollectAllGarbage();
   1555   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
   1556   CHECK(function->is_compiled() || !function->IsOptimized());
   1557 }
   1558 
   1559 TEST(TestUseOfIncrementalBarrierOnCompileLazy) {
   1560   // Turn off always_opt because it interferes with running the built-in for
   1561   // the last call to g().
   1562   i::FLAG_always_opt = false;
   1563   i::FLAG_allow_natives_syntax = true;
   1564   CcTest::InitializeVM();
   1565   Isolate* isolate = CcTest::i_isolate();
   1566   Factory* factory = isolate->factory();
   1567   Heap* heap = isolate->heap();
   1568   v8::HandleScope scope(CcTest::isolate());
   1569 
   1570   CompileRun(
   1571       "function make_closure(x) {"
   1572       "  return function() { return x + 3 };"
   1573       "}"
   1574       "var f = make_closure(5); f();"
   1575       "var g = make_closure(5);");
   1576 
   1577   // Check f is compiled.
   1578   Handle<String> f_name = factory->InternalizeUtf8String("f");
   1579   Handle<Object> f_value =
   1580       Object::GetProperty(isolate->global_object(), f_name).ToHandleChecked();
   1581   Handle<JSFunction> f_function = Handle<JSFunction>::cast(f_value);
   1582   CHECK(f_function->is_compiled());
   1583 
   1584   // Check g is not compiled.
   1585   Handle<String> g_name = factory->InternalizeUtf8String("g");
   1586   Handle<Object> g_value =
   1587       Object::GetProperty(isolate->global_object(), g_name).ToHandleChecked();
   1588   Handle<JSFunction> g_function = Handle<JSFunction>::cast(g_value);
   1589   CHECK(!g_function->is_compiled());
   1590 
   1591   heap::SimulateIncrementalMarking(heap);
   1592   CompileRun("%OptimizeFunctionOnNextCall(f); f();");
   1593 
   1594   // g should now have available an optimized function, unmarked by gc. The
   1595   // CompileLazy built-in will discover it and install it in the closure, and
   1596   // the incremental write barrier should be used.
   1597   CompileRun("g();");
   1598   CHECK(g_function->is_compiled());
   1599 }
   1600 
   1601 TEST(CompilationCacheCachingBehavior) {
   1602   // If we do not flush code, or have the compilation cache turned off, this
   1603   // test is invalid.
   1604   if (!FLAG_flush_code || !FLAG_compilation_cache) {
   1605     return;
   1606   }
   1607   CcTest::InitializeVM();
   1608   Isolate* isolate = CcTest::i_isolate();
   1609   Factory* factory = isolate->factory();
   1610   Heap* heap = isolate->heap();
   1611   CompilationCache* compilation_cache = isolate->compilation_cache();
   1612   LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
   1613 
   1614   v8::HandleScope scope(CcTest::isolate());
   1615   const char* raw_source =
   1616       "function foo() {"
   1617       "  var x = 42;"
   1618       "  var y = 42;"
   1619       "  var z = x + y;"
   1620       "};"
   1621       "foo()";
   1622   Handle<String> source = factory->InternalizeUtf8String(raw_source);
   1623   Handle<Context> native_context = isolate->native_context();
   1624 
   1625   {
   1626     v8::HandleScope scope(CcTest::isolate());
   1627     CompileRun(raw_source);
   1628   }
   1629 
   1630   // The script should be in the cache now.
   1631   MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript(
   1632       source, Handle<Object>(), 0, 0,
   1633       v8::ScriptOriginOptions(false, true, false), native_context,
   1634       language_mode);
   1635   CHECK(!info.is_null());
   1636 
   1637   // Check that the code cache entry survives at least on GC.
   1638   // (Unless --optimize-for-size, in which case it might get collected
   1639   // immediately.)
   1640   if (!FLAG_optimize_for_size) {
   1641     heap->CollectAllGarbage();
   1642     info = compilation_cache->LookupScript(
   1643         source, Handle<Object>(), 0, 0,
   1644         v8::ScriptOriginOptions(false, true, false), native_context,
   1645         language_mode);
   1646     CHECK(!info.is_null());
   1647   }
   1648 
   1649   // Progress code age until it's old and ready for GC.
   1650   while (!info.ToHandleChecked()->code()->IsOld()) {
   1651     // To guarantee progress, we have to MakeOlder with different parities.
   1652     // We can't just use NO_MARKING_PARITY, since e.g. kExecutedOnceCodeAge is
   1653     // always NO_MARKING_PARITY and the code age only progresses if the parity
   1654     // is different.
   1655     info.ToHandleChecked()->code()->MakeOlder(ODD_MARKING_PARITY);
   1656     info.ToHandleChecked()->code()->MakeOlder(EVEN_MARKING_PARITY);
   1657   }
   1658 
   1659   heap->CollectAllGarbage();
   1660   // Ensure code aging cleared the entry from the cache.
   1661   info = compilation_cache->LookupScript(
   1662       source, Handle<Object>(), 0, 0,
   1663       v8::ScriptOriginOptions(false, true, false), native_context,
   1664       language_mode);
   1665   CHECK(info.is_null());
   1666 }
   1667 
   1668 
   1669 static void OptimizeEmptyFunction(const char* name) {
   1670   HandleScope scope(CcTest::i_isolate());
   1671   EmbeddedVector<char, 256> source;
   1672   SNPrintF(source,
   1673            "function %s() { return 0; }"
   1674            "%s(); %s();"
   1675            "%%OptimizeFunctionOnNextCall(%s);"
   1676            "%s();",
   1677            name, name, name, name, name);
   1678   CompileRun(source.start());
   1679 }
   1680 
   1681 
   1682 // Count the number of native contexts in the weak list of native contexts.
   1683 int CountNativeContexts() {
   1684   int count = 0;
   1685   Object* object = CcTest::heap()->native_contexts_list();
   1686   while (!object->IsUndefined(CcTest::i_isolate())) {
   1687     count++;
   1688     object = Context::cast(object)->next_context_link();
   1689   }
   1690   return count;
   1691 }
   1692 
   1693 
   1694 // Count the number of user functions in the weak list of optimized
   1695 // functions attached to a native context.
   1696 static int CountOptimizedUserFunctions(v8::Local<v8::Context> context) {
   1697   int count = 0;
   1698   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
   1699   Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
   1700   while (object->IsJSFunction() &&
   1701          !JSFunction::cast(object)->shared()->IsBuiltin()) {
   1702     count++;
   1703     object = JSFunction::cast(object)->next_function_link();
   1704   }
   1705   return count;
   1706 }
   1707 
   1708 
   1709 TEST(TestInternalWeakLists) {
   1710   FLAG_always_opt = false;
   1711   FLAG_allow_natives_syntax = true;
   1712   v8::V8::Initialize();
   1713 
   1714   // Some flags turn Scavenge collections into Mark-sweep collections
   1715   // and hence are incompatible with this test case.
   1716   if (FLAG_gc_global || FLAG_stress_compaction) return;
   1717   FLAG_retain_maps_for_n_gc = 0;
   1718 
   1719   static const int kNumTestContexts = 10;
   1720 
   1721   Isolate* isolate = CcTest::i_isolate();
   1722   Heap* heap = isolate->heap();
   1723   HandleScope scope(isolate);
   1724   v8::Local<v8::Context> ctx[kNumTestContexts];
   1725   if (!isolate->use_crankshaft()) return;
   1726 
   1727   CHECK_EQ(0, CountNativeContexts());
   1728 
   1729   // Create a number of global contests which gets linked together.
   1730   for (int i = 0; i < kNumTestContexts; i++) {
   1731     ctx[i] = v8::Context::New(CcTest::isolate());
   1732 
   1733     // Collect garbage that might have been created by one of the
   1734     // installed extensions.
   1735     isolate->compilation_cache()->Clear();
   1736     heap->CollectAllGarbage();
   1737 
   1738     CHECK_EQ(i + 1, CountNativeContexts());
   1739 
   1740     ctx[i]->Enter();
   1741 
   1742     // Create a handle scope so no function objects get stuck in the outer
   1743     // handle scope.
   1744     HandleScope scope(isolate);
   1745     CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
   1746     OptimizeEmptyFunction("f1");
   1747     CHECK_EQ(1, CountOptimizedUserFunctions(ctx[i]));
   1748     OptimizeEmptyFunction("f2");
   1749     CHECK_EQ(2, CountOptimizedUserFunctions(ctx[i]));
   1750     OptimizeEmptyFunction("f3");
   1751     CHECK_EQ(3, CountOptimizedUserFunctions(ctx[i]));
   1752     OptimizeEmptyFunction("f4");
   1753     CHECK_EQ(4, CountOptimizedUserFunctions(ctx[i]));
   1754     OptimizeEmptyFunction("f5");
   1755     CHECK_EQ(5, CountOptimizedUserFunctions(ctx[i]));
   1756 
   1757     // Remove function f1, and
   1758     CompileRun("f1=null");
   1759 
   1760     // Scavenge treats these references as strong.
   1761     for (int j = 0; j < 10; j++) {
   1762       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1763       CHECK_EQ(5, CountOptimizedUserFunctions(ctx[i]));
   1764     }
   1765 
   1766     // Mark compact handles the weak references.
   1767     isolate->compilation_cache()->Clear();
   1768     heap->CollectAllGarbage();
   1769     CHECK_EQ(4, CountOptimizedUserFunctions(ctx[i]));
   1770 
   1771     // Get rid of f3 and f5 in the same way.
   1772     CompileRun("f3=null");
   1773     for (int j = 0; j < 10; j++) {
   1774       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1775       CHECK_EQ(4, CountOptimizedUserFunctions(ctx[i]));
   1776     }
   1777     CcTest::heap()->CollectAllGarbage();
   1778     CHECK_EQ(3, CountOptimizedUserFunctions(ctx[i]));
   1779     CompileRun("f5=null");
   1780     for (int j = 0; j < 10; j++) {
   1781       CcTest::heap()->CollectGarbage(NEW_SPACE);
   1782       CHECK_EQ(3, CountOptimizedUserFunctions(ctx[i]));
   1783     }
   1784     CcTest::heap()->CollectAllGarbage();
   1785     CHECK_EQ(2, CountOptimizedUserFunctions(ctx[i]));
   1786 
   1787     ctx[i]->Exit();
   1788   }
   1789 
   1790   // Force compilation cache cleanup.
   1791   CcTest::heap()->NotifyContextDisposed(true);
   1792   CcTest::heap()->CollectAllGarbage();
   1793 
   1794   // Dispose the native contexts one by one.
   1795   for (int i = 0; i < kNumTestContexts; i++) {
   1796     // TODO(dcarney): is there a better way to do this?
   1797     i::Object** unsafe = reinterpret_cast<i::Object**>(*ctx[i]);
   1798     *unsafe = CcTest::heap()->undefined_value();
   1799     ctx[i].Clear();
   1800 
   1801     // Scavenge treats these references as strong.
   1802     for (int j = 0; j < 10; j++) {
   1803       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   1804       CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
   1805     }
   1806 
   1807     // Mark compact handles the weak references.
   1808     CcTest::heap()->CollectAllGarbage();
   1809     CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
   1810   }
   1811 
   1812   CHECK_EQ(0, CountNativeContexts());
   1813 }
   1814 
   1815 
   1816 // Count the number of native contexts in the weak list of native contexts
   1817 // causing a GC after the specified number of elements.
   1818 static int CountNativeContextsWithGC(Isolate* isolate, int n) {
   1819   Heap* heap = isolate->heap();
   1820   int count = 0;
   1821   Handle<Object> object(heap->native_contexts_list(), isolate);
   1822   while (!object->IsUndefined(isolate)) {
   1823     count++;
   1824     if (count == n) heap->CollectAllGarbage();
   1825     object =
   1826         Handle<Object>(Context::cast(*object)->next_context_link(), isolate);
   1827   }
   1828   return count;
   1829 }
   1830 
   1831 
   1832 // Count the number of user functions in the weak list of optimized
   1833 // functions attached to a native context causing a GC after the
   1834 // specified number of elements.
   1835 static int CountOptimizedUserFunctionsWithGC(v8::Local<v8::Context> context,
   1836                                              int n) {
   1837   int count = 0;
   1838   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
   1839   Isolate* isolate = icontext->GetIsolate();
   1840   Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
   1841                         isolate);
   1842   while (object->IsJSFunction() &&
   1843          !Handle<JSFunction>::cast(object)->shared()->IsBuiltin()) {
   1844     count++;
   1845     if (count == n) isolate->heap()->CollectAllGarbage();
   1846     object = Handle<Object>(
   1847         Object::cast(JSFunction::cast(*object)->next_function_link()),
   1848         isolate);
   1849   }
   1850   return count;
   1851 }
   1852 
   1853 
   1854 TEST(TestInternalWeakListsTraverseWithGC) {
   1855   FLAG_always_opt = false;
   1856   FLAG_allow_natives_syntax = true;
   1857   v8::V8::Initialize();
   1858 
   1859   static const int kNumTestContexts = 10;
   1860 
   1861   Isolate* isolate = CcTest::i_isolate();
   1862   HandleScope scope(isolate);
   1863   v8::Local<v8::Context> ctx[kNumTestContexts];
   1864   if (!isolate->use_crankshaft()) return;
   1865 
   1866   CHECK_EQ(0, CountNativeContexts());
   1867 
   1868   // Create an number of contexts and check the length of the weak list both
   1869   // with and without GCs while iterating the list.
   1870   for (int i = 0; i < kNumTestContexts; i++) {
   1871     ctx[i] = v8::Context::New(CcTest::isolate());
   1872     CHECK_EQ(i + 1, CountNativeContexts());
   1873     CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
   1874   }
   1875 
   1876   ctx[0]->Enter();
   1877 
   1878   // Compile a number of functions the length of the weak list of optimized
   1879   // functions both with and without GCs while iterating the list.
   1880   CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
   1881   OptimizeEmptyFunction("f1");
   1882   CHECK_EQ(1, CountOptimizedUserFunctions(ctx[0]));
   1883   CHECK_EQ(1, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1884   OptimizeEmptyFunction("f2");
   1885   CHECK_EQ(2, CountOptimizedUserFunctions(ctx[0]));
   1886   CHECK_EQ(2, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1887   OptimizeEmptyFunction("f3");
   1888   CHECK_EQ(3, CountOptimizedUserFunctions(ctx[0]));
   1889   CHECK_EQ(3, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
   1890   OptimizeEmptyFunction("f4");
   1891   CHECK_EQ(4, CountOptimizedUserFunctions(ctx[0]));
   1892   CHECK_EQ(4, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
   1893   OptimizeEmptyFunction("f5");
   1894   CHECK_EQ(5, CountOptimizedUserFunctions(ctx[0]));
   1895   CHECK_EQ(5, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
   1896 
   1897   ctx[0]->Exit();
   1898 }
   1899 
   1900 
   1901 TEST(TestSizeOfRegExpCode) {
   1902   if (!FLAG_regexp_optimization) return;
   1903 
   1904   v8::V8::Initialize();
   1905 
   1906   Isolate* isolate = CcTest::i_isolate();
   1907   HandleScope scope(isolate);
   1908 
   1909   LocalContext context;
   1910 
   1911   // Adjust source below and this check to match
   1912   // RegExpImple::kRegExpTooLargeToOptimize.
   1913   CHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 20 * KB);
   1914 
   1915   // Compile a regexp that is much larger if we are using regexp optimizations.
   1916   CompileRun(
   1917       "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';"
   1918       "var half_size_reg_exp;"
   1919       "while (reg_exp_source.length < 20 * 1024) {"
   1920       "  half_size_reg_exp = reg_exp_source;"
   1921       "  reg_exp_source = reg_exp_source + reg_exp_source;"
   1922       "}"
   1923       // Flatten string.
   1924       "reg_exp_source.match(/f/);");
   1925 
   1926   // Get initial heap size after several full GCs, which will stabilize
   1927   // the heap size and return with sweeping finished completely.
   1928   CcTest::heap()->CollectAllGarbage();
   1929   CcTest::heap()->CollectAllGarbage();
   1930   CcTest::heap()->CollectAllGarbage();
   1931   CcTest::heap()->CollectAllGarbage();
   1932   CcTest::heap()->CollectAllGarbage();
   1933   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
   1934   if (collector->sweeping_in_progress()) {
   1935     collector->EnsureSweepingCompleted();
   1936   }
   1937   int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
   1938 
   1939   CompileRun("'foo'.match(reg_exp_source);");
   1940   CcTest::heap()->CollectAllGarbage();
   1941   int size_with_regexp = static_cast<int>(CcTest::heap()->SizeOfObjects());
   1942 
   1943   CompileRun("'foo'.match(half_size_reg_exp);");
   1944   CcTest::heap()->CollectAllGarbage();
   1945   int size_with_optimized_regexp =
   1946       static_cast<int>(CcTest::heap()->SizeOfObjects());
   1947 
   1948   int size_of_regexp_code = size_with_regexp - initial_size;
   1949 
   1950   // On some platforms the debug-code flag causes huge amounts of regexp code
   1951   // to be emitted, breaking this test.
   1952   if (!FLAG_debug_code) {
   1953     CHECK_LE(size_of_regexp_code, 1 * MB);
   1954   }
   1955 
   1956   // Small regexp is half the size, but compiles to more than twice the code
   1957   // due to the optimization steps.
   1958   CHECK_GE(size_with_optimized_regexp,
   1959            size_with_regexp + size_of_regexp_code * 2);
   1960 }
   1961 
   1962 
   1963 HEAP_TEST(TestSizeOfObjects) {
   1964   v8::V8::Initialize();
   1965 
   1966   // Get initial heap size after several full GCs, which will stabilize
   1967   // the heap size and return with sweeping finished completely.
   1968   CcTest::heap()->CollectAllGarbage();
   1969   CcTest::heap()->CollectAllGarbage();
   1970   CcTest::heap()->CollectAllGarbage();
   1971   CcTest::heap()->CollectAllGarbage();
   1972   CcTest::heap()->CollectAllGarbage();
   1973   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
   1974   if (collector->sweeping_in_progress()) {
   1975     collector->EnsureSweepingCompleted();
   1976   }
   1977   int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
   1978 
   1979   {
   1980     // Allocate objects on several different old-space pages so that
   1981     // concurrent sweeper threads will be busy sweeping the old space on
   1982     // subsequent GC runs.
   1983     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   1984     int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
   1985     for (int i = 1; i <= 100; i++) {
   1986       CcTest::heap()->AllocateFixedArray(8192, TENURED).ToObjectChecked();
   1987       CHECK_EQ(initial_size + i * filler_size,
   1988                static_cast<int>(CcTest::heap()->SizeOfObjects()));
   1989     }
   1990   }
   1991 
   1992   // The heap size should go back to initial size after a full GC, even
   1993   // though sweeping didn't finish yet.
   1994   CcTest::heap()->CollectAllGarbage();
   1995 
   1996   // Normally sweeping would not be complete here, but no guarantees.
   1997 
   1998   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
   1999 
   2000   // Waiting for sweeper threads should not change heap size.
   2001   if (collector->sweeping_in_progress()) {
   2002     collector->EnsureSweepingCompleted();
   2003   }
   2004   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
   2005 }
   2006 
   2007 
   2008 TEST(TestAlignmentCalculations) {
   2009   // Maximum fill amounts are consistent.
   2010   int maximum_double_misalignment = kDoubleSize - kPointerSize;
   2011   int maximum_simd128_misalignment = kSimd128Size - kPointerSize;
   2012   int max_word_fill = Heap::GetMaximumFillToAlign(kWordAligned);
   2013   CHECK_EQ(0, max_word_fill);
   2014   int max_double_fill = Heap::GetMaximumFillToAlign(kDoubleAligned);
   2015   CHECK_EQ(maximum_double_misalignment, max_double_fill);
   2016   int max_double_unaligned_fill = Heap::GetMaximumFillToAlign(kDoubleUnaligned);
   2017   CHECK_EQ(maximum_double_misalignment, max_double_unaligned_fill);
   2018   int max_simd128_unaligned_fill =
   2019       Heap::GetMaximumFillToAlign(kSimd128Unaligned);
   2020   CHECK_EQ(maximum_simd128_misalignment, max_simd128_unaligned_fill);
   2021 
   2022   Address base = static_cast<Address>(NULL);
   2023   int fill = 0;
   2024 
   2025   // Word alignment never requires fill.
   2026   fill = Heap::GetFillToAlign(base, kWordAligned);
   2027   CHECK_EQ(0, fill);
   2028   fill = Heap::GetFillToAlign(base + kPointerSize, kWordAligned);
   2029   CHECK_EQ(0, fill);
   2030 
   2031   // No fill is required when address is double aligned.
   2032   fill = Heap::GetFillToAlign(base, kDoubleAligned);
   2033   CHECK_EQ(0, fill);
   2034   // Fill is required if address is not double aligned.
   2035   fill = Heap::GetFillToAlign(base + kPointerSize, kDoubleAligned);
   2036   CHECK_EQ(maximum_double_misalignment, fill);
   2037   // kDoubleUnaligned has the opposite fill amounts.
   2038   fill = Heap::GetFillToAlign(base, kDoubleUnaligned);
   2039   CHECK_EQ(maximum_double_misalignment, fill);
   2040   fill = Heap::GetFillToAlign(base + kPointerSize, kDoubleUnaligned);
   2041   CHECK_EQ(0, fill);
   2042 
   2043   // 128 bit SIMD types have 2 or 4 possible alignments, depending on platform.
   2044   fill = Heap::GetFillToAlign(base, kSimd128Unaligned);
   2045   CHECK_EQ((3 * kPointerSize) & kSimd128AlignmentMask, fill);
   2046   fill = Heap::GetFillToAlign(base + kPointerSize, kSimd128Unaligned);
   2047   CHECK_EQ((2 * kPointerSize) & kSimd128AlignmentMask, fill);
   2048   fill = Heap::GetFillToAlign(base + 2 * kPointerSize, kSimd128Unaligned);
   2049   CHECK_EQ(kPointerSize, fill);
   2050   fill = Heap::GetFillToAlign(base + 3 * kPointerSize, kSimd128Unaligned);
   2051   CHECK_EQ(0, fill);
   2052 }
   2053 
   2054 
   2055 static HeapObject* NewSpaceAllocateAligned(int size,
   2056                                            AllocationAlignment alignment) {
   2057   Heap* heap = CcTest::heap();
   2058   AllocationResult allocation =
   2059       heap->new_space()->AllocateRawAligned(size, alignment);
   2060   HeapObject* obj = NULL;
   2061   allocation.To(&obj);
   2062   heap->CreateFillerObjectAt(obj->address(), size, ClearRecordedSlots::kNo);
   2063   return obj;
   2064 }
   2065 
   2066 
   2067 // Get new space allocation into the desired alignment.
   2068 static Address AlignNewSpace(AllocationAlignment alignment, int offset) {
   2069   Address* top_addr = CcTest::heap()->new_space()->allocation_top_address();
   2070   int fill = Heap::GetFillToAlign(*top_addr, alignment);
   2071   if (fill) {
   2072     NewSpaceAllocateAligned(fill + offset, kWordAligned);
   2073   }
   2074   return *top_addr;
   2075 }
   2076 
   2077 
   2078 TEST(TestAlignedAllocation) {
   2079   // Double misalignment is 4 on 32-bit platforms, 0 on 64-bit ones.
   2080   const intptr_t double_misalignment = kDoubleSize - kPointerSize;
   2081   Address* top_addr = CcTest::heap()->new_space()->allocation_top_address();
   2082   Address start;
   2083   HeapObject* obj;
   2084   HeapObject* filler;
   2085   if (double_misalignment) {
   2086     // Allocate a pointer sized object that must be double aligned at an
   2087     // aligned address.
   2088     start = AlignNewSpace(kDoubleAligned, 0);
   2089     obj = NewSpaceAllocateAligned(kPointerSize, kDoubleAligned);
   2090     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment));
   2091     // There is no filler.
   2092     CHECK_EQ(kPointerSize, *top_addr - start);
   2093 
   2094     // Allocate a second pointer sized object that must be double aligned at an
   2095     // unaligned address.
   2096     start = AlignNewSpace(kDoubleAligned, kPointerSize);
   2097     obj = NewSpaceAllocateAligned(kPointerSize, kDoubleAligned);
   2098     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment));
   2099     // There is a filler object before the object.
   2100     filler = HeapObject::FromAddress(start);
   2101     CHECK(obj != filler && filler->IsFiller() &&
   2102           filler->Size() == kPointerSize);
   2103     CHECK_EQ(kPointerSize + double_misalignment, *top_addr - start);
   2104 
   2105     // Similarly for kDoubleUnaligned.
   2106     start = AlignNewSpace(kDoubleUnaligned, 0);
   2107     obj = NewSpaceAllocateAligned(kPointerSize, kDoubleUnaligned);
   2108     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize));
   2109     CHECK_EQ(kPointerSize, *top_addr - start);
   2110     start = AlignNewSpace(kDoubleUnaligned, kPointerSize);
   2111     obj = NewSpaceAllocateAligned(kPointerSize, kDoubleUnaligned);
   2112     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize));
   2113     // There is a filler object before the object.
   2114     filler = HeapObject::FromAddress(start);
   2115     CHECK(obj != filler && filler->IsFiller() &&
   2116           filler->Size() == kPointerSize);
   2117     CHECK_EQ(kPointerSize + double_misalignment, *top_addr - start);
   2118   }
   2119 
   2120   // Now test SIMD alignment. There are 2 or 4 possible alignments, depending
   2121   // on platform.
   2122   start = AlignNewSpace(kSimd128Unaligned, 0);
   2123   obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2124   CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2125   // There is no filler.
   2126   CHECK_EQ(kPointerSize, *top_addr - start);
   2127   start = AlignNewSpace(kSimd128Unaligned, kPointerSize);
   2128   obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2129   CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2130   // There is a filler object before the object.
   2131   filler = HeapObject::FromAddress(start);
   2132   CHECK(obj != filler && filler->IsFiller() &&
   2133         filler->Size() == kSimd128Size - kPointerSize);
   2134   CHECK_EQ(kPointerSize + kSimd128Size - kPointerSize, *top_addr - start);
   2135 
   2136   if (double_misalignment) {
   2137     // Test the 2 other alignments possible on 32 bit platforms.
   2138     start = AlignNewSpace(kSimd128Unaligned, 2 * kPointerSize);
   2139     obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2140     CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2141     // There is a filler object before the object.
   2142     filler = HeapObject::FromAddress(start);
   2143     CHECK(obj != filler && filler->IsFiller() &&
   2144           filler->Size() == 2 * kPointerSize);
   2145     CHECK_EQ(kPointerSize + 2 * kPointerSize, *top_addr - start);
   2146     start = AlignNewSpace(kSimd128Unaligned, 3 * kPointerSize);
   2147     obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2148     CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2149     // There is a filler object before the object.
   2150     filler = HeapObject::FromAddress(start);
   2151     CHECK(obj != filler && filler->IsFiller() &&
   2152           filler->Size() == kPointerSize);
   2153     CHECK_EQ(kPointerSize + kPointerSize, *top_addr - start);
   2154   }
   2155 }
   2156 
   2157 
   2158 static HeapObject* OldSpaceAllocateAligned(int size,
   2159                                            AllocationAlignment alignment) {
   2160   Heap* heap = CcTest::heap();
   2161   AllocationResult allocation =
   2162       heap->old_space()->AllocateRawAligned(size, alignment);
   2163   HeapObject* obj = NULL;
   2164   allocation.To(&obj);
   2165   heap->CreateFillerObjectAt(obj->address(), size, ClearRecordedSlots::kNo);
   2166   return obj;
   2167 }
   2168 
   2169 
   2170 // Get old space allocation into the desired alignment.
   2171 static Address AlignOldSpace(AllocationAlignment alignment, int offset) {
   2172   Address* top_addr = CcTest::heap()->old_space()->allocation_top_address();
   2173   int fill = Heap::GetFillToAlign(*top_addr, alignment);
   2174   int allocation = fill + offset;
   2175   if (allocation) {
   2176     OldSpaceAllocateAligned(allocation, kWordAligned);
   2177   }
   2178   Address top = *top_addr;
   2179   // Now force the remaining allocation onto the free list.
   2180   CcTest::heap()->old_space()->EmptyAllocationInfo();
   2181   return top;
   2182 }
   2183 
   2184 
   2185 // Test the case where allocation must be done from the free list, so filler
   2186 // may precede or follow the object.
   2187 TEST(TestAlignedOverAllocation) {
   2188   // Double misalignment is 4 on 32-bit platforms, 0 on 64-bit ones.
   2189   const intptr_t double_misalignment = kDoubleSize - kPointerSize;
   2190   Address start;
   2191   HeapObject* obj;
   2192   HeapObject* filler1;
   2193   HeapObject* filler2;
   2194   if (double_misalignment) {
   2195     start = AlignOldSpace(kDoubleAligned, 0);
   2196     obj = OldSpaceAllocateAligned(kPointerSize, kDoubleAligned);
   2197     // The object is aligned, and a filler object is created after.
   2198     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment));
   2199     filler1 = HeapObject::FromAddress(start + kPointerSize);
   2200     CHECK(obj != filler1 && filler1->IsFiller() &&
   2201           filler1->Size() == kPointerSize);
   2202     // Try the opposite alignment case.
   2203     start = AlignOldSpace(kDoubleAligned, kPointerSize);
   2204     obj = OldSpaceAllocateAligned(kPointerSize, kDoubleAligned);
   2205     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment));
   2206     filler1 = HeapObject::FromAddress(start);
   2207     CHECK(obj != filler1);
   2208     CHECK(filler1->IsFiller());
   2209     CHECK(filler1->Size() == kPointerSize);
   2210     CHECK(obj != filler1 && filler1->IsFiller() &&
   2211           filler1->Size() == kPointerSize);
   2212 
   2213     // Similarly for kDoubleUnaligned.
   2214     start = AlignOldSpace(kDoubleUnaligned, 0);
   2215     obj = OldSpaceAllocateAligned(kPointerSize, kDoubleUnaligned);
   2216     // The object is aligned, and a filler object is created after.
   2217     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize));
   2218     filler1 = HeapObject::FromAddress(start + kPointerSize);
   2219     CHECK(obj != filler1 && filler1->IsFiller() &&
   2220           filler1->Size() == kPointerSize);
   2221     // Try the opposite alignment case.
   2222     start = AlignOldSpace(kDoubleUnaligned, kPointerSize);
   2223     obj = OldSpaceAllocateAligned(kPointerSize, kDoubleUnaligned);
   2224     CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize));
   2225     filler1 = HeapObject::FromAddress(start);
   2226     CHECK(obj != filler1 && filler1->IsFiller() &&
   2227           filler1->Size() == kPointerSize);
   2228   }
   2229 
   2230   // Now test SIMD alignment. There are 2 or 4 possible alignments, depending
   2231   // on platform.
   2232   start = AlignOldSpace(kSimd128Unaligned, 0);
   2233   obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2234   CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2235   // There is a filler object after the object.
   2236   filler1 = HeapObject::FromAddress(start + kPointerSize);
   2237   CHECK(obj != filler1 && filler1->IsFiller() &&
   2238         filler1->Size() == kSimd128Size - kPointerSize);
   2239   start = AlignOldSpace(kSimd128Unaligned, kPointerSize);
   2240   obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2241   CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2242   // There is a filler object before the object.
   2243   filler1 = HeapObject::FromAddress(start);
   2244   CHECK(obj != filler1 && filler1->IsFiller() &&
   2245         filler1->Size() == kSimd128Size - kPointerSize);
   2246 
   2247   if (double_misalignment) {
   2248     // Test the 2 other alignments possible on 32 bit platforms.
   2249     start = AlignOldSpace(kSimd128Unaligned, 2 * kPointerSize);
   2250     obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2251     CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2252     // There are filler objects before and after the object.
   2253     filler1 = HeapObject::FromAddress(start);
   2254     CHECK(obj != filler1 && filler1->IsFiller() &&
   2255           filler1->Size() == 2 * kPointerSize);
   2256     filler2 = HeapObject::FromAddress(start + 3 * kPointerSize);
   2257     CHECK(obj != filler2 && filler2->IsFiller() &&
   2258           filler2->Size() == kPointerSize);
   2259     start = AlignOldSpace(kSimd128Unaligned, 3 * kPointerSize);
   2260     obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned);
   2261     CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize));
   2262     // There are filler objects before and after the object.
   2263     filler1 = HeapObject::FromAddress(start);
   2264     CHECK(obj != filler1 && filler1->IsFiller() &&
   2265           filler1->Size() == kPointerSize);
   2266     filler2 = HeapObject::FromAddress(start + 2 * kPointerSize);
   2267     CHECK(obj != filler2 && filler2->IsFiller() &&
   2268           filler2->Size() == 2 * kPointerSize);
   2269   }
   2270 }
   2271 
   2272 
   2273 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
   2274   CcTest::InitializeVM();
   2275   HeapIterator iterator(CcTest::heap());
   2276   intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects();
   2277   intptr_t size_of_objects_2 = 0;
   2278   for (HeapObject* obj = iterator.next();
   2279        obj != NULL;
   2280        obj = iterator.next()) {
   2281     if (!obj->IsFreeSpace()) {
   2282       size_of_objects_2 += obj->Size();
   2283     }
   2284   }
   2285   // Delta must be within 5% of the larger result.
   2286   // TODO(gc): Tighten this up by distinguishing between byte
   2287   // arrays that are real and those that merely mark free space
   2288   // on the heap.
   2289   if (size_of_objects_1 > size_of_objects_2) {
   2290     intptr_t delta = size_of_objects_1 - size_of_objects_2;
   2291     PrintF("Heap::SizeOfObjects: %" V8PRIdPTR
   2292            ", "
   2293            "Iterator: %" V8PRIdPTR
   2294            ", "
   2295            "delta: %" V8PRIdPTR "\n",
   2296            size_of_objects_1, size_of_objects_2, delta);
   2297     CHECK_GT(size_of_objects_1 / 20, delta);
   2298   } else {
   2299     intptr_t delta = size_of_objects_2 - size_of_objects_1;
   2300     PrintF("Heap::SizeOfObjects: %" V8PRIdPTR
   2301            ", "
   2302            "Iterator: %" V8PRIdPTR
   2303            ", "
   2304            "delta: %" V8PRIdPTR "\n",
   2305            size_of_objects_1, size_of_objects_2, delta);
   2306     CHECK_GT(size_of_objects_2 / 20, delta);
   2307   }
   2308 }
   2309 
   2310 
   2311 static void FillUpNewSpace(NewSpace* new_space) {
   2312   // Fill up new space to the point that it is completely full. Make sure
   2313   // that the scavenger does not undo the filling.
   2314   Heap* heap = new_space->heap();
   2315   Isolate* isolate = heap->isolate();
   2316   Factory* factory = isolate->factory();
   2317   HandleScope scope(isolate);
   2318   AlwaysAllocateScope always_allocate(isolate);
   2319   intptr_t available = new_space->Capacity() - new_space->Size();
   2320   intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
   2321   for (intptr_t i = 0; i < number_of_fillers; i++) {
   2322     CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
   2323   }
   2324 }
   2325 
   2326 
   2327 TEST(GrowAndShrinkNewSpace) {
   2328   CcTest::InitializeVM();
   2329   Heap* heap = CcTest::heap();
   2330   NewSpace* new_space = heap->new_space();
   2331 
   2332   if (heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
   2333     return;
   2334   }
   2335 
   2336   // Explicitly growing should double the space capacity.
   2337   intptr_t old_capacity, new_capacity;
   2338   old_capacity = new_space->TotalCapacity();
   2339   new_space->Grow();
   2340   new_capacity = new_space->TotalCapacity();
   2341   CHECK(2 * old_capacity == new_capacity);
   2342 
   2343   old_capacity = new_space->TotalCapacity();
   2344   FillUpNewSpace(new_space);
   2345   new_capacity = new_space->TotalCapacity();
   2346   CHECK(old_capacity == new_capacity);
   2347 
   2348   // Explicitly shrinking should not affect space capacity.
   2349   old_capacity = new_space->TotalCapacity();
   2350   new_space->Shrink();
   2351   new_capacity = new_space->TotalCapacity();
   2352   CHECK(old_capacity == new_capacity);
   2353 
   2354   // Let the scavenger empty the new space.
   2355   heap->CollectGarbage(NEW_SPACE);
   2356   CHECK_LE(new_space->Size(), old_capacity);
   2357 
   2358   // Explicitly shrinking should halve the space capacity.
   2359   old_capacity = new_space->TotalCapacity();
   2360   new_space->Shrink();
   2361   new_capacity = new_space->TotalCapacity();
   2362   CHECK(old_capacity == 2 * new_capacity);
   2363 
   2364   // Consecutive shrinking should not affect space capacity.
   2365   old_capacity = new_space->TotalCapacity();
   2366   new_space->Shrink();
   2367   new_space->Shrink();
   2368   new_space->Shrink();
   2369   new_capacity = new_space->TotalCapacity();
   2370   CHECK(old_capacity == new_capacity);
   2371 }
   2372 
   2373 
   2374 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
   2375   CcTest::InitializeVM();
   2376   Heap* heap = CcTest::heap();
   2377   if (heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
   2378     return;
   2379   }
   2380 
   2381   v8::HandleScope scope(CcTest::isolate());
   2382   NewSpace* new_space = heap->new_space();
   2383   intptr_t old_capacity, new_capacity;
   2384   old_capacity = new_space->TotalCapacity();
   2385   new_space->Grow();
   2386   new_capacity = new_space->TotalCapacity();
   2387   CHECK(2 * old_capacity == new_capacity);
   2388   FillUpNewSpace(new_space);
   2389   heap->CollectAllAvailableGarbage();
   2390   new_capacity = new_space->TotalCapacity();
   2391   CHECK(old_capacity == new_capacity);
   2392 }
   2393 
   2394 
   2395 static int NumberOfGlobalObjects() {
   2396   int count = 0;
   2397   HeapIterator iterator(CcTest::heap());
   2398   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
   2399     if (obj->IsJSGlobalObject()) count++;
   2400   }
   2401   return count;
   2402 }
   2403 
   2404 
   2405 // Test that we don't embed maps from foreign contexts into
   2406 // optimized code.
   2407 TEST(LeakNativeContextViaMap) {
   2408   i::FLAG_allow_natives_syntax = true;
   2409   v8::Isolate* isolate = CcTest::isolate();
   2410   v8::HandleScope outer_scope(isolate);
   2411   v8::Persistent<v8::Context> ctx1p;
   2412   v8::Persistent<v8::Context> ctx2p;
   2413   {
   2414     v8::HandleScope scope(isolate);
   2415     ctx1p.Reset(isolate, v8::Context::New(isolate));
   2416     ctx2p.Reset(isolate, v8::Context::New(isolate));
   2417     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   2418   }
   2419 
   2420   CcTest::heap()->CollectAllAvailableGarbage();
   2421   CHECK_EQ(2, NumberOfGlobalObjects());
   2422 
   2423   {
   2424     v8::HandleScope inner_scope(isolate);
   2425     CompileRun("var v = {x: 42}");
   2426     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   2427     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   2428     v8::Local<v8::Value> v =
   2429         ctx1->Global()->Get(ctx1, v8_str("v")).ToLocalChecked();
   2430     ctx2->Enter();
   2431     CHECK(ctx2->Global()->Set(ctx2, v8_str("o"), v).FromJust());
   2432     v8::Local<v8::Value> res = CompileRun(
   2433         "function f() { return o.x; }"
   2434         "for (var i = 0; i < 10; ++i) f();"
   2435         "%OptimizeFunctionOnNextCall(f);"
   2436         "f();");
   2437     CHECK_EQ(42, res->Int32Value(ctx2).FromJust());
   2438     CHECK(ctx2->Global()
   2439               ->Set(ctx2, v8_str("o"), v8::Int32::New(isolate, 0))
   2440               .FromJust());
   2441     ctx2->Exit();
   2442     v8::Local<v8::Context>::New(isolate, ctx1)->Exit();
   2443     ctx1p.Reset();
   2444     isolate->ContextDisposedNotification();
   2445   }
   2446   CcTest::heap()->CollectAllAvailableGarbage();
   2447   CHECK_EQ(1, NumberOfGlobalObjects());
   2448   ctx2p.Reset();
   2449   CcTest::heap()->CollectAllAvailableGarbage();
   2450   CHECK_EQ(0, NumberOfGlobalObjects());
   2451 }
   2452 
   2453 
   2454 // Test that we don't embed functions from foreign contexts into
   2455 // optimized code.
   2456 TEST(LeakNativeContextViaFunction) {
   2457   i::FLAG_allow_natives_syntax = true;
   2458   v8::Isolate* isolate = CcTest::isolate();
   2459   v8::HandleScope outer_scope(isolate);
   2460   v8::Persistent<v8::Context> ctx1p;
   2461   v8::Persistent<v8::Context> ctx2p;
   2462   {
   2463     v8::HandleScope scope(isolate);
   2464     ctx1p.Reset(isolate, v8::Context::New(isolate));
   2465     ctx2p.Reset(isolate, v8::Context::New(isolate));
   2466     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   2467   }
   2468 
   2469   CcTest::heap()->CollectAllAvailableGarbage();
   2470   CHECK_EQ(2, NumberOfGlobalObjects());
   2471 
   2472   {
   2473     v8::HandleScope inner_scope(isolate);
   2474     CompileRun("var v = function() { return 42; }");
   2475     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   2476     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   2477     v8::Local<v8::Value> v =
   2478         ctx1->Global()->Get(ctx1, v8_str("v")).ToLocalChecked();
   2479     ctx2->Enter();
   2480     CHECK(ctx2->Global()->Set(ctx2, v8_str("o"), v).FromJust());
   2481     v8::Local<v8::Value> res = CompileRun(
   2482         "function f(x) { return x(); }"
   2483         "for (var i = 0; i < 10; ++i) f(o);"
   2484         "%OptimizeFunctionOnNextCall(f);"
   2485         "f(o);");
   2486     CHECK_EQ(42, res->Int32Value(ctx2).FromJust());
   2487     CHECK(ctx2->Global()
   2488               ->Set(ctx2, v8_str("o"), v8::Int32::New(isolate, 0))
   2489               .FromJust());
   2490     ctx2->Exit();
   2491     ctx1->Exit();
   2492     ctx1p.Reset();
   2493     isolate->ContextDisposedNotification();
   2494   }
   2495   CcTest::heap()->CollectAllAvailableGarbage();
   2496   CHECK_EQ(1, NumberOfGlobalObjects());
   2497   ctx2p.Reset();
   2498   CcTest::heap()->CollectAllAvailableGarbage();
   2499   CHECK_EQ(0, NumberOfGlobalObjects());
   2500 }
   2501 
   2502 
   2503 TEST(LeakNativeContextViaMapKeyed) {
   2504   i::FLAG_allow_natives_syntax = true;
   2505   v8::Isolate* isolate = CcTest::isolate();
   2506   v8::HandleScope outer_scope(isolate);
   2507   v8::Persistent<v8::Context> ctx1p;
   2508   v8::Persistent<v8::Context> ctx2p;
   2509   {
   2510     v8::HandleScope scope(isolate);
   2511     ctx1p.Reset(isolate, v8::Context::New(isolate));
   2512     ctx2p.Reset(isolate, v8::Context::New(isolate));
   2513     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   2514   }
   2515 
   2516   CcTest::heap()->CollectAllAvailableGarbage();
   2517   CHECK_EQ(2, NumberOfGlobalObjects());
   2518 
   2519   {
   2520     v8::HandleScope inner_scope(isolate);
   2521     CompileRun("var v = [42, 43]");
   2522     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   2523     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   2524     v8::Local<v8::Value> v =
   2525         ctx1->Global()->Get(ctx1, v8_str("v")).ToLocalChecked();
   2526     ctx2->Enter();
   2527     CHECK(ctx2->Global()->Set(ctx2, v8_str("o"), v).FromJust());
   2528     v8::Local<v8::Value> res = CompileRun(
   2529         "function f() { return o[0]; }"
   2530         "for (var i = 0; i < 10; ++i) f();"
   2531         "%OptimizeFunctionOnNextCall(f);"
   2532         "f();");
   2533     CHECK_EQ(42, res->Int32Value(ctx2).FromJust());
   2534     CHECK(ctx2->Global()
   2535               ->Set(ctx2, v8_str("o"), v8::Int32::New(isolate, 0))
   2536               .FromJust());
   2537     ctx2->Exit();
   2538     ctx1->Exit();
   2539     ctx1p.Reset();
   2540     isolate->ContextDisposedNotification();
   2541   }
   2542   CcTest::heap()->CollectAllAvailableGarbage();
   2543   CHECK_EQ(1, NumberOfGlobalObjects());
   2544   ctx2p.Reset();
   2545   CcTest::heap()->CollectAllAvailableGarbage();
   2546   CHECK_EQ(0, NumberOfGlobalObjects());
   2547 }
   2548 
   2549 
   2550 TEST(LeakNativeContextViaMapProto) {
   2551   i::FLAG_allow_natives_syntax = true;
   2552   v8::Isolate* isolate = CcTest::isolate();
   2553   v8::HandleScope outer_scope(isolate);
   2554   v8::Persistent<v8::Context> ctx1p;
   2555   v8::Persistent<v8::Context> ctx2p;
   2556   {
   2557     v8::HandleScope scope(isolate);
   2558     ctx1p.Reset(isolate, v8::Context::New(isolate));
   2559     ctx2p.Reset(isolate, v8::Context::New(isolate));
   2560     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
   2561   }
   2562 
   2563   CcTest::heap()->CollectAllAvailableGarbage();
   2564   CHECK_EQ(2, NumberOfGlobalObjects());
   2565 
   2566   {
   2567     v8::HandleScope inner_scope(isolate);
   2568     CompileRun("var v = { y: 42}");
   2569     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
   2570     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
   2571     v8::Local<v8::Value> v =
   2572         ctx1->Global()->Get(ctx1, v8_str("v")).ToLocalChecked();
   2573     ctx2->Enter();
   2574     CHECK(ctx2->Global()->Set(ctx2, v8_str("o"), v).FromJust());
   2575     v8::Local<v8::Value> res = CompileRun(
   2576         "function f() {"
   2577         "  var p = {x: 42};"
   2578         "  p.__proto__ = o;"
   2579         "  return p.x;"
   2580         "}"
   2581         "for (var i = 0; i < 10; ++i) f();"
   2582         "%OptimizeFunctionOnNextCall(f);"
   2583         "f();");
   2584     CHECK_EQ(42, res->Int32Value(ctx2).FromJust());
   2585     CHECK(ctx2->Global()
   2586               ->Set(ctx2, v8_str("o"), v8::Int32::New(isolate, 0))
   2587               .FromJust());
   2588     ctx2->Exit();
   2589     ctx1->Exit();
   2590     ctx1p.Reset();
   2591     isolate->ContextDisposedNotification();
   2592   }
   2593   CcTest::heap()->CollectAllAvailableGarbage();
   2594   CHECK_EQ(1, NumberOfGlobalObjects());
   2595   ctx2p.Reset();
   2596   CcTest::heap()->CollectAllAvailableGarbage();
   2597   CHECK_EQ(0, NumberOfGlobalObjects());
   2598 }
   2599 
   2600 
   2601 TEST(InstanceOfStubWriteBarrier) {
   2602   i::FLAG_allow_natives_syntax = true;
   2603 #ifdef VERIFY_HEAP
   2604   i::FLAG_verify_heap = true;
   2605 #endif
   2606 
   2607   CcTest::InitializeVM();
   2608   if (!CcTest::i_isolate()->use_crankshaft()) return;
   2609   if (i::FLAG_force_marking_deque_overflows) return;
   2610   v8::HandleScope outer_scope(CcTest::isolate());
   2611   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   2612 
   2613   {
   2614     v8::HandleScope scope(CcTest::isolate());
   2615     CompileRun(
   2616         "function foo () { }"
   2617         "function mkbar () { return new (new Function(\"\")) (); }"
   2618         "function f (x) { return (x instanceof foo); }"
   2619         "function g () { f(mkbar()); }"
   2620         "f(new foo()); f(new foo());"
   2621         "%OptimizeFunctionOnNextCall(f);"
   2622         "f(new foo()); g();");
   2623   }
   2624 
   2625   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   2626   marking->Stop();
   2627   CcTest::heap()->StartIncrementalMarking();
   2628 
   2629   i::Handle<JSFunction> f = i::Handle<JSFunction>::cast(
   2630       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   2631           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   2632 
   2633   CHECK(f->IsOptimized());
   2634 
   2635   while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
   2636          !marking->IsStopped()) {
   2637     // Discard any pending GC requests otherwise we will get GC when we enter
   2638     // code below.
   2639     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   2640   }
   2641 
   2642   CHECK(marking->IsMarking());
   2643 
   2644   {
   2645     v8::HandleScope scope(CcTest::isolate());
   2646     v8::Local<v8::Object> global = CcTest::global();
   2647     v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   2648         global->Get(ctx, v8_str("g")).ToLocalChecked());
   2649     g->Call(ctx, global, 0, nullptr).ToLocalChecked();
   2650   }
   2651 
   2652   CcTest::heap()->incremental_marking()->set_should_hurry(true);
   2653   CcTest::heap()->CollectGarbage(OLD_SPACE);
   2654 }
   2655 
   2656 namespace {
   2657 
   2658 int GetProfilerTicks(SharedFunctionInfo* shared) {
   2659   return FLAG_ignition ? shared->profiler_ticks()
   2660                        : shared->code()->profiler_ticks();
   2661 }
   2662 
   2663 }  // namespace
   2664 
   2665 TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
   2666   i::FLAG_stress_compaction = false;
   2667   i::FLAG_allow_natives_syntax = true;
   2668 #ifdef VERIFY_HEAP
   2669   i::FLAG_verify_heap = true;
   2670 #endif
   2671 
   2672   CcTest::InitializeVM();
   2673   if (!CcTest::i_isolate()->use_crankshaft()) return;
   2674   v8::HandleScope outer_scope(CcTest::isolate());
   2675   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   2676 
   2677   {
   2678     v8::HandleScope scope(CcTest::isolate());
   2679     CompileRun(
   2680         "function f () {"
   2681         "  var s = 0;"
   2682         "  for (var i = 0; i < 100; i++)  s += i;"
   2683         "  return s;"
   2684         "}"
   2685         "f(); f();"
   2686         "%OptimizeFunctionOnNextCall(f);"
   2687         "f();");
   2688   }
   2689   i::Handle<JSFunction> f = i::Handle<JSFunction>::cast(
   2690       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   2691           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   2692   CHECK(f->IsOptimized());
   2693 
   2694   // Make sure incremental marking it not running.
   2695   CcTest::heap()->incremental_marking()->Stop();
   2696 
   2697   CcTest::heap()->StartIncrementalMarking();
   2698   // The following calls will increment CcTest::heap()->global_ic_age().
   2699   CcTest::isolate()->ContextDisposedNotification();
   2700   heap::SimulateIncrementalMarking(CcTest::heap());
   2701   CcTest::heap()->CollectAllGarbage();
   2702 
   2703   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
   2704   CHECK_EQ(0, f->shared()->opt_count());
   2705   CHECK_EQ(0, GetProfilerTicks(f->shared()));
   2706 }
   2707 
   2708 
   2709 TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
   2710   i::FLAG_stress_compaction = false;
   2711   i::FLAG_allow_natives_syntax = true;
   2712 #ifdef VERIFY_HEAP
   2713   i::FLAG_verify_heap = true;
   2714 #endif
   2715 
   2716   CcTest::InitializeVM();
   2717   if (!CcTest::i_isolate()->use_crankshaft()) return;
   2718   v8::HandleScope outer_scope(CcTest::isolate());
   2719   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   2720 
   2721   {
   2722     v8::HandleScope scope(CcTest::isolate());
   2723     CompileRun(
   2724         "function f () {"
   2725         "  var s = 0;"
   2726         "  for (var i = 0; i < 100; i++)  s += i;"
   2727         "  return s;"
   2728         "}"
   2729         "f(); f();"
   2730         "%OptimizeFunctionOnNextCall(f);"
   2731         "f();");
   2732   }
   2733   i::Handle<JSFunction> f = i::Handle<JSFunction>::cast(
   2734       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   2735           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   2736   CHECK(f->IsOptimized());
   2737 
   2738   // Make sure incremental marking it not running.
   2739   CcTest::heap()->incremental_marking()->Stop();
   2740 
   2741   // The following two calls will increment CcTest::heap()->global_ic_age().
   2742   CcTest::isolate()->ContextDisposedNotification();
   2743   CcTest::heap()->CollectAllGarbage();
   2744 
   2745   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
   2746   CHECK_EQ(0, f->shared()->opt_count());
   2747   CHECK_EQ(0, GetProfilerTicks(f->shared()));
   2748 }
   2749 
   2750 
   2751 HEAP_TEST(GCFlags) {
   2752   CcTest::InitializeVM();
   2753   Heap* heap = CcTest::heap();
   2754 
   2755   heap->set_current_gc_flags(Heap::kNoGCFlags);
   2756   CHECK_EQ(Heap::kNoGCFlags, heap->current_gc_flags_);
   2757 
   2758   // Set the flags to check whether we appropriately resets them after the GC.
   2759   heap->set_current_gc_flags(Heap::kAbortIncrementalMarkingMask);
   2760   heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
   2761   CHECK_EQ(Heap::kNoGCFlags, heap->current_gc_flags_);
   2762 
   2763   MarkCompactCollector* collector = heap->mark_compact_collector();
   2764   if (collector->sweeping_in_progress()) {
   2765     collector->EnsureSweepingCompleted();
   2766   }
   2767 
   2768   IncrementalMarking* marking = heap->incremental_marking();
   2769   marking->Stop();
   2770   heap->StartIncrementalMarking(Heap::kReduceMemoryFootprintMask);
   2771   CHECK_NE(0, heap->current_gc_flags_ & Heap::kReduceMemoryFootprintMask);
   2772 
   2773   heap->CollectGarbage(NEW_SPACE);
   2774   // NewSpace scavenges should not overwrite the flags.
   2775   CHECK_NE(0, heap->current_gc_flags_ & Heap::kReduceMemoryFootprintMask);
   2776 
   2777   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   2778   CHECK_EQ(Heap::kNoGCFlags, heap->current_gc_flags_);
   2779 }
   2780 
   2781 
   2782 TEST(IdleNotificationFinishMarking) {
   2783   i::FLAG_allow_natives_syntax = true;
   2784   CcTest::InitializeVM();
   2785   const int initial_gc_count = CcTest::heap()->gc_count();
   2786   heap::SimulateFullSpace(CcTest::heap()->old_space());
   2787   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   2788   marking->Stop();
   2789   CcTest::heap()->StartIncrementalMarking();
   2790 
   2791   CHECK_EQ(CcTest::heap()->gc_count(), initial_gc_count);
   2792 
   2793   // TODO(hpayer): We cannot write proper unit test right now for heap.
   2794   // The ideal test would call kMaxIdleMarkingDelayCounter to test the
   2795   // marking delay counter.
   2796 
   2797   // Perform a huge incremental marking step but don't complete marking.
   2798   intptr_t bytes_processed = 0;
   2799   do {
   2800     bytes_processed =
   2801         marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
   2802                       IncrementalMarking::FORCE_MARKING,
   2803                       IncrementalMarking::DO_NOT_FORCE_COMPLETION);
   2804     CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
   2805   } while (bytes_processed);
   2806 
   2807   // The next invocations of incremental marking are not going to complete
   2808   // marking
   2809   // since the completion threshold is not reached
   2810   for (size_t i = 0; i < IncrementalMarking::kMaxIdleMarkingDelayCounter - 2;
   2811        i++) {
   2812     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
   2813                   IncrementalMarking::FORCE_MARKING,
   2814                   IncrementalMarking::DO_NOT_FORCE_COMPLETION);
   2815     CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
   2816   }
   2817 
   2818   marking->SetWeakClosureWasOverApproximatedForTesting(true);
   2819 
   2820   // The next idle notification has to finish incremental marking.
   2821   const double kLongIdleTime = 1000.0;
   2822   CcTest::isolate()->IdleNotificationDeadline(
   2823       (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
   2824        static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
   2825       kLongIdleTime);
   2826   CHECK_EQ(CcTest::heap()->gc_count(), initial_gc_count + 1);
   2827 }
   2828 
   2829 
   2830 // Test that HAllocateObject will always return an object in new-space.
   2831 TEST(OptimizedAllocationAlwaysInNewSpace) {
   2832   i::FLAG_allow_natives_syntax = true;
   2833   CcTest::InitializeVM();
   2834   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2835   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2836   v8::HandleScope scope(CcTest::isolate());
   2837   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   2838   heap::SimulateFullSpace(CcTest::heap()->new_space());
   2839   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   2840   v8::Local<v8::Value> res = CompileRun(
   2841       "function c(x) {"
   2842       "  this.x = x;"
   2843       "  for (var i = 0; i < 32; i++) {"
   2844       "    this['x' + i] = x;"
   2845       "  }"
   2846       "}"
   2847       "function f(x) { return new c(x); };"
   2848       "f(1); f(2); f(3);"
   2849       "%OptimizeFunctionOnNextCall(f);"
   2850       "f(4);");
   2851 
   2852   CHECK_EQ(4, res.As<v8::Object>()
   2853                   ->GetRealNamedProperty(ctx, v8_str("x"))
   2854                   .ToLocalChecked()
   2855                   ->Int32Value(ctx)
   2856                   .FromJust());
   2857 
   2858   i::Handle<JSReceiver> o =
   2859       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res));
   2860 
   2861   CHECK(CcTest::heap()->InNewSpace(*o));
   2862 }
   2863 
   2864 
   2865 TEST(OptimizedPretenuringAllocationFolding) {
   2866   i::FLAG_allow_natives_syntax = true;
   2867   i::FLAG_expose_gc = true;
   2868   CcTest::InitializeVM();
   2869   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2870   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2871   v8::HandleScope scope(CcTest::isolate());
   2872   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   2873   // Grow new space unitl maximum capacity reached.
   2874   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2875     CcTest::heap()->new_space()->Grow();
   2876   }
   2877 
   2878   i::ScopedVector<char> source(1024);
   2879   i::SNPrintF(
   2880       source,
   2881       "var number_elements = %d;"
   2882       "var elements = new Array();"
   2883       "function f() {"
   2884       "  for (var i = 0; i < number_elements; i++) {"
   2885       "    elements[i] = [[{}], [1.1]];"
   2886       "  }"
   2887       "  return elements[number_elements-1]"
   2888       "};"
   2889       "f(); gc();"
   2890       "f(); f();"
   2891       "%%OptimizeFunctionOnNextCall(f);"
   2892       "f();",
   2893       AllocationSite::kPretenureMinimumCreated);
   2894 
   2895   v8::Local<v8::Value> res = CompileRun(source.start());
   2896 
   2897   v8::Local<v8::Value> int_array =
   2898       v8::Object::Cast(*res)->Get(ctx, v8_str("0")).ToLocalChecked();
   2899   i::Handle<JSObject> int_array_handle = i::Handle<JSObject>::cast(
   2900       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(int_array)));
   2901   v8::Local<v8::Value> double_array =
   2902       v8::Object::Cast(*res)->Get(ctx, v8_str("1")).ToLocalChecked();
   2903   i::Handle<JSObject> double_array_handle = i::Handle<JSObject>::cast(
   2904       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(double_array)));
   2905 
   2906   i::Handle<JSReceiver> o =
   2907       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res));
   2908   CHECK(CcTest::heap()->InOldSpace(*o));
   2909   CHECK(CcTest::heap()->InOldSpace(*int_array_handle));
   2910   CHECK(CcTest::heap()->InOldSpace(int_array_handle->elements()));
   2911   CHECK(CcTest::heap()->InOldSpace(*double_array_handle));
   2912   CHECK(CcTest::heap()->InOldSpace(double_array_handle->elements()));
   2913 }
   2914 
   2915 
   2916 TEST(OptimizedPretenuringObjectArrayLiterals) {
   2917   i::FLAG_allow_natives_syntax = true;
   2918   i::FLAG_expose_gc = true;
   2919   CcTest::InitializeVM();
   2920   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2921   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2922   v8::HandleScope scope(CcTest::isolate());
   2923 
   2924   // Grow new space unitl maximum capacity reached.
   2925   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2926     CcTest::heap()->new_space()->Grow();
   2927   }
   2928 
   2929   i::ScopedVector<char> source(1024);
   2930   i::SNPrintF(
   2931       source,
   2932       "var number_elements = %d;"
   2933       "var elements = new Array(number_elements);"
   2934       "function f() {"
   2935       "  for (var i = 0; i < number_elements; i++) {"
   2936       "    elements[i] = [{}, {}, {}];"
   2937       "  }"
   2938       "  return elements[number_elements - 1];"
   2939       "};"
   2940       "f(); gc();"
   2941       "f(); f();"
   2942       "%%OptimizeFunctionOnNextCall(f);"
   2943       "f();",
   2944       AllocationSite::kPretenureMinimumCreated);
   2945 
   2946   v8::Local<v8::Value> res = CompileRun(source.start());
   2947 
   2948   i::Handle<JSObject> o = Handle<JSObject>::cast(
   2949       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   2950 
   2951   CHECK(CcTest::heap()->InOldSpace(o->elements()));
   2952   CHECK(CcTest::heap()->InOldSpace(*o));
   2953 }
   2954 
   2955 
   2956 TEST(OptimizedPretenuringMixedInObjectProperties) {
   2957   i::FLAG_allow_natives_syntax = true;
   2958   i::FLAG_expose_gc = true;
   2959   CcTest::InitializeVM();
   2960   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   2961   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   2962   v8::HandleScope scope(CcTest::isolate());
   2963 
   2964   // Grow new space unitl maximum capacity reached.
   2965   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   2966     CcTest::heap()->new_space()->Grow();
   2967   }
   2968 
   2969 
   2970   i::ScopedVector<char> source(1024);
   2971   i::SNPrintF(
   2972       source,
   2973       "var number_elements = %d;"
   2974       "var elements = new Array(number_elements);"
   2975       "function f() {"
   2976       "  for (var i = 0; i < number_elements; i++) {"
   2977       "    elements[i] = {a: {c: 2.2, d: {}}, b: 1.1};"
   2978       "  }"
   2979       "  return elements[number_elements - 1];"
   2980       "};"
   2981       "f(); gc();"
   2982       "f(); f();"
   2983       "%%OptimizeFunctionOnNextCall(f);"
   2984       "f();",
   2985       AllocationSite::kPretenureMinimumCreated);
   2986 
   2987   v8::Local<v8::Value> res = CompileRun(source.start());
   2988 
   2989   i::Handle<JSObject> o = Handle<JSObject>::cast(
   2990       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   2991 
   2992   CHECK(CcTest::heap()->InOldSpace(*o));
   2993   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
   2994   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
   2995   CHECK(CcTest::heap()->InOldSpace(o->RawFastPropertyAt(idx1)));
   2996   if (!o->IsUnboxedDoubleField(idx2)) {
   2997     CHECK(CcTest::heap()->InOldSpace(o->RawFastPropertyAt(idx2)));
   2998   } else {
   2999     CHECK_EQ(1.1, o->RawFastDoublePropertyAt(idx2));
   3000   }
   3001 
   3002   JSObject* inner_object =
   3003       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   3004   CHECK(CcTest::heap()->InOldSpace(inner_object));
   3005   if (!inner_object->IsUnboxedDoubleField(idx1)) {
   3006     CHECK(CcTest::heap()->InOldSpace(inner_object->RawFastPropertyAt(idx1)));
   3007   } else {
   3008     CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
   3009   }
   3010   CHECK(CcTest::heap()->InOldSpace(inner_object->RawFastPropertyAt(idx2)));
   3011 }
   3012 
   3013 
   3014 TEST(OptimizedPretenuringDoubleArrayProperties) {
   3015   i::FLAG_allow_natives_syntax = true;
   3016   i::FLAG_expose_gc = true;
   3017   CcTest::InitializeVM();
   3018   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3019   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3020   v8::HandleScope scope(CcTest::isolate());
   3021 
   3022   // Grow new space unitl maximum capacity reached.
   3023   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   3024     CcTest::heap()->new_space()->Grow();
   3025   }
   3026 
   3027   i::ScopedVector<char> source(1024);
   3028   i::SNPrintF(
   3029       source,
   3030       "var number_elements = %d;"
   3031       "var elements = new Array(number_elements);"
   3032       "function f() {"
   3033       "  for (var i = 0; i < number_elements; i++) {"
   3034       "    elements[i] = {a: 1.1, b: 2.2};"
   3035       "  }"
   3036       "  return elements[i - 1];"
   3037       "};"
   3038       "f(); gc();"
   3039       "f(); f();"
   3040       "%%OptimizeFunctionOnNextCall(f);"
   3041       "f();",
   3042       AllocationSite::kPretenureMinimumCreated);
   3043 
   3044   v8::Local<v8::Value> res = CompileRun(source.start());
   3045 
   3046   i::Handle<JSObject> o = Handle<JSObject>::cast(
   3047       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3048 
   3049   CHECK(CcTest::heap()->InOldSpace(*o));
   3050   CHECK(CcTest::heap()->InOldSpace(o->properties()));
   3051 }
   3052 
   3053 
   3054 TEST(OptimizedPretenuringdoubleArrayLiterals) {
   3055   i::FLAG_allow_natives_syntax = true;
   3056   i::FLAG_expose_gc = true;
   3057   CcTest::InitializeVM();
   3058   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3059   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3060   v8::HandleScope scope(CcTest::isolate());
   3061 
   3062   // Grow new space unitl maximum capacity reached.
   3063   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   3064     CcTest::heap()->new_space()->Grow();
   3065   }
   3066 
   3067   i::ScopedVector<char> source(1024);
   3068   i::SNPrintF(
   3069       source,
   3070       "var number_elements = %d;"
   3071       "var elements = new Array(number_elements);"
   3072       "function f() {"
   3073       "  for (var i = 0; i < number_elements; i++) {"
   3074       "    elements[i] = [1.1, 2.2, 3.3];"
   3075       "  }"
   3076       "  return elements[number_elements - 1];"
   3077       "};"
   3078       "f(); gc();"
   3079       "f(); f();"
   3080       "%%OptimizeFunctionOnNextCall(f);"
   3081       "f();",
   3082       AllocationSite::kPretenureMinimumCreated);
   3083 
   3084   v8::Local<v8::Value> res = CompileRun(source.start());
   3085 
   3086   i::Handle<JSObject> o = Handle<JSObject>::cast(
   3087       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3088 
   3089   CHECK(CcTest::heap()->InOldSpace(o->elements()));
   3090   CHECK(CcTest::heap()->InOldSpace(*o));
   3091 }
   3092 
   3093 
   3094 TEST(OptimizedPretenuringNestedMixedArrayLiterals) {
   3095   i::FLAG_allow_natives_syntax = true;
   3096   i::FLAG_expose_gc = true;
   3097   CcTest::InitializeVM();
   3098   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3099   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3100   v8::HandleScope scope(CcTest::isolate());
   3101   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3102   // Grow new space unitl maximum capacity reached.
   3103   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   3104     CcTest::heap()->new_space()->Grow();
   3105   }
   3106 
   3107   i::ScopedVector<char> source(1024);
   3108   i::SNPrintF(
   3109       source,
   3110       "var number_elements = 100;"
   3111       "var elements = new Array(number_elements);"
   3112       "function f() {"
   3113       "  for (var i = 0; i < number_elements; i++) {"
   3114       "    elements[i] = [[{}, {}, {}], [1.1, 2.2, 3.3]];"
   3115       "  }"
   3116       "  return elements[number_elements - 1];"
   3117       "};"
   3118       "f(); gc();"
   3119       "f(); f();"
   3120       "%%OptimizeFunctionOnNextCall(f);"
   3121       "f();");
   3122 
   3123   v8::Local<v8::Value> res = CompileRun(source.start());
   3124 
   3125   v8::Local<v8::Value> int_array =
   3126       v8::Object::Cast(*res)->Get(ctx, v8_str("0")).ToLocalChecked();
   3127   i::Handle<JSObject> int_array_handle = i::Handle<JSObject>::cast(
   3128       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(int_array)));
   3129   v8::Local<v8::Value> double_array =
   3130       v8::Object::Cast(*res)->Get(ctx, v8_str("1")).ToLocalChecked();
   3131   i::Handle<JSObject> double_array_handle = i::Handle<JSObject>::cast(
   3132       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(double_array)));
   3133 
   3134   Handle<JSObject> o = Handle<JSObject>::cast(
   3135       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3136   CHECK(CcTest::heap()->InOldSpace(*o));
   3137   CHECK(CcTest::heap()->InOldSpace(*int_array_handle));
   3138   CHECK(CcTest::heap()->InOldSpace(int_array_handle->elements()));
   3139   CHECK(CcTest::heap()->InOldSpace(*double_array_handle));
   3140   CHECK(CcTest::heap()->InOldSpace(double_array_handle->elements()));
   3141 }
   3142 
   3143 
   3144 TEST(OptimizedPretenuringNestedObjectLiterals) {
   3145   i::FLAG_allow_natives_syntax = true;
   3146   i::FLAG_expose_gc = true;
   3147   CcTest::InitializeVM();
   3148   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3149   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3150   v8::HandleScope scope(CcTest::isolate());
   3151   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3152   // Grow new space unitl maximum capacity reached.
   3153   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   3154     CcTest::heap()->new_space()->Grow();
   3155   }
   3156 
   3157   i::ScopedVector<char> source(1024);
   3158   i::SNPrintF(
   3159       source,
   3160       "var number_elements = %d;"
   3161       "var elements = new Array(number_elements);"
   3162       "function f() {"
   3163       "  for (var i = 0; i < number_elements; i++) {"
   3164       "    elements[i] = [[{}, {}, {}],[{}, {}, {}]];"
   3165       "  }"
   3166       "  return elements[number_elements - 1];"
   3167       "};"
   3168       "f(); gc();"
   3169       "f(); f();"
   3170       "%%OptimizeFunctionOnNextCall(f);"
   3171       "f();",
   3172       AllocationSite::kPretenureMinimumCreated);
   3173 
   3174   v8::Local<v8::Value> res = CompileRun(source.start());
   3175 
   3176   v8::Local<v8::Value> int_array_1 =
   3177       v8::Object::Cast(*res)->Get(ctx, v8_str("0")).ToLocalChecked();
   3178   Handle<JSObject> int_array_handle_1 = Handle<JSObject>::cast(
   3179       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(int_array_1)));
   3180   v8::Local<v8::Value> int_array_2 =
   3181       v8::Object::Cast(*res)->Get(ctx, v8_str("1")).ToLocalChecked();
   3182   Handle<JSObject> int_array_handle_2 = Handle<JSObject>::cast(
   3183       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(int_array_2)));
   3184 
   3185   Handle<JSObject> o = Handle<JSObject>::cast(
   3186       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3187   CHECK(CcTest::heap()->InOldSpace(*o));
   3188   CHECK(CcTest::heap()->InOldSpace(*int_array_handle_1));
   3189   CHECK(CcTest::heap()->InOldSpace(int_array_handle_1->elements()));
   3190   CHECK(CcTest::heap()->InOldSpace(*int_array_handle_2));
   3191   CHECK(CcTest::heap()->InOldSpace(int_array_handle_2->elements()));
   3192 }
   3193 
   3194 
   3195 TEST(OptimizedPretenuringNestedDoubleLiterals) {
   3196   i::FLAG_allow_natives_syntax = true;
   3197   i::FLAG_expose_gc = true;
   3198   CcTest::InitializeVM();
   3199   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3200   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3201   v8::HandleScope scope(CcTest::isolate());
   3202   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3203   // Grow new space unitl maximum capacity reached.
   3204   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
   3205     CcTest::heap()->new_space()->Grow();
   3206   }
   3207 
   3208   i::ScopedVector<char> source(1024);
   3209   i::SNPrintF(
   3210       source,
   3211       "var number_elements = %d;"
   3212       "var elements = new Array(number_elements);"
   3213       "function f() {"
   3214       "  for (var i = 0; i < number_elements; i++) {"
   3215       "    elements[i] = [[1.1, 1.2, 1.3],[2.1, 2.2, 2.3]];"
   3216       "  }"
   3217       "  return elements[number_elements - 1];"
   3218       "};"
   3219       "f(); gc();"
   3220       "f(); f();"
   3221       "%%OptimizeFunctionOnNextCall(f);"
   3222       "f();",
   3223       AllocationSite::kPretenureMinimumCreated);
   3224 
   3225   v8::Local<v8::Value> res = CompileRun(source.start());
   3226 
   3227   v8::Local<v8::Value> double_array_1 =
   3228       v8::Object::Cast(*res)->Get(ctx, v8_str("0")).ToLocalChecked();
   3229   i::Handle<JSObject> double_array_handle_1 = i::Handle<JSObject>::cast(
   3230       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(double_array_1)));
   3231   v8::Local<v8::Value> double_array_2 =
   3232       v8::Object::Cast(*res)->Get(ctx, v8_str("1")).ToLocalChecked();
   3233   i::Handle<JSObject> double_array_handle_2 = Handle<JSObject>::cast(
   3234       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(double_array_2)));
   3235 
   3236   i::Handle<JSObject> o = Handle<JSObject>::cast(
   3237       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3238   CHECK(CcTest::heap()->InOldSpace(*o));
   3239   CHECK(CcTest::heap()->InOldSpace(*double_array_handle_1));
   3240   CHECK(CcTest::heap()->InOldSpace(double_array_handle_1->elements()));
   3241   CHECK(CcTest::heap()->InOldSpace(*double_array_handle_2));
   3242   CHECK(CcTest::heap()->InOldSpace(double_array_handle_2->elements()));
   3243 }
   3244 
   3245 
   3246 // Test regular array literals allocation.
   3247 TEST(OptimizedAllocationArrayLiterals) {
   3248   i::FLAG_allow_natives_syntax = true;
   3249   CcTest::InitializeVM();
   3250   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   3251   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
   3252   v8::HandleScope scope(CcTest::isolate());
   3253   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3254   v8::Local<v8::Value> res = CompileRun(
   3255       "function f() {"
   3256       "  var numbers = new Array(1, 2, 3);"
   3257       "  numbers[0] = 3.14;"
   3258       "  return numbers;"
   3259       "};"
   3260       "f(); f(); f();"
   3261       "%OptimizeFunctionOnNextCall(f);"
   3262       "f();");
   3263   CHECK_EQ(static_cast<int>(3.14), v8::Object::Cast(*res)
   3264                                        ->Get(ctx, v8_str("0"))
   3265                                        .ToLocalChecked()
   3266                                        ->Int32Value(ctx)
   3267                                        .FromJust());
   3268 
   3269   i::Handle<JSObject> o = Handle<JSObject>::cast(
   3270       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res)));
   3271 
   3272   CHECK(CcTest::heap()->InNewSpace(o->elements()));
   3273 }
   3274 
   3275 
   3276 static int CountMapTransitions(Map* map) {
   3277   return TransitionArray::NumberOfTransitions(map->raw_transitions());
   3278 }
   3279 
   3280 
   3281 // Test that map transitions are cleared and maps are collected with
   3282 // incremental marking as well.
   3283 TEST(Regress1465) {
   3284   i::FLAG_stress_compaction = false;
   3285   i::FLAG_allow_natives_syntax = true;
   3286   i::FLAG_trace_incremental_marking = true;
   3287   i::FLAG_retain_maps_for_n_gc = 0;
   3288   CcTest::InitializeVM();
   3289   v8::HandleScope scope(CcTest::isolate());
   3290   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3291   static const int transitions_count = 256;
   3292 
   3293   CompileRun("function F() {}");
   3294   {
   3295     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   3296     for (int i = 0; i < transitions_count; i++) {
   3297       EmbeddedVector<char, 64> buffer;
   3298       SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
   3299       CompileRun(buffer.start());
   3300     }
   3301     CompileRun("var root = new F;");
   3302   }
   3303 
   3304   i::Handle<JSReceiver> root =
   3305       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
   3306           CcTest::global()->Get(ctx, v8_str("root")).ToLocalChecked()));
   3307 
   3308   // Count number of live transitions before marking.
   3309   int transitions_before = CountMapTransitions(root->map());
   3310   CompileRun("%DebugPrint(root);");
   3311   CHECK_EQ(transitions_count, transitions_before);
   3312 
   3313   heap::SimulateIncrementalMarking(CcTest::heap());
   3314   CcTest::heap()->CollectAllGarbage();
   3315 
   3316   // Count number of live transitions after marking.  Note that one transition
   3317   // is left, because 'o' still holds an instance of one transition target.
   3318   int transitions_after = CountMapTransitions(root->map());
   3319   CompileRun("%DebugPrint(root);");
   3320   CHECK_EQ(1, transitions_after);
   3321 }
   3322 
   3323 
   3324 #ifdef DEBUG
   3325 static void AddTransitions(int transitions_count) {
   3326   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   3327   for (int i = 0; i < transitions_count; i++) {
   3328     EmbeddedVector<char, 64> buffer;
   3329     SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
   3330     CompileRun(buffer.start());
   3331   }
   3332 }
   3333 
   3334 
   3335 static i::Handle<JSObject> GetByName(const char* name) {
   3336   return i::Handle<JSObject>::cast(
   3337       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
   3338           CcTest::global()
   3339               ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
   3340               .ToLocalChecked())));
   3341 }
   3342 
   3343 
   3344 static void AddPropertyTo(
   3345     int gc_count, Handle<JSObject> object, const char* property_name) {
   3346   Isolate* isolate = CcTest::i_isolate();
   3347   Factory* factory = isolate->factory();
   3348   Handle<String> prop_name = factory->InternalizeUtf8String(property_name);
   3349   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
   3350   i::FLAG_gc_interval = gc_count;
   3351   i::FLAG_gc_global = true;
   3352   i::FLAG_retain_maps_for_n_gc = 0;
   3353   CcTest::heap()->set_allocation_timeout(gc_count);
   3354   JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check();
   3355 }
   3356 
   3357 
   3358 TEST(TransitionArrayShrinksDuringAllocToZero) {
   3359   i::FLAG_stress_compaction = false;
   3360   i::FLAG_allow_natives_syntax = true;
   3361   CcTest::InitializeVM();
   3362   v8::HandleScope scope(CcTest::isolate());
   3363   static const int transitions_count = 10;
   3364   CompileRun("function F() { }");
   3365   AddTransitions(transitions_count);
   3366   CompileRun("var root = new F;");
   3367   Handle<JSObject> root = GetByName("root");
   3368 
   3369   // Count number of live transitions before marking.
   3370   int transitions_before = CountMapTransitions(root->map());
   3371   CHECK_EQ(transitions_count, transitions_before);
   3372 
   3373   // Get rid of o
   3374   CompileRun("o = new F;"
   3375              "root = new F");
   3376   root = GetByName("root");
   3377   AddPropertyTo(2, root, "funny");
   3378   CcTest::heap()->CollectGarbage(NEW_SPACE);
   3379 
   3380   // Count number of live transitions after marking.  Note that one transition
   3381   // is left, because 'o' still holds an instance of one transition target.
   3382   int transitions_after = CountMapTransitions(
   3383       Map::cast(root->map()->GetBackPointer()));
   3384   CHECK_EQ(1, transitions_after);
   3385 }
   3386 
   3387 
   3388 TEST(TransitionArrayShrinksDuringAllocToOne) {
   3389   i::FLAG_stress_compaction = false;
   3390   i::FLAG_allow_natives_syntax = true;
   3391   CcTest::InitializeVM();
   3392   v8::HandleScope scope(CcTest::isolate());
   3393   static const int transitions_count = 10;
   3394   CompileRun("function F() {}");
   3395   AddTransitions(transitions_count);
   3396   CompileRun("var root = new F;");
   3397   Handle<JSObject> root = GetByName("root");
   3398 
   3399   // Count number of live transitions before marking.
   3400   int transitions_before = CountMapTransitions(root->map());
   3401   CHECK_EQ(transitions_count, transitions_before);
   3402 
   3403   root = GetByName("root");
   3404   AddPropertyTo(2, root, "funny");
   3405   CcTest::heap()->CollectGarbage(NEW_SPACE);
   3406 
   3407   // Count number of live transitions after marking.  Note that one transition
   3408   // is left, because 'o' still holds an instance of one transition target.
   3409   int transitions_after = CountMapTransitions(
   3410       Map::cast(root->map()->GetBackPointer()));
   3411   CHECK_EQ(2, transitions_after);
   3412 }
   3413 
   3414 
   3415 TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
   3416   i::FLAG_stress_compaction = false;
   3417   i::FLAG_allow_natives_syntax = true;
   3418   CcTest::InitializeVM();
   3419   v8::HandleScope scope(CcTest::isolate());
   3420   static const int transitions_count = 10;
   3421   CompileRun("function F() {}");
   3422   AddTransitions(transitions_count);
   3423   CompileRun("var root = new F;");
   3424   Handle<JSObject> root = GetByName("root");
   3425 
   3426   // Count number of live transitions before marking.
   3427   int transitions_before = CountMapTransitions(root->map());
   3428   CHECK_EQ(transitions_count, transitions_before);
   3429 
   3430   root = GetByName("root");
   3431   AddPropertyTo(0, root, "prop9");
   3432   CcTest::i_isolate()->heap()->CollectGarbage(OLD_SPACE);
   3433 
   3434   // Count number of live transitions after marking.  Note that one transition
   3435   // is left, because 'o' still holds an instance of one transition target.
   3436   int transitions_after = CountMapTransitions(
   3437       Map::cast(root->map()->GetBackPointer()));
   3438   CHECK_EQ(1, transitions_after);
   3439 }
   3440 
   3441 
   3442 TEST(TransitionArraySimpleToFull) {
   3443   i::FLAG_stress_compaction = false;
   3444   i::FLAG_allow_natives_syntax = true;
   3445   CcTest::InitializeVM();
   3446   v8::HandleScope scope(CcTest::isolate());
   3447   static const int transitions_count = 1;
   3448   CompileRun("function F() {}");
   3449   AddTransitions(transitions_count);
   3450   CompileRun("var root = new F;");
   3451   Handle<JSObject> root = GetByName("root");
   3452 
   3453   // Count number of live transitions before marking.
   3454   int transitions_before = CountMapTransitions(root->map());
   3455   CHECK_EQ(transitions_count, transitions_before);
   3456 
   3457   CompileRun("o = new F;"
   3458              "root = new F");
   3459   root = GetByName("root");
   3460   CHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions()));
   3461   AddPropertyTo(2, root, "happy");
   3462 
   3463   // Count number of live transitions after marking.  Note that one transition
   3464   // is left, because 'o' still holds an instance of one transition target.
   3465   int transitions_after = CountMapTransitions(
   3466       Map::cast(root->map()->GetBackPointer()));
   3467   CHECK_EQ(1, transitions_after);
   3468 }
   3469 #endif  // DEBUG
   3470 
   3471 
   3472 TEST(Regress2143a) {
   3473   i::FLAG_incremental_marking = true;
   3474   CcTest::InitializeVM();
   3475   v8::HandleScope scope(CcTest::isolate());
   3476 
   3477   // Prepare a map transition from the root object together with a yet
   3478   // untransitioned root object.
   3479   CompileRun("var root = new Object;"
   3480              "root.foo = 0;"
   3481              "root = new Object;");
   3482 
   3483   heap::SimulateIncrementalMarking(CcTest::heap());
   3484 
   3485   // Compile a StoreIC that performs the prepared map transition. This
   3486   // will restart incremental marking and should make sure the root is
   3487   // marked grey again.
   3488   CompileRun("function f(o) {"
   3489              "  o.foo = 0;"
   3490              "}"
   3491              "f(new Object);"
   3492              "f(root);");
   3493 
   3494   // This bug only triggers with aggressive IC clearing.
   3495   CcTest::heap()->AgeInlineCaches();
   3496 
   3497   // Explicitly request GC to perform final marking step and sweeping.
   3498   CcTest::heap()->CollectAllGarbage();
   3499 
   3500   Handle<JSReceiver> root = v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
   3501       CcTest::global()
   3502           ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("root"))
   3503           .ToLocalChecked()));
   3504 
   3505   // The root object should be in a sane state.
   3506   CHECK(root->IsJSObject());
   3507   CHECK(root->map()->IsMap());
   3508 }
   3509 
   3510 
   3511 TEST(Regress2143b) {
   3512   i::FLAG_incremental_marking = true;
   3513   i::FLAG_allow_natives_syntax = true;
   3514   CcTest::InitializeVM();
   3515   v8::HandleScope scope(CcTest::isolate());
   3516 
   3517   // Prepare a map transition from the root object together with a yet
   3518   // untransitioned root object.
   3519   CompileRun("var root = new Object;"
   3520              "root.foo = 0;"
   3521              "root = new Object;");
   3522 
   3523   heap::SimulateIncrementalMarking(CcTest::heap());
   3524 
   3525   // Compile an optimized LStoreNamedField that performs the prepared
   3526   // map transition. This will restart incremental marking and should
   3527   // make sure the root is marked grey again.
   3528   CompileRun("function f(o) {"
   3529              "  o.foo = 0;"
   3530              "}"
   3531              "f(new Object);"
   3532              "f(new Object);"
   3533              "%OptimizeFunctionOnNextCall(f);"
   3534              "f(root);"
   3535              "%DeoptimizeFunction(f);");
   3536 
   3537   // This bug only triggers with aggressive IC clearing.
   3538   CcTest::heap()->AgeInlineCaches();
   3539 
   3540   // Explicitly request GC to perform final marking step and sweeping.
   3541   CcTest::heap()->CollectAllGarbage();
   3542 
   3543   Handle<JSReceiver> root = v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
   3544       CcTest::global()
   3545           ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("root"))
   3546           .ToLocalChecked()));
   3547 
   3548   // The root object should be in a sane state.
   3549   CHECK(root->IsJSObject());
   3550   CHECK(root->map()->IsMap());
   3551 }
   3552 
   3553 
   3554 TEST(ReleaseOverReservedPages) {
   3555   if (FLAG_never_compact) return;
   3556   i::FLAG_trace_gc = true;
   3557   // The optimizer can allocate stuff, messing up the test.
   3558   i::FLAG_crankshaft = false;
   3559   i::FLAG_always_opt = false;
   3560   // Parallel compaction increases fragmentation, depending on how existing
   3561   // memory is distributed. Since this is non-deterministic because of
   3562   // concurrent sweeping, we disable it for this test.
   3563   i::FLAG_parallel_compaction = false;
   3564   // Concurrent sweeping adds non determinism, depending on when memory is
   3565   // available for further reuse.
   3566   i::FLAG_concurrent_sweeping = false;
   3567   // Fast evacuation of pages may result in a different page count in old space.
   3568   i::FLAG_page_promotion = false;
   3569   CcTest::InitializeVM();
   3570   Isolate* isolate = CcTest::i_isolate();
   3571   Factory* factory = isolate->factory();
   3572   Heap* heap = isolate->heap();
   3573   v8::HandleScope scope(CcTest::isolate());
   3574   static const int number_of_test_pages = 20;
   3575 
   3576   // Prepare many pages with low live-bytes count.
   3577   PagedSpace* old_space = heap->old_space();
   3578   const int initial_page_count = old_space->CountTotalPages();
   3579   const int overall_page_count = number_of_test_pages + initial_page_count;
   3580   for (int i = 0; i < number_of_test_pages; i++) {
   3581     AlwaysAllocateScope always_allocate(isolate);
   3582     heap::SimulateFullSpace(old_space);
   3583     factory->NewFixedArray(1, TENURED);
   3584   }
   3585   CHECK_EQ(overall_page_count, old_space->CountTotalPages());
   3586 
   3587   // Triggering one GC will cause a lot of garbage to be discovered but
   3588   // even spread across all allocated pages.
   3589   heap->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
   3590                           "triggered for preparation");
   3591   CHECK_GE(overall_page_count, old_space->CountTotalPages());
   3592 
   3593   // Triggering subsequent GCs should cause at least half of the pages
   3594   // to be released to the OS after at most two cycles.
   3595   heap->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
   3596                           "triggered by test 1");
   3597   CHECK_GE(overall_page_count, old_space->CountTotalPages());
   3598   heap->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
   3599                           "triggered by test 2");
   3600   CHECK_GE(overall_page_count, old_space->CountTotalPages() * 2);
   3601 
   3602   // Triggering a last-resort GC should cause all pages to be released to the
   3603   // OS so that other processes can seize the memory.  If we get a failure here
   3604   // where there are 2 pages left instead of 1, then we should increase the
   3605   // size of the first page a little in SizeOfFirstPage in spaces.cc.  The
   3606   // first page should be small in order to reduce memory used when the VM
   3607   // boots, but if the 20 small arrays don't fit on the first page then that's
   3608   // an indication that it is too small.
   3609   heap->CollectAllAvailableGarbage("triggered really hard");
   3610   CHECK_EQ(initial_page_count, old_space->CountTotalPages());
   3611 }
   3612 
   3613 static int forced_gc_counter = 0;
   3614 
   3615 void MockUseCounterCallback(v8::Isolate* isolate,
   3616                             v8::Isolate::UseCounterFeature feature) {
   3617   isolate->GetCurrentContext();
   3618   if (feature == v8::Isolate::kForcedGC) {
   3619     forced_gc_counter++;
   3620   }
   3621 }
   3622 
   3623 
   3624 TEST(CountForcedGC) {
   3625   i::FLAG_expose_gc = true;
   3626   CcTest::InitializeVM();
   3627   Isolate* isolate = CcTest::i_isolate();
   3628   v8::HandleScope scope(CcTest::isolate());
   3629 
   3630   isolate->SetUseCounterCallback(MockUseCounterCallback);
   3631 
   3632   forced_gc_counter = 0;
   3633   const char* source = "gc();";
   3634   CompileRun(source);
   3635   CHECK_GT(forced_gc_counter, 0);
   3636 }
   3637 
   3638 
   3639 #ifdef OBJECT_PRINT
   3640 TEST(PrintSharedFunctionInfo) {
   3641   CcTest::InitializeVM();
   3642   v8::HandleScope scope(CcTest::isolate());
   3643   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3644   const char* source = "f = function() { return 987654321; }\n"
   3645                        "g = function() { return 123456789; }\n";
   3646   CompileRun(source);
   3647   i::Handle<JSFunction> g = i::Handle<JSFunction>::cast(
   3648       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3649           CcTest::global()->Get(ctx, v8_str("g")).ToLocalChecked())));
   3650 
   3651   OFStream os(stdout);
   3652   g->shared()->Print(os);
   3653   os << std::endl;
   3654 }
   3655 #endif  // OBJECT_PRINT
   3656 
   3657 
   3658 TEST(IncrementalMarkingPreservesMonomorphicCallIC) {
   3659   if (i::FLAG_always_opt) return;
   3660   CcTest::InitializeVM();
   3661   v8::HandleScope scope(CcTest::isolate());
   3662   v8::Local<v8::Value> fun1, fun2;
   3663   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3664   {
   3665     CompileRun("function fun() {};");
   3666     fun1 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked();
   3667   }
   3668 
   3669   {
   3670     CompileRun("function fun() {};");
   3671     fun2 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked();
   3672   }
   3673 
   3674   // Prepare function f that contains type feedback for the two closures.
   3675   CHECK(CcTest::global()->Set(ctx, v8_str("fun1"), fun1).FromJust());
   3676   CHECK(CcTest::global()->Set(ctx, v8_str("fun2"), fun2).FromJust());
   3677   CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
   3678 
   3679   Handle<JSFunction> f = Handle<JSFunction>::cast(
   3680       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3681           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   3682 
   3683   Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
   3684   FeedbackVectorHelper feedback_helper(feedback_vector);
   3685 
   3686   int expected_slots = 2;
   3687   CHECK_EQ(expected_slots, feedback_helper.slot_count());
   3688   int slot1 = 0;
   3689   int slot2 = 1;
   3690   CHECK(feedback_vector->Get(feedback_helper.slot(slot1))->IsWeakCell());
   3691   CHECK(feedback_vector->Get(feedback_helper.slot(slot2))->IsWeakCell());
   3692 
   3693   heap::SimulateIncrementalMarking(CcTest::heap());
   3694   CcTest::heap()->CollectAllGarbage();
   3695 
   3696   CHECK(!WeakCell::cast(feedback_vector->Get(feedback_helper.slot(slot1)))
   3697              ->cleared());
   3698   CHECK(!WeakCell::cast(feedback_vector->Get(feedback_helper.slot(slot2)))
   3699              ->cleared());
   3700 }
   3701 
   3702 
   3703 static Code* FindFirstIC(Code* code, Code::Kind kind) {
   3704   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
   3705              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
   3706   for (RelocIterator it(code, mask); !it.done(); it.next()) {
   3707     RelocInfo* info = it.rinfo();
   3708     Code* target = Code::GetCodeFromTargetAddress(info->target_address());
   3709     if (target->is_inline_cache_stub() && target->kind() == kind) {
   3710       return target;
   3711     }
   3712   }
   3713   return NULL;
   3714 }
   3715 
   3716 
   3717 static void CheckVectorIC(Handle<JSFunction> f, int slot_index,
   3718                           InlineCacheState desired_state) {
   3719   Handle<TypeFeedbackVector> vector =
   3720       Handle<TypeFeedbackVector>(f->feedback_vector());
   3721   FeedbackVectorHelper helper(vector);
   3722   FeedbackVectorSlot slot = helper.slot(slot_index);
   3723   if (vector->GetKind(slot) == FeedbackVectorSlotKind::LOAD_IC) {
   3724     LoadICNexus nexus(vector, slot);
   3725     CHECK(nexus.StateFromFeedback() == desired_state);
   3726   } else {
   3727     CHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot));
   3728     KeyedLoadICNexus nexus(vector, slot);
   3729     CHECK(nexus.StateFromFeedback() == desired_state);
   3730   }
   3731 }
   3732 
   3733 TEST(IncrementalMarkingPreservesMonomorphicConstructor) {
   3734   if (i::FLAG_always_opt) return;
   3735   CcTest::InitializeVM();
   3736   v8::HandleScope scope(CcTest::isolate());
   3737   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3738   // Prepare function f that contains a monomorphic IC for object
   3739   // originating from the same native context.
   3740   CompileRun(
   3741       "function fun() { this.x = 1; };"
   3742       "function f(o) { return new o(); } f(fun); f(fun);");
   3743   Handle<JSFunction> f = Handle<JSFunction>::cast(
   3744       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3745           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   3746 
   3747   Handle<TypeFeedbackVector> vector(f->feedback_vector());
   3748   CHECK(vector->Get(FeedbackVectorSlot(0))->IsWeakCell());
   3749 
   3750   heap::SimulateIncrementalMarking(CcTest::heap());
   3751   CcTest::heap()->CollectAllGarbage();
   3752 
   3753   CHECK(vector->Get(FeedbackVectorSlot(0))->IsWeakCell());
   3754 }
   3755 
   3756 TEST(IncrementalMarkingPreservesMonomorphicIC) {
   3757   if (i::FLAG_always_opt) return;
   3758   CcTest::InitializeVM();
   3759   v8::HandleScope scope(CcTest::isolate());
   3760   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3761   // Prepare function f that contains a monomorphic IC for object
   3762   // originating from the same native context.
   3763   CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
   3764              "function f(o) { return o.x; } f(obj); f(obj);");
   3765   Handle<JSFunction> f = Handle<JSFunction>::cast(
   3766       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3767           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   3768 
   3769   CheckVectorIC(f, 0, MONOMORPHIC);
   3770 
   3771   heap::SimulateIncrementalMarking(CcTest::heap());
   3772   CcTest::heap()->CollectAllGarbage();
   3773 
   3774   CheckVectorIC(f, 0, MONOMORPHIC);
   3775 }
   3776 
   3777 TEST(IncrementalMarkingPreservesPolymorphicIC) {
   3778   if (i::FLAG_always_opt) return;
   3779   CcTest::InitializeVM();
   3780   v8::HandleScope scope(CcTest::isolate());
   3781   v8::Local<v8::Value> obj1, obj2;
   3782   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3783 
   3784   {
   3785     LocalContext env;
   3786     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
   3787     obj1 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   3788   }
   3789 
   3790   {
   3791     LocalContext env;
   3792     CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
   3793     obj2 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   3794   }
   3795 
   3796   // Prepare function f that contains a polymorphic IC for objects
   3797   // originating from two different native contexts.
   3798   CHECK(CcTest::global()->Set(ctx, v8_str("obj1"), obj1).FromJust());
   3799   CHECK(CcTest::global()->Set(ctx, v8_str("obj2"), obj2).FromJust());
   3800   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
   3801   Handle<JSFunction> f = Handle<JSFunction>::cast(
   3802       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3803           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   3804 
   3805   CheckVectorIC(f, 0, POLYMORPHIC);
   3806 
   3807   // Fire context dispose notification.
   3808   heap::SimulateIncrementalMarking(CcTest::heap());
   3809   CcTest::heap()->CollectAllGarbage();
   3810 
   3811   CheckVectorIC(f, 0, POLYMORPHIC);
   3812 }
   3813 
   3814 TEST(ContextDisposeDoesntClearPolymorphicIC) {
   3815   if (i::FLAG_always_opt) return;
   3816   CcTest::InitializeVM();
   3817   v8::HandleScope scope(CcTest::isolate());
   3818   v8::Local<v8::Value> obj1, obj2;
   3819   v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
   3820 
   3821   {
   3822     LocalContext env;
   3823     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
   3824     obj1 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   3825   }
   3826 
   3827   {
   3828     LocalContext env;
   3829     CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
   3830     obj2 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   3831   }
   3832 
   3833   // Prepare function f that contains a polymorphic IC for objects
   3834   // originating from two different native contexts.
   3835   CHECK(CcTest::global()->Set(ctx, v8_str("obj1"), obj1).FromJust());
   3836   CHECK(CcTest::global()->Set(ctx, v8_str("obj2"), obj2).FromJust());
   3837   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
   3838   Handle<JSFunction> f = Handle<JSFunction>::cast(
   3839       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3840           CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked())));
   3841 
   3842   CheckVectorIC(f, 0, POLYMORPHIC);
   3843 
   3844   // Fire context dispose notification.
   3845   CcTest::isolate()->ContextDisposedNotification();
   3846   heap::SimulateIncrementalMarking(CcTest::heap());
   3847   CcTest::heap()->CollectAllGarbage();
   3848 
   3849   CheckVectorIC(f, 0, POLYMORPHIC);
   3850 }
   3851 
   3852 
   3853 class SourceResource : public v8::String::ExternalOneByteStringResource {
   3854  public:
   3855   explicit SourceResource(const char* data)
   3856     : data_(data), length_(strlen(data)) { }
   3857 
   3858   virtual void Dispose() {
   3859     i::DeleteArray(data_);
   3860     data_ = NULL;
   3861   }
   3862 
   3863   const char* data() const { return data_; }
   3864 
   3865   size_t length() const { return length_; }
   3866 
   3867   bool IsDisposed() { return data_ == NULL; }
   3868 
   3869  private:
   3870   const char* data_;
   3871   size_t length_;
   3872 };
   3873 
   3874 
   3875 void ReleaseStackTraceDataTest(v8::Isolate* isolate, const char* source,
   3876                                const char* accessor) {
   3877   // Test that the data retained by the Error.stack accessor is released
   3878   // after the first time the accessor is fired.  We use external string
   3879   // to check whether the data is being released since the external string
   3880   // resource's callback is fired when the external string is GC'ed.
   3881   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   3882   v8::HandleScope scope(isolate);
   3883   SourceResource* resource = new SourceResource(i::StrDup(source));
   3884   {
   3885     v8::HandleScope scope(isolate);
   3886     v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
   3887     v8::Local<v8::String> source_string =
   3888         v8::String::NewExternalOneByte(isolate, resource).ToLocalChecked();
   3889     i_isolate->heap()->CollectAllAvailableGarbage();
   3890     v8::Script::Compile(ctx, source_string)
   3891         .ToLocalChecked()
   3892         ->Run(ctx)
   3893         .ToLocalChecked();
   3894     CHECK(!resource->IsDisposed());
   3895   }
   3896   // i_isolate->heap()->CollectAllAvailableGarbage();
   3897   CHECK(!resource->IsDisposed());
   3898 
   3899   CompileRun(accessor);
   3900   i_isolate->heap()->CollectAllAvailableGarbage();
   3901 
   3902   // External source has been released.
   3903   CHECK(resource->IsDisposed());
   3904   delete resource;
   3905 }
   3906 
   3907 
   3908 UNINITIALIZED_TEST(ReleaseStackTraceData) {
   3909   if (i::FLAG_always_opt) {
   3910     // TODO(ulan): Remove this once the memory leak via code_next_link is fixed.
   3911     // See: https://codereview.chromium.org/181833004/
   3912     return;
   3913   }
   3914   FLAG_use_ic = false;  // ICs retain objects.
   3915   FLAG_concurrent_recompilation = false;
   3916   v8::Isolate::CreateParams create_params;
   3917   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
   3918   v8::Isolate* isolate = v8::Isolate::New(create_params);
   3919   {
   3920     v8::Isolate::Scope isolate_scope(isolate);
   3921     v8::HandleScope handle_scope(isolate);
   3922     v8::Context::New(isolate)->Enter();
   3923     static const char* source1 = "var error = null;            "
   3924     /* Normal Error */           "try {                        "
   3925                                  "  throw new Error();         "
   3926                                  "} catch (e) {                "
   3927                                  "  error = e;                 "
   3928                                  "}                            ";
   3929     static const char* source2 = "var error = null;            "
   3930     /* Stack overflow */         "try {                        "
   3931                                  "  (function f() { f(); })(); "
   3932                                  "} catch (e) {                "
   3933                                  "  error = e;                 "
   3934                                  "}                            ";
   3935     static const char* source3 = "var error = null;            "
   3936     /* Normal Error */           "try {                        "
   3937     /* as prototype */           "  throw new Error();         "
   3938                                  "} catch (e) {                "
   3939                                  "  error = {};                "
   3940                                  "  error.__proto__ = e;       "
   3941                                  "}                            ";
   3942     static const char* source4 = "var error = null;            "
   3943     /* Stack overflow */         "try {                        "
   3944     /* as prototype   */         "  (function f() { f(); })(); "
   3945                                  "} catch (e) {                "
   3946                                  "  error = {};                "
   3947                                  "  error.__proto__ = e;       "
   3948                                  "}                            ";
   3949     static const char* getter = "error.stack";
   3950     static const char* setter = "error.stack = 0";
   3951 
   3952     ReleaseStackTraceDataTest(isolate, source1, setter);
   3953     ReleaseStackTraceDataTest(isolate, source2, setter);
   3954     // We do not test source3 and source4 with setter, since the setter is
   3955     // supposed to (untypically) write to the receiver, not the holder.  This is
   3956     // to emulate the behavior of a data property.
   3957 
   3958     ReleaseStackTraceDataTest(isolate, source1, getter);
   3959     ReleaseStackTraceDataTest(isolate, source2, getter);
   3960     ReleaseStackTraceDataTest(isolate, source3, getter);
   3961     ReleaseStackTraceDataTest(isolate, source4, getter);
   3962   }
   3963   isolate->Dispose();
   3964 }
   3965 
   3966 
   3967 TEST(Regress159140) {
   3968   i::FLAG_allow_natives_syntax = true;
   3969   CcTest::InitializeVM();
   3970   Isolate* isolate = CcTest::i_isolate();
   3971   LocalContext env;
   3972   Heap* heap = isolate->heap();
   3973   HandleScope scope(isolate);
   3974 
   3975   // Perform one initial GC to enable code flushing.
   3976   heap->CollectAllGarbage();
   3977 
   3978   // Prepare several closures that are all eligible for code flushing
   3979   // because all reachable ones are not optimized. Make sure that the
   3980   // optimized code object is directly reachable through a handle so
   3981   // that it is marked black during incremental marking.
   3982   Handle<Code> code;
   3983   {
   3984     HandleScope inner_scope(isolate);
   3985     CompileRun("function h(x) {}"
   3986                "function mkClosure() {"
   3987                "  return function(x) { return x + 1; };"
   3988                "}"
   3989                "var f = mkClosure();"
   3990                "var g = mkClosure();"
   3991                "f(1); f(2);"
   3992                "g(1); g(2);"
   3993                "h(1); h(2);"
   3994                "%OptimizeFunctionOnNextCall(f); f(3);"
   3995                "%OptimizeFunctionOnNextCall(h); h(3);");
   3996 
   3997     Handle<JSFunction> f = Handle<JSFunction>::cast(
   3998         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   3999             CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
   4000     CHECK(f->is_compiled());
   4001     CompileRun("f = null;");
   4002 
   4003     Handle<JSFunction> g = Handle<JSFunction>::cast(
   4004         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4005             CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
   4006     CHECK(g->is_compiled());
   4007     const int kAgingThreshold = 6;
   4008     for (int i = 0; i < kAgingThreshold; i++) {
   4009       g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   4010     }
   4011 
   4012     code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
   4013   }
   4014 
   4015   // Simulate incremental marking so that the functions are enqueued as
   4016   // code flushing candidates. Then optimize one function. Finally
   4017   // finish the GC to complete code flushing.
   4018   heap::SimulateIncrementalMarking(heap);
   4019   CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
   4020   heap->CollectAllGarbage();
   4021 
   4022   // Unoptimized code is missing and the deoptimizer will go ballistic.
   4023   CompileRun("g('bozo');");
   4024 }
   4025 
   4026 
   4027 TEST(Regress165495) {
   4028   i::FLAG_allow_natives_syntax = true;
   4029   CcTest::InitializeVM();
   4030   Isolate* isolate = CcTest::i_isolate();
   4031   Heap* heap = isolate->heap();
   4032   HandleScope scope(isolate);
   4033 
   4034   // Perform one initial GC to enable code flushing.
   4035   heap->CollectAllGarbage();
   4036 
   4037   // Prepare an optimized closure that the optimized code map will get
   4038   // populated. Then age the unoptimized code to trigger code flushing
   4039   // but make sure the optimized code is unreachable.
   4040   {
   4041     HandleScope inner_scope(isolate);
   4042     LocalContext env;
   4043     CompileRun("function mkClosure() {"
   4044                "  return function(x) { return x + 1; };"
   4045                "}"
   4046                "var f = mkClosure();"
   4047                "f(1); f(2);"
   4048                "%OptimizeFunctionOnNextCall(f); f(3);");
   4049 
   4050     Handle<JSFunction> f = Handle<JSFunction>::cast(
   4051         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4052             CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
   4053     CHECK(f->is_compiled());
   4054     const int kAgingThreshold = 6;
   4055     for (int i = 0; i < kAgingThreshold; i++) {
   4056       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   4057     }
   4058 
   4059     CompileRun("f = null;");
   4060   }
   4061 
   4062   // Simulate incremental marking so that unoptimized code is flushed
   4063   // even though it still is cached in the optimized code map.
   4064   heap::SimulateIncrementalMarking(heap);
   4065   heap->CollectAllGarbage();
   4066 
   4067   // Make a new closure that will get code installed from the code map.
   4068   // Unoptimized code is missing and the deoptimizer will go ballistic.
   4069   CompileRun("var g = mkClosure(); g('bozo');");
   4070 }
   4071 
   4072 
   4073 TEST(Regress169209) {
   4074   i::FLAG_stress_compaction = false;
   4075   i::FLAG_allow_natives_syntax = true;
   4076 
   4077   CcTest::InitializeVM();
   4078   Isolate* isolate = CcTest::i_isolate();
   4079   Heap* heap = isolate->heap();
   4080   HandleScope scope(isolate);
   4081 
   4082   // Perform one initial GC to enable code flushing.
   4083   heap->CollectAllGarbage();
   4084 
   4085   // Prepare a shared function info eligible for code flushing for which
   4086   // the unoptimized code will be replaced during optimization.
   4087   Handle<SharedFunctionInfo> shared1;
   4088   {
   4089     HandleScope inner_scope(isolate);
   4090     LocalContext env;
   4091     CompileRun("function f() { return 'foobar'; }"
   4092                "function g(x) { if (x) f(); }"
   4093                "f();"
   4094                "g(false);"
   4095                "g(false);");
   4096 
   4097     Handle<JSFunction> f = Handle<JSFunction>::cast(
   4098         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4099             CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
   4100     CHECK(f->is_compiled());
   4101     const int kAgingThreshold = 6;
   4102     for (int i = 0; i < kAgingThreshold; i++) {
   4103       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   4104     }
   4105 
   4106     shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   4107   }
   4108 
   4109   // Prepare a shared function info eligible for code flushing that will
   4110   // represent the dangling tail of the candidate list.
   4111   Handle<SharedFunctionInfo> shared2;
   4112   {
   4113     HandleScope inner_scope(isolate);
   4114     LocalContext env;
   4115     CompileRun("function flushMe() { return 0; }"
   4116                "flushMe(1);");
   4117 
   4118     Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
   4119         *v8::Local<v8::Function>::Cast(CcTest::global()
   4120                                            ->Get(env.local(), v8_str("flushMe"))
   4121                                            .ToLocalChecked())));
   4122     CHECK(f->is_compiled());
   4123     const int kAgingThreshold = 6;
   4124     for (int i = 0; i < kAgingThreshold; i++) {
   4125       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   4126     }
   4127 
   4128     shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   4129   }
   4130 
   4131   // Simulate incremental marking and collect code flushing candidates.
   4132   heap::SimulateIncrementalMarking(heap);
   4133   CHECK(shared1->code()->gc_metadata() != NULL);
   4134 
   4135   // Optimize function and make sure the unoptimized code is replaced.
   4136   CompileRun("%OptimizeFunctionOnNextCall(g);"
   4137              "g(false);");
   4138 
   4139   // Finish garbage collection cycle.
   4140   heap->CollectAllGarbage();
   4141   CHECK(shared1->code()->gc_metadata() == NULL);
   4142 }
   4143 
   4144 
   4145 TEST(Regress169928) {
   4146   i::FLAG_allow_natives_syntax = true;
   4147   i::FLAG_crankshaft = false;
   4148   CcTest::InitializeVM();
   4149   Isolate* isolate = CcTest::i_isolate();
   4150   LocalContext env;
   4151   Factory* factory = isolate->factory();
   4152   v8::HandleScope scope(CcTest::isolate());
   4153 
   4154   // Some flags turn Scavenge collections into Mark-sweep collections
   4155   // and hence are incompatible with this test case.
   4156   if (FLAG_gc_global || FLAG_stress_compaction) return;
   4157 
   4158   // Prepare the environment
   4159   CompileRun("function fastliteralcase(literal, value) {"
   4160              "    literal[0] = value;"
   4161              "    return literal;"
   4162              "}"
   4163              "function get_standard_literal() {"
   4164              "    var literal = [1, 2, 3];"
   4165              "    return literal;"
   4166              "}"
   4167              "obj = fastliteralcase(get_standard_literal(), 1);"
   4168              "obj = fastliteralcase(get_standard_literal(), 1.5);"
   4169              "obj = fastliteralcase(get_standard_literal(), 2);");
   4170 
   4171   // prepare the heap
   4172   v8::Local<v8::String> mote_code_string =
   4173       v8_str("fastliteralcase(mote, 2.5);");
   4174 
   4175   v8::Local<v8::String> array_name = v8_str("mote");
   4176   CHECK(CcTest::global()
   4177             ->Set(env.local(), array_name, v8::Int32::New(CcTest::isolate(), 0))
   4178             .FromJust());
   4179 
   4180   // First make sure we flip spaces
   4181   CcTest::heap()->CollectGarbage(NEW_SPACE);
   4182 
   4183   // Allocate the object.
   4184   Handle<FixedArray> array_data = factory->NewFixedArray(2, NOT_TENURED);
   4185   array_data->set(0, Smi::FromInt(1));
   4186   array_data->set(1, Smi::FromInt(2));
   4187 
   4188   heap::AllocateAllButNBytes(
   4189       CcTest::heap()->new_space(),
   4190       JSArray::kSize + AllocationMemento::kSize + kPointerSize);
   4191 
   4192   Handle<JSArray> array =
   4193       factory->NewJSArrayWithElements(array_data, FAST_SMI_ELEMENTS);
   4194 
   4195   CHECK_EQ(Smi::FromInt(2), array->length());
   4196   CHECK(array->HasFastSmiOrObjectElements());
   4197 
   4198   // We need filler the size of AllocationMemento object, plus an extra
   4199   // fill pointer value.
   4200   HeapObject* obj = NULL;
   4201   AllocationResult allocation =
   4202       CcTest::heap()->new_space()->AllocateRawUnaligned(
   4203           AllocationMemento::kSize + kPointerSize);
   4204   CHECK(allocation.To(&obj));
   4205   Address addr_obj = obj->address();
   4206   CcTest::heap()->CreateFillerObjectAt(addr_obj,
   4207                                        AllocationMemento::kSize + kPointerSize,
   4208                                        ClearRecordedSlots::kNo);
   4209 
   4210   // Give the array a name, making sure not to allocate strings.
   4211   v8::Local<v8::Object> array_obj = v8::Utils::ToLocal(array);
   4212   CHECK(CcTest::global()->Set(env.local(), array_name, array_obj).FromJust());
   4213 
   4214   // This should crash with a protection violation if we are running a build
   4215   // with the bug.
   4216   AlwaysAllocateScope aa_scope(isolate);
   4217   v8::Script::Compile(env.local(), mote_code_string)
   4218       .ToLocalChecked()
   4219       ->Run(env.local())
   4220       .ToLocalChecked();
   4221 }
   4222 
   4223 
   4224 #ifdef DEBUG
   4225 TEST(Regress513507) {
   4226   i::FLAG_flush_optimized_code_cache = false;
   4227   i::FLAG_allow_natives_syntax = true;
   4228   i::FLAG_gc_global = true;
   4229   CcTest::InitializeVM();
   4230   Isolate* isolate = CcTest::i_isolate();
   4231   LocalContext env;
   4232   Heap* heap = isolate->heap();
   4233   HandleScope scope(isolate);
   4234 
   4235   // Prepare function whose optimized code map we can use.
   4236   Handle<SharedFunctionInfo> shared;
   4237   {
   4238     HandleScope inner_scope(isolate);
   4239     CompileRun("function f() { return 1 }"
   4240                "f(); %OptimizeFunctionOnNextCall(f); f();");
   4241 
   4242     Handle<JSFunction> f = Handle<JSFunction>::cast(
   4243         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4244             CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
   4245     shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   4246     CompileRun("f = null");
   4247   }
   4248 
   4249   // Prepare optimized code that we can use.
   4250   Handle<Code> code;
   4251   {
   4252     HandleScope inner_scope(isolate);
   4253     CompileRun("function g() { return 2 }"
   4254                "g(); %OptimizeFunctionOnNextCall(g); g();");
   4255 
   4256     Handle<JSFunction> g = Handle<JSFunction>::cast(
   4257         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4258             CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
   4259     code = inner_scope.CloseAndEscape(handle(g->code(), isolate));
   4260     if (!code->is_optimized_code()) return;
   4261   }
   4262 
   4263   Handle<TypeFeedbackVector> vector =
   4264       TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
   4265   Handle<LiteralsArray> lit =
   4266       LiteralsArray::New(isolate, vector, shared->num_literals(), TENURED);
   4267   Handle<Context> context(isolate->context());
   4268 
   4269   // Add the new code several times to the optimized code map and also set an
   4270   // allocation timeout so that expanding the code map will trigger a GC.
   4271   heap->set_allocation_timeout(5);
   4272   FLAG_gc_interval = 1000;
   4273   for (int i = 0; i < 10; ++i) {
   4274     BailoutId id = BailoutId(i);
   4275     SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
   4276   }
   4277 }
   4278 #endif  // DEBUG
   4279 
   4280 
   4281 TEST(Regress514122) {
   4282   i::FLAG_flush_optimized_code_cache = false;
   4283   i::FLAG_allow_natives_syntax = true;
   4284   CcTest::InitializeVM();
   4285   Isolate* isolate = CcTest::i_isolate();
   4286   LocalContext env;
   4287   Heap* heap = isolate->heap();
   4288   HandleScope scope(isolate);
   4289 
   4290   // Perfrom one initial GC to enable code flushing.
   4291   CcTest::heap()->CollectAllGarbage();
   4292 
   4293   // Prepare function whose optimized code map we can use.
   4294   Handle<SharedFunctionInfo> shared;
   4295   {
   4296     HandleScope inner_scope(isolate);
   4297     CompileRun("function f() { return 1 }"
   4298                "f(); %OptimizeFunctionOnNextCall(f); f();");
   4299 
   4300     Handle<JSFunction> f = Handle<JSFunction>::cast(
   4301         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4302             CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
   4303     shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   4304     CompileRun("f = null");
   4305   }
   4306 
   4307   // Prepare optimized code that we can use.
   4308   Handle<Code> code;
   4309   {
   4310     HandleScope inner_scope(isolate);
   4311     CompileRun("function g() { return 2 }"
   4312                "g(); %OptimizeFunctionOnNextCall(g); g();");
   4313 
   4314     Handle<JSFunction> g = Handle<JSFunction>::cast(
   4315         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4316             CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
   4317     code = inner_scope.CloseAndEscape(handle(g->code(), isolate));
   4318     if (!code->is_optimized_code()) return;
   4319   }
   4320 
   4321   Handle<TypeFeedbackVector> vector =
   4322       TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
   4323   Handle<LiteralsArray> lit =
   4324       LiteralsArray::New(isolate, vector, shared->num_literals(), TENURED);
   4325   Handle<Context> context(isolate->context());
   4326 
   4327   // Add the code several times to the optimized code map.
   4328   for (int i = 0; i < 3; ++i) {
   4329     HandleScope inner_scope(isolate);
   4330     BailoutId id = BailoutId(i);
   4331     SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
   4332   }
   4333   shared->optimized_code_map()->Print();
   4334 
   4335   // Add the code with a literals array to be evacuated.
   4336   Page* evac_page;
   4337   {
   4338     HandleScope inner_scope(isolate);
   4339     AlwaysAllocateScope always_allocate(isolate);
   4340     // Make sure literal is placed on an old-space evacuation candidate.
   4341     heap::SimulateFullSpace(heap->old_space());
   4342 
   4343     // Make sure there the number of literals is > 0.
   4344     Handle<LiteralsArray> lit =
   4345         LiteralsArray::New(isolate, vector, 23, TENURED);
   4346 
   4347     evac_page = Page::FromAddress(lit->address());
   4348     BailoutId id = BailoutId(100);
   4349     SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
   4350   }
   4351 
   4352   // Heap is ready, force {lit_page} to become an evacuation candidate and
   4353   // simulate incremental marking to enqueue optimized code map.
   4354   FLAG_manual_evacuation_candidates_selection = true;
   4355   evac_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
   4356   heap::SimulateIncrementalMarking(heap);
   4357 
   4358   // No matter whether reachable or not, {boomer} is doomed.
   4359   Handle<Object> boomer(shared->optimized_code_map(), isolate);
   4360 
   4361   // Add the code several times to the optimized code map. This will leave old
   4362   // copies of the optimized code map unreachable but still marked.
   4363   for (int i = 3; i < 6; ++i) {
   4364     HandleScope inner_scope(isolate);
   4365     BailoutId id = BailoutId(i);
   4366     SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
   4367   }
   4368 
   4369   // Trigger a GC to flush out the bug.
   4370   heap->CollectGarbage(i::OLD_SPACE, "fire in the hole");
   4371   boomer->Print();
   4372 }
   4373 
   4374 
   4375 TEST(OptimizedCodeMapReuseEntries) {
   4376   i::FLAG_flush_optimized_code_cache = false;
   4377   i::FLAG_allow_natives_syntax = true;
   4378   // BUG(v8:4598): Since TurboFan doesn't treat maps in code weakly, we can't
   4379   // run this test.
   4380   if (i::FLAG_turbo) return;
   4381   CcTest::InitializeVM();
   4382   v8::Isolate* v8_isolate = CcTest::isolate();
   4383   Isolate* isolate = CcTest::i_isolate();
   4384   Heap* heap = isolate->heap();
   4385   HandleScope scope(isolate);
   4386 
   4387   // Create 3 contexts, allow the 2nd one to be disposed, and verify that
   4388   // a 4th context will re-use the weak slots in the optimized code map
   4389   // to hold data, rather than expanding the map.
   4390   v8::Local<v8::Context> c1 = v8::Context::New(v8_isolate);
   4391   const char* source = "function foo(x) { var l = [1]; return x+l[0]; }";
   4392   v8::ScriptCompiler::Source script_source(
   4393       v8::String::NewFromUtf8(v8_isolate, source, v8::NewStringType::kNormal)
   4394           .ToLocalChecked());
   4395   v8::Local<v8::UnboundScript> indep =
   4396       v8::ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source)
   4397           .ToLocalChecked();
   4398   const char* toplevel = "foo(3); %OptimizeFunctionOnNextCall(foo); foo(3);";
   4399   // Perfrom one initial GC to enable code flushing.
   4400   heap->CollectAllGarbage();
   4401 
   4402   c1->Enter();
   4403   indep->BindToCurrentContext()->Run(c1).ToLocalChecked();
   4404   CompileRun(toplevel);
   4405 
   4406   Handle<SharedFunctionInfo> shared;
   4407   Handle<JSFunction> foo = Handle<JSFunction>::cast(
   4408       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4409           CcTest::global()->Get(c1, v8_str("foo")).ToLocalChecked())));
   4410   CHECK(foo->shared()->is_compiled());
   4411   shared = handle(foo->shared());
   4412   c1->Exit();
   4413 
   4414   {
   4415     HandleScope scope(isolate);
   4416     v8::Local<v8::Context> c2 = v8::Context::New(v8_isolate);
   4417     c2->Enter();
   4418     indep->BindToCurrentContext()->Run(c2).ToLocalChecked();
   4419     CompileRun(toplevel);
   4420     c2->Exit();
   4421   }
   4422 
   4423   {
   4424     HandleScope scope(isolate);
   4425     v8::Local<v8::Context> c3 = v8::Context::New(v8_isolate);
   4426     c3->Enter();
   4427     indep->BindToCurrentContext()->Run(c3).ToLocalChecked();
   4428     CompileRun(toplevel);
   4429     c3->Exit();
   4430 
   4431     // Now, collect garbage. Context c2 should have no roots to it, and it's
   4432     // entry in the optimized code map should be free for a new context.
   4433     for (int i = 0; i < 4; i++) {
   4434       heap->CollectAllGarbage();
   4435     }
   4436 
   4437     Handle<FixedArray> optimized_code_map =
   4438         handle(shared->optimized_code_map());
   4439     // There should be 3 entries in the map.
   4440     CHECK_EQ(
   4441         3, ((optimized_code_map->length() - SharedFunctionInfo::kEntriesStart) /
   4442             SharedFunctionInfo::kEntryLength));
   4443     // But one of them (formerly for c2) should be cleared.
   4444     int cleared_count = 0;
   4445     for (int i = SharedFunctionInfo::kEntriesStart;
   4446          i < optimized_code_map->length();
   4447          i += SharedFunctionInfo::kEntryLength) {
   4448       cleared_count +=
   4449           WeakCell::cast(
   4450               optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
   4451                   ->cleared()
   4452               ? 1
   4453               : 0;
   4454     }
   4455     CHECK_EQ(1, cleared_count);
   4456 
   4457     // Verify that a new context uses the cleared entry rather than creating a
   4458     // new
   4459     // optimized code map array.
   4460     v8::Local<v8::Context> c4 = v8::Context::New(v8_isolate);
   4461     c4->Enter();
   4462     indep->BindToCurrentContext()->Run(c4).ToLocalChecked();
   4463     CompileRun(toplevel);
   4464     c4->Exit();
   4465     CHECK_EQ(*optimized_code_map, shared->optimized_code_map());
   4466 
   4467     // Now each entry is in use.
   4468     cleared_count = 0;
   4469     for (int i = SharedFunctionInfo::kEntriesStart;
   4470          i < optimized_code_map->length();
   4471          i += SharedFunctionInfo::kEntryLength) {
   4472       cleared_count +=
   4473           WeakCell::cast(
   4474               optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
   4475                   ->cleared()
   4476               ? 1
   4477               : 0;
   4478     }
   4479     CHECK_EQ(0, cleared_count);
   4480   }
   4481 }
   4482 
   4483 
   4484 TEST(Regress513496) {
   4485   i::FLAG_flush_optimized_code_cache = false;
   4486   i::FLAG_allow_natives_syntax = true;
   4487   CcTest::InitializeVM();
   4488   Isolate* isolate = CcTest::i_isolate();
   4489   Heap* heap = isolate->heap();
   4490   HandleScope scope(isolate);
   4491 
   4492   // Perfrom one initial GC to enable code flushing.
   4493   CcTest::heap()->CollectAllGarbage();
   4494 
   4495   // Prepare an optimized closure with containing an inlined function. Then age
   4496   // the inlined unoptimized code to trigger code flushing but make sure the
   4497   // outer optimized code is kept in the optimized code map.
   4498   Handle<SharedFunctionInfo> shared;
   4499   {
   4500     LocalContext context;
   4501     HandleScope inner_scope(isolate);
   4502     CompileRun(
   4503         "function g(x) { return x + 1 }"
   4504         "function mkClosure() {"
   4505         "  return function(x) { return g(x); };"
   4506         "}"
   4507         "var f = mkClosure();"
   4508         "f(1); f(2);"
   4509         "%OptimizeFunctionOnNextCall(f); f(3);");
   4510 
   4511     Handle<JSFunction> g = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
   4512         *v8::Local<v8::Function>::Cast(CcTest::global()
   4513                                            ->Get(context.local(), v8_str("g"))
   4514                                            .ToLocalChecked())));
   4515     CHECK(g->shared()->is_compiled());
   4516     const int kAgingThreshold = 6;
   4517     for (int i = 0; i < kAgingThreshold; i++) {
   4518       g->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
   4519     }
   4520 
   4521     Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
   4522         *v8::Local<v8::Function>::Cast(CcTest::global()
   4523                                            ->Get(context.local(), v8_str("f"))
   4524                                            .ToLocalChecked())));
   4525     CHECK(f->is_compiled());
   4526     shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
   4527     CompileRun("f = null");
   4528   }
   4529 
   4530   // Lookup the optimized code and keep it alive.
   4531   CodeAndLiterals result = shared->SearchOptimizedCodeMap(
   4532       isolate->context()->native_context(), BailoutId::None());
   4533   Handle<Code> optimized_code(result.code, isolate);
   4534 
   4535   // Finish a full GC cycle so that the unoptimized code of 'g' is flushed even
   4536   // though the optimized code for 'f' is reachable via the optimized code map.
   4537   heap->CollectAllGarbage();
   4538 
   4539   // Make a new closure that will get code installed from the code map.
   4540   // Unoptimized code is missing and the deoptimizer will go ballistic.
   4541   CompileRun("var h = mkClosure(); h('bozo');");
   4542 }
   4543 
   4544 
   4545 TEST(LargeObjectSlotRecording) {
   4546   FLAG_manual_evacuation_candidates_selection = true;
   4547   CcTest::InitializeVM();
   4548   Isolate* isolate = CcTest::i_isolate();
   4549   Heap* heap = isolate->heap();
   4550   HandleScope scope(isolate);
   4551 
   4552   // Create an object on an evacuation candidate.
   4553   heap::SimulateFullSpace(heap->old_space());
   4554   Handle<FixedArray> lit = isolate->factory()->NewFixedArray(4, TENURED);
   4555   Page* evac_page = Page::FromAddress(lit->address());
   4556   evac_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
   4557   FixedArray* old_location = *lit;
   4558 
   4559   // Allocate a large object.
   4560   int size = Max(1000000, Page::kMaxRegularHeapObjectSize + KB);
   4561   CHECK(size > Page::kMaxRegularHeapObjectSize);
   4562   Handle<FixedArray> lo = isolate->factory()->NewFixedArray(size, TENURED);
   4563   CHECK(heap->lo_space()->Contains(*lo));
   4564 
   4565   // Start incremental marking to active write barrier.
   4566   heap::SimulateIncrementalMarking(heap, false);
   4567   heap->incremental_marking()->AdvanceIncrementalMarking(
   4568       10000000, IncrementalMarking::IdleStepActions());
   4569 
   4570   // Create references from the large object to the object on the evacuation
   4571   // candidate.
   4572   const int kStep = size / 10;
   4573   for (int i = 0; i < size; i += kStep) {
   4574     lo->set(i, *lit);
   4575     CHECK(lo->get(i) == old_location);
   4576   }
   4577 
   4578   // Move the evaucation candidate object.
   4579   CcTest::heap()->CollectAllGarbage();
   4580 
   4581   // Verify that the pointers in the large object got updated.
   4582   for (int i = 0; i < size; i += kStep) {
   4583     CHECK_EQ(lo->get(i), *lit);
   4584     CHECK(lo->get(i) != old_location);
   4585   }
   4586 }
   4587 
   4588 
   4589 class DummyVisitor : public ObjectVisitor {
   4590  public:
   4591   void VisitPointers(Object** start, Object** end) override {}
   4592 };
   4593 
   4594 
   4595 TEST(DeferredHandles) {
   4596   CcTest::InitializeVM();
   4597   Isolate* isolate = CcTest::i_isolate();
   4598   Heap* heap = isolate->heap();
   4599   v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
   4600   HandleScopeData* data = isolate->handle_scope_data();
   4601   Handle<Object> init(heap->empty_string(), isolate);
   4602   while (data->next < data->limit) {
   4603     Handle<Object> obj(heap->empty_string(), isolate);
   4604   }
   4605   // An entire block of handles has been filled.
   4606   // Next handle would require a new block.
   4607   CHECK(data->next == data->limit);
   4608 
   4609   DeferredHandleScope deferred(isolate);
   4610   DummyVisitor visitor;
   4611   isolate->handle_scope_implementer()->Iterate(&visitor);
   4612   delete deferred.Detach();
   4613 }
   4614 
   4615 
   4616 TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
   4617   CcTest::InitializeVM();
   4618   v8::HandleScope scope(CcTest::isolate());
   4619   CompileRun("function f(n) {"
   4620              "    var a = new Array(n);"
   4621              "    for (var i = 0; i < n; i += 100) a[i] = i;"
   4622              "};"
   4623              "f(10 * 1024 * 1024);");
   4624   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   4625   if (marking->IsStopped()) {
   4626     CcTest::heap()->StartIncrementalMarking();
   4627   }
   4628   // This big step should be sufficient to mark the whole array.
   4629   marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   4630   CHECK(marking->IsComplete() ||
   4631         marking->IsReadyToOverApproximateWeakClosure());
   4632 }
   4633 
   4634 
   4635 TEST(DisableInlineAllocation) {
   4636   i::FLAG_allow_natives_syntax = true;
   4637   CcTest::InitializeVM();
   4638   v8::HandleScope scope(CcTest::isolate());
   4639   CompileRun("function test() {"
   4640              "  var x = [];"
   4641              "  for (var i = 0; i < 10; i++) {"
   4642              "    x[i] = [ {}, [1,2,3], [1,x,3] ];"
   4643              "  }"
   4644              "}"
   4645              "function run() {"
   4646              "  %OptimizeFunctionOnNextCall(test);"
   4647              "  test();"
   4648              "  %DeoptimizeFunction(test);"
   4649              "}");
   4650 
   4651   // Warm-up with inline allocation enabled.
   4652   CompileRun("test(); test(); run();");
   4653 
   4654   // Run test with inline allocation disabled.
   4655   CcTest::heap()->DisableInlineAllocation();
   4656   CompileRun("run()");
   4657 
   4658   // Run test with inline allocation re-enabled.
   4659   CcTest::heap()->EnableInlineAllocation();
   4660   CompileRun("run()");
   4661 }
   4662 
   4663 
   4664 static int AllocationSitesCount(Heap* heap) {
   4665   int count = 0;
   4666   for (Object* site = heap->allocation_sites_list();
   4667        !(site->IsUndefined(heap->isolate()));
   4668        site = AllocationSite::cast(site)->weak_next()) {
   4669     count++;
   4670   }
   4671   return count;
   4672 }
   4673 
   4674 
   4675 TEST(EnsureAllocationSiteDependentCodesProcessed) {
   4676   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   4677   i::FLAG_allow_natives_syntax = true;
   4678   CcTest::InitializeVM();
   4679   Isolate* isolate = CcTest::i_isolate();
   4680   v8::internal::Heap* heap = CcTest::heap();
   4681   GlobalHandles* global_handles = isolate->global_handles();
   4682 
   4683   if (!isolate->use_crankshaft()) return;
   4684 
   4685   // The allocation site at the head of the list is ours.
   4686   Handle<AllocationSite> site;
   4687   {
   4688     LocalContext context;
   4689     v8::HandleScope scope(context->GetIsolate());
   4690 
   4691     int count = AllocationSitesCount(heap);
   4692     CompileRun("var bar = function() { return (new Array()); };"
   4693                "var a = bar();"
   4694                "bar();"
   4695                "bar();");
   4696 
   4697     // One allocation site should have been created.
   4698     int new_count = AllocationSitesCount(heap);
   4699     CHECK_EQ(new_count, (count + 1));
   4700     site = Handle<AllocationSite>::cast(
   4701         global_handles->Create(
   4702             AllocationSite::cast(heap->allocation_sites_list())));
   4703 
   4704     CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
   4705 
   4706     CHECK_EQ(DependentCode::kAllocationSiteTransitionChangedGroup,
   4707              site->dependent_code()->group());
   4708     CHECK_EQ(1, site->dependent_code()->count());
   4709     CHECK(site->dependent_code()->object_at(0)->IsWeakCell());
   4710     Code* function_bar = Code::cast(
   4711         WeakCell::cast(site->dependent_code()->object_at(0))->value());
   4712     Handle<JSFunction> bar_handle = Handle<JSFunction>::cast(
   4713         v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4714             CcTest::global()
   4715                 ->Get(context.local(), v8_str("bar"))
   4716                 .ToLocalChecked())));
   4717     CHECK_EQ(bar_handle->code(), function_bar);
   4718   }
   4719 
   4720   // Now make sure that a gc should get rid of the function, even though we
   4721   // still have the allocation site alive.
   4722   for (int i = 0; i < 4; i++) {
   4723     heap->CollectAllGarbage();
   4724   }
   4725 
   4726   // The site still exists because of our global handle, but the code is no
   4727   // longer referred to by dependent_code().
   4728   CHECK(site->dependent_code()->object_at(0)->IsWeakCell() &&
   4729         WeakCell::cast(site->dependent_code()->object_at(0))->cleared());
   4730 }
   4731 
   4732 
   4733 TEST(CellsInOptimizedCodeAreWeak) {
   4734   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   4735   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   4736   i::FLAG_allow_natives_syntax = true;
   4737   CcTest::InitializeVM();
   4738   Isolate* isolate = CcTest::i_isolate();
   4739   v8::internal::Heap* heap = CcTest::heap();
   4740 
   4741   if (!isolate->use_crankshaft()) return;
   4742   HandleScope outer_scope(heap->isolate());
   4743   Handle<Code> code;
   4744   {
   4745     LocalContext context;
   4746     HandleScope scope(heap->isolate());
   4747 
   4748     CompileRun(
   4749         "bar = (function() {"
   4750         "  function bar() {"
   4751         "    return foo(1);"
   4752         "  };"
   4753         "  var foo = function(x) { with (x) { return 1 + x; } };"
   4754         "  %NeverOptimizeFunction(foo);"
   4755         "  bar(foo);"
   4756         "  bar(foo);"
   4757         "  bar(foo);"
   4758         "  %OptimizeFunctionOnNextCall(bar);"
   4759         "  bar(foo);"
   4760         "  return bar;})();");
   4761 
   4762     Handle<JSFunction> bar = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
   4763         *v8::Local<v8::Function>::Cast(CcTest::global()
   4764                                            ->Get(context.local(), v8_str("bar"))
   4765                                            .ToLocalChecked())));
   4766     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
   4767   }
   4768 
   4769   // Now make sure that a gc should get rid of the function
   4770   for (int i = 0; i < 4; i++) {
   4771     heap->CollectAllGarbage();
   4772   }
   4773 
   4774   CHECK(code->marked_for_deoptimization());
   4775 }
   4776 
   4777 
   4778 TEST(ObjectsInOptimizedCodeAreWeak) {
   4779   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   4780   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   4781   i::FLAG_allow_natives_syntax = true;
   4782   CcTest::InitializeVM();
   4783   Isolate* isolate = CcTest::i_isolate();
   4784   v8::internal::Heap* heap = CcTest::heap();
   4785 
   4786   if (!isolate->use_crankshaft()) return;
   4787   HandleScope outer_scope(heap->isolate());
   4788   Handle<Code> code;
   4789   {
   4790     LocalContext context;
   4791     HandleScope scope(heap->isolate());
   4792 
   4793     CompileRun(
   4794         "function bar() {"
   4795         "  return foo(1);"
   4796         "};"
   4797         "function foo(x) { with (x) { return 1 + x; } };"
   4798         "%NeverOptimizeFunction(foo);"
   4799         "bar();"
   4800         "bar();"
   4801         "bar();"
   4802         "%OptimizeFunctionOnNextCall(bar);"
   4803         "bar();");
   4804 
   4805     Handle<JSFunction> bar = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
   4806         *v8::Local<v8::Function>::Cast(CcTest::global()
   4807                                            ->Get(context.local(), v8_str("bar"))
   4808                                            .ToLocalChecked())));
   4809     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
   4810   }
   4811 
   4812   // Now make sure that a gc should get rid of the function
   4813   for (int i = 0; i < 4; i++) {
   4814     heap->CollectAllGarbage();
   4815   }
   4816 
   4817   CHECK(code->marked_for_deoptimization());
   4818 }
   4819 
   4820 
   4821 TEST(NoWeakHashTableLeakWithIncrementalMarking) {
   4822   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
   4823   if (!i::FLAG_incremental_marking) return;
   4824   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   4825   i::FLAG_allow_natives_syntax = true;
   4826   i::FLAG_compilation_cache = false;
   4827   i::FLAG_retain_maps_for_n_gc = 0;
   4828   CcTest::InitializeVM();
   4829   Isolate* isolate = CcTest::i_isolate();
   4830 
   4831   // Do not run for no-snap builds.
   4832   if (!i::Snapshot::HaveASnapshotToStartFrom(isolate)) return;
   4833 
   4834   v8::internal::Heap* heap = CcTest::heap();
   4835 
   4836   // Get a clean slate regarding optimized functions on the heap.
   4837   i::Deoptimizer::DeoptimizeAll(isolate);
   4838   heap->CollectAllGarbage();
   4839 
   4840   if (!isolate->use_crankshaft()) return;
   4841   HandleScope outer_scope(heap->isolate());
   4842   for (int i = 0; i < 3; i++) {
   4843     heap::SimulateIncrementalMarking(heap);
   4844     {
   4845       LocalContext context;
   4846       HandleScope scope(heap->isolate());
   4847       EmbeddedVector<char, 256> source;
   4848       SNPrintF(source,
   4849                "function bar%d() {"
   4850                "  return foo%d(1);"
   4851                "};"
   4852                "function foo%d(x) { with (x) { return 1 + x; } };"
   4853                "bar%d();"
   4854                "bar%d();"
   4855                "bar%d();"
   4856                "%%OptimizeFunctionOnNextCall(bar%d);"
   4857                "bar%d();",
   4858                i, i, i, i, i, i, i, i);
   4859       CompileRun(source.start());
   4860     }
   4861     // We have to abort incremental marking here to abandon black pages.
   4862     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   4863   }
   4864   int elements = 0;
   4865   if (heap->weak_object_to_code_table()->IsHashTable()) {
   4866     WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table());
   4867     elements = t->NumberOfElements();
   4868   }
   4869   CHECK_EQ(0, elements);
   4870 }
   4871 
   4872 
   4873 static Handle<JSFunction> OptimizeDummyFunction(v8::Isolate* isolate,
   4874                                                 const char* name) {
   4875   EmbeddedVector<char, 256> source;
   4876   SNPrintF(source,
   4877           "function %s() { return 0; }"
   4878           "%s(); %s();"
   4879           "%%OptimizeFunctionOnNextCall(%s);"
   4880           "%s();", name, name, name, name, name);
   4881   CompileRun(source.start());
   4882   i::Handle<JSFunction> fun = Handle<JSFunction>::cast(
   4883       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4884           CcTest::global()
   4885               ->Get(isolate->GetCurrentContext(), v8_str(name))
   4886               .ToLocalChecked())));
   4887   return fun;
   4888 }
   4889 
   4890 
   4891 static int GetCodeChainLength(Code* code) {
   4892   int result = 0;
   4893   while (code->next_code_link()->IsCode()) {
   4894     result++;
   4895     code = Code::cast(code->next_code_link());
   4896   }
   4897   return result;
   4898 }
   4899 
   4900 
   4901 TEST(NextCodeLinkIsWeak) {
   4902   i::FLAG_always_opt = false;
   4903   i::FLAG_allow_natives_syntax = true;
   4904   CcTest::InitializeVM();
   4905   Isolate* isolate = CcTest::i_isolate();
   4906   v8::internal::Heap* heap = CcTest::heap();
   4907 
   4908   if (!isolate->use_crankshaft()) return;
   4909   HandleScope outer_scope(heap->isolate());
   4910   Handle<Code> code;
   4911   heap->CollectAllAvailableGarbage();
   4912   int code_chain_length_before, code_chain_length_after;
   4913   {
   4914     HandleScope scope(heap->isolate());
   4915     Handle<JSFunction> mortal =
   4916         OptimizeDummyFunction(CcTest::isolate(), "mortal");
   4917     Handle<JSFunction> immortal =
   4918         OptimizeDummyFunction(CcTest::isolate(), "immortal");
   4919     CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
   4920     code_chain_length_before = GetCodeChainLength(immortal->code());
   4921     // Keep the immortal code and let the mortal code die.
   4922     code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
   4923     CompileRun("mortal = null; immortal = null;");
   4924   }
   4925   heap->CollectAllAvailableGarbage();
   4926   // Now mortal code should be dead.
   4927   code_chain_length_after = GetCodeChainLength(*code);
   4928   CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
   4929 }
   4930 
   4931 
   4932 static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
   4933   i::byte buffer[i::Assembler::kMinimalBufferSize];
   4934   MacroAssembler masm(isolate, buffer, sizeof(buffer),
   4935                       v8::internal::CodeObjectRequired::kYes);
   4936   CodeDesc desc;
   4937   masm.Push(isolate->factory()->undefined_value());
   4938   masm.Drop(1);
   4939   masm.GetCode(&desc);
   4940   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
   4941   Handle<Code> code = isolate->factory()->NewCode(
   4942       desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
   4943   CHECK(code->IsCode());
   4944   return code;
   4945 }
   4946 
   4947 
   4948 TEST(NextCodeLinkIsWeak2) {
   4949   i::FLAG_allow_natives_syntax = true;
   4950   CcTest::InitializeVM();
   4951   Isolate* isolate = CcTest::i_isolate();
   4952   v8::internal::Heap* heap = CcTest::heap();
   4953 
   4954   if (!isolate->use_crankshaft()) return;
   4955   HandleScope outer_scope(heap->isolate());
   4956   heap->CollectAllAvailableGarbage();
   4957   Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
   4958   Handle<Code> new_head;
   4959   Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
   4960   {
   4961     HandleScope scope(heap->isolate());
   4962     Handle<Code> immortal = DummyOptimizedCode(isolate);
   4963     Handle<Code> mortal = DummyOptimizedCode(isolate);
   4964     mortal->set_next_code_link(*old_head);
   4965     immortal->set_next_code_link(*mortal);
   4966     context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
   4967     new_head = scope.CloseAndEscape(immortal);
   4968   }
   4969   heap->CollectAllAvailableGarbage();
   4970   // Now mortal code should be dead.
   4971   CHECK_EQ(*old_head, new_head->next_code_link());
   4972 }
   4973 
   4974 
   4975 static bool weak_ic_cleared = false;
   4976 
   4977 static void ClearWeakIC(
   4978     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
   4979   printf("clear weak is called\n");
   4980   weak_ic_cleared = true;
   4981   data.GetParameter()->Reset();
   4982 }
   4983 
   4984 
   4985 TEST(WeakFunctionInConstructor) {
   4986   if (i::FLAG_always_opt) return;
   4987   i::FLAG_stress_compaction = false;
   4988   CcTest::InitializeVM();
   4989   v8::Isolate* isolate = CcTest::isolate();
   4990   LocalContext env;
   4991   v8::HandleScope scope(isolate);
   4992   CompileRun(
   4993       "function createObj(obj) {"
   4994       "  return new obj();"
   4995       "}");
   4996   i::Handle<JSFunction> createObj = Handle<JSFunction>::cast(
   4997       v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
   4998           CcTest::global()
   4999               ->Get(env.local(), v8_str("createObj"))
   5000               .ToLocalChecked())));
   5001 
   5002   v8::Persistent<v8::Object> garbage;
   5003   {
   5004     v8::HandleScope scope(isolate);
   5005     const char* source =
   5006         " (function() {"
   5007         "   function hat() { this.x = 5; }"
   5008         "   createObj(hat);"
   5009         "   createObj(hat);"
   5010         "   return hat;"
   5011         " })();";
   5012     garbage.Reset(isolate, CompileRun(env.local(), source)
   5013                                .ToLocalChecked()
   5014                                ->ToObject(env.local())
   5015                                .ToLocalChecked());
   5016   }
   5017   weak_ic_cleared = false;
   5018   garbage.SetWeak(&garbage, &ClearWeakIC, v8::WeakCallbackType::kParameter);
   5019   Heap* heap = CcTest::i_isolate()->heap();
   5020   heap->CollectAllGarbage();
   5021   CHECK(weak_ic_cleared);
   5022 
   5023   // We've determined the constructor in createObj has had it's weak cell
   5024   // cleared. Now, verify that one additional call with a new function
   5025   // allows monomorphicity.
   5026   Handle<TypeFeedbackVector> feedback_vector = Handle<TypeFeedbackVector>(
   5027       createObj->feedback_vector(), CcTest::i_isolate());
   5028   for (int i = 0; i < 20; i++) {
   5029     Object* slot_value = feedback_vector->Get(FeedbackVectorSlot(0));
   5030     CHECK(slot_value->IsWeakCell());
   5031     if (WeakCell::cast(slot_value)->cleared()) break;
   5032     heap->CollectAllGarbage();
   5033   }
   5034 
   5035   Object* slot_value = feedback_vector->Get(FeedbackVectorSlot(0));
   5036   CHECK(slot_value->IsWeakCell() && WeakCell::cast(slot_value)->cleared());
   5037   CompileRun(
   5038       "function coat() { this.x = 6; }"
   5039       "createObj(coat);");
   5040   slot_value = feedback_vector->Get(FeedbackVectorSlot(0));
   5041   CHECK(slot_value->IsWeakCell() && !WeakCell::cast(slot_value)->cleared());
   5042 }
   5043 
   5044 
   5045 // Checks that the value returned by execution of the source is weak.
   5046 void CheckWeakness(const char* source) {
   5047   i::FLAG_stress_compaction = false;
   5048   CcTest::InitializeVM();
   5049   v8::Isolate* isolate = CcTest::isolate();
   5050   LocalContext env;
   5051   v8::HandleScope scope(isolate);
   5052   v8::Persistent<v8::Object> garbage;
   5053   {
   5054     v8::HandleScope scope(isolate);
   5055     garbage.Reset(isolate, CompileRun(env.local(), source)
   5056                                .ToLocalChecked()
   5057                                ->ToObject(env.local())
   5058                                .ToLocalChecked());
   5059   }
   5060   weak_ic_cleared = false;
   5061   garbage.SetWeak(&garbage, &ClearWeakIC, v8::WeakCallbackType::kParameter);
   5062   Heap* heap = CcTest::i_isolate()->heap();
   5063   heap->CollectAllGarbage();
   5064   CHECK(weak_ic_cleared);
   5065 }
   5066 
   5067 
   5068 // Each of the following "weak IC" tests creates an IC that embeds a map with
   5069 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
   5070 TEST(WeakMapInMonomorphicLoadIC) {
   5071   CheckWeakness("function loadIC(obj) {"
   5072                 "  return obj.name;"
   5073                 "}"
   5074                 " (function() {"
   5075                 "   var proto = {'name' : 'weak'};"
   5076                 "   var obj = Object.create(proto);"
   5077                 "   loadIC(obj);"
   5078                 "   loadIC(obj);"
   5079                 "   loadIC(obj);"
   5080                 "   return proto;"
   5081                 " })();");
   5082 }
   5083 
   5084 
   5085 TEST(WeakMapInPolymorphicLoadIC) {
   5086   CheckWeakness(
   5087       "function loadIC(obj) {"
   5088       "  return obj.name;"
   5089       "}"
   5090       " (function() {"
   5091       "   var proto = {'name' : 'weak'};"
   5092       "   var obj = Object.create(proto);"
   5093       "   loadIC(obj);"
   5094       "   loadIC(obj);"
   5095       "   loadIC(obj);"
   5096       "   var poly = Object.create(proto);"
   5097       "   poly.x = true;"
   5098       "   loadIC(poly);"
   5099       "   return proto;"
   5100       " })();");
   5101 }
   5102 
   5103 
   5104 TEST(WeakMapInMonomorphicKeyedLoadIC) {
   5105   CheckWeakness("function keyedLoadIC(obj, field) {"
   5106                 "  return obj[field];"
   5107                 "}"
   5108                 " (function() {"
   5109                 "   var proto = {'name' : 'weak'};"
   5110                 "   var obj = Object.create(proto);"
   5111                 "   keyedLoadIC(obj, 'name');"
   5112                 "   keyedLoadIC(obj, 'name');"
   5113                 "   keyedLoadIC(obj, 'name');"
   5114                 "   return proto;"
   5115                 " })();");
   5116 }
   5117 
   5118 
   5119 TEST(WeakMapInPolymorphicKeyedLoadIC) {
   5120   CheckWeakness(
   5121       "function keyedLoadIC(obj, field) {"
   5122       "  return obj[field];"
   5123       "}"
   5124       " (function() {"
   5125       "   var proto = {'name' : 'weak'};"
   5126       "   var obj = Object.create(proto);"
   5127       "   keyedLoadIC(obj, 'name');"
   5128       "   keyedLoadIC(obj, 'name');"
   5129       "   keyedLoadIC(obj, 'name');"
   5130       "   var poly = Object.create(proto);"
   5131       "   poly.x = true;"
   5132       "   keyedLoadIC(poly, 'name');"
   5133       "   return proto;"
   5134       " })();");
   5135 }
   5136 
   5137 
   5138 TEST(WeakMapInMonomorphicStoreIC) {
   5139   CheckWeakness("function storeIC(obj, value) {"
   5140                 "  obj.name = value;"
   5141                 "}"
   5142                 " (function() {"
   5143                 "   var proto = {'name' : 'weak'};"
   5144                 "   var obj = Object.create(proto);"
   5145                 "   storeIC(obj, 'x');"
   5146                 "   storeIC(obj, 'x');"
   5147                 "   storeIC(obj, 'x');"
   5148                 "   return proto;"
   5149                 " })();");
   5150 }
   5151 
   5152 
   5153 TEST(WeakMapInPolymorphicStoreIC) {
   5154   CheckWeakness(
   5155       "function storeIC(obj, value) {"
   5156       "  obj.name = value;"
   5157       "}"
   5158       " (function() {"
   5159       "   var proto = {'name' : 'weak'};"
   5160       "   var obj = Object.create(proto);"
   5161       "   storeIC(obj, 'x');"
   5162       "   storeIC(obj, 'x');"
   5163       "   storeIC(obj, 'x');"
   5164       "   var poly = Object.create(proto);"
   5165       "   poly.x = true;"
   5166       "   storeIC(poly, 'x');"
   5167       "   return proto;"
   5168       " })();");
   5169 }
   5170 
   5171 
   5172 TEST(WeakMapInMonomorphicKeyedStoreIC) {
   5173   CheckWeakness("function keyedStoreIC(obj, field, value) {"
   5174                 "  obj[field] = value;"
   5175                 "}"
   5176                 " (function() {"
   5177                 "   var proto = {'name' : 'weak'};"
   5178                 "   var obj = Object.create(proto);"
   5179                 "   keyedStoreIC(obj, 'x');"
   5180                 "   keyedStoreIC(obj, 'x');"
   5181                 "   keyedStoreIC(obj, 'x');"
   5182                 "   return proto;"
   5183                 " })();");
   5184 }
   5185 
   5186 
   5187 TEST(WeakMapInPolymorphicKeyedStoreIC) {
   5188   CheckWeakness(
   5189       "function keyedStoreIC(obj, field, value) {"
   5190       "  obj[field] = value;"
   5191       "}"
   5192       " (function() {"
   5193       "   var proto = {'name' : 'weak'};"
   5194       "   var obj = Object.create(proto);"
   5195       "   keyedStoreIC(obj, 'x');"
   5196       "   keyedStoreIC(obj, 'x');"
   5197       "   keyedStoreIC(obj, 'x');"
   5198       "   var poly = Object.create(proto);"
   5199       "   poly.x = true;"
   5200       "   keyedStoreIC(poly, 'x');"
   5201       "   return proto;"
   5202       " })();");
   5203 }
   5204 
   5205 
   5206 TEST(WeakMapInMonomorphicCompareNilIC) {
   5207   CheckWeakness("function compareNilIC(obj) {"
   5208                 "  return obj == null;"
   5209                 "}"
   5210                 " (function() {"
   5211                 "   var proto = {'name' : 'weak'};"
   5212                 "   var obj = Object.create(proto);"
   5213                 "   compareNilIC(obj);"
   5214                 "   compareNilIC(obj);"
   5215                 "   compareNilIC(obj);"
   5216                 "   return proto;"
   5217                 " })();");
   5218 }
   5219 
   5220 
   5221 Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {
   5222   Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
   5223   Handle<Object> obj =
   5224       Object::GetProperty(isolate->global_object(), str).ToHandleChecked();
   5225   return Handle<JSFunction>::cast(obj);
   5226 }
   5227 
   5228 void CheckIC(Handle<JSFunction> function, Code::Kind kind, int slot_index,
   5229              InlineCacheState state) {
   5230   if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC ||
   5231       kind == Code::CALL_IC) {
   5232     TypeFeedbackVector* vector = function->feedback_vector();
   5233     FeedbackVectorSlot slot(slot_index);
   5234     if (kind == Code::LOAD_IC) {
   5235       LoadICNexus nexus(vector, slot);
   5236       CHECK_EQ(nexus.StateFromFeedback(), state);
   5237     } else if (kind == Code::KEYED_LOAD_IC) {
   5238       KeyedLoadICNexus nexus(vector, slot);
   5239       CHECK_EQ(nexus.StateFromFeedback(), state);
   5240     } else if (kind == Code::CALL_IC) {
   5241       CallICNexus nexus(vector, slot);
   5242       CHECK_EQ(nexus.StateFromFeedback(), state);
   5243     }
   5244   } else {
   5245     Code* ic = FindFirstIC(function->code(), kind);
   5246     CHECK(ic->is_inline_cache_stub());
   5247     CHECK(!IC::ICUseVector(kind));
   5248     CHECK_EQ(state, IC::StateFromCode(ic));
   5249   }
   5250 }
   5251 
   5252 
   5253 TEST(MonomorphicStaysMonomorphicAfterGC) {
   5254   if (FLAG_always_opt) return;
   5255   CcTest::InitializeVM();
   5256   Isolate* isolate = CcTest::i_isolate();
   5257   Heap* heap = isolate->heap();
   5258   v8::HandleScope scope(CcTest::isolate());
   5259   CompileRun(
   5260       "function loadIC(obj) {"
   5261       "  return obj.name;"
   5262       "}"
   5263       "function testIC() {"
   5264       "  var proto = {'name' : 'weak'};"
   5265       "  var obj = Object.create(proto);"
   5266       "  loadIC(obj);"
   5267       "  loadIC(obj);"
   5268       "  loadIC(obj);"
   5269       "  return proto;"
   5270       "};");
   5271   Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
   5272   {
   5273     v8::HandleScope scope(CcTest::isolate());
   5274     CompileRun("(testIC())");
   5275   }
   5276   heap->CollectAllGarbage();
   5277   CheckIC(loadIC, Code::LOAD_IC, 0, MONOMORPHIC);
   5278   {
   5279     v8::HandleScope scope(CcTest::isolate());
   5280     CompileRun("(testIC())");
   5281   }
   5282   CheckIC(loadIC, Code::LOAD_IC, 0, MONOMORPHIC);
   5283 }
   5284 
   5285 
   5286 TEST(PolymorphicStaysPolymorphicAfterGC) {
   5287   if (FLAG_always_opt) return;
   5288   CcTest::InitializeVM();
   5289   Isolate* isolate = CcTest::i_isolate();
   5290   Heap* heap = isolate->heap();
   5291   v8::HandleScope scope(CcTest::isolate());
   5292   CompileRun(
   5293       "function loadIC(obj) {"
   5294       "  return obj.name;"
   5295       "}"
   5296       "function testIC() {"
   5297       "  var proto = {'name' : 'weak'};"
   5298       "  var obj = Object.create(proto);"
   5299       "  loadIC(obj);"
   5300       "  loadIC(obj);"
   5301       "  loadIC(obj);"
   5302       "  var poly = Object.create(proto);"
   5303       "  poly.x = true;"
   5304       "  loadIC(poly);"
   5305       "  return proto;"
   5306       "};");
   5307   Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
   5308   {
   5309     v8::HandleScope scope(CcTest::isolate());
   5310     CompileRun("(testIC())");
   5311   }
   5312   heap->CollectAllGarbage();
   5313   CheckIC(loadIC, Code::LOAD_IC, 0, POLYMORPHIC);
   5314   {
   5315     v8::HandleScope scope(CcTest::isolate());
   5316     CompileRun("(testIC())");
   5317   }
   5318   CheckIC(loadIC, Code::LOAD_IC, 0, POLYMORPHIC);
   5319 }
   5320 
   5321 
   5322 TEST(WeakCell) {
   5323   CcTest::InitializeVM();
   5324   Isolate* isolate = CcTest::i_isolate();
   5325   v8::internal::Heap* heap = CcTest::heap();
   5326   v8::internal::Factory* factory = isolate->factory();
   5327 
   5328   HandleScope outer_scope(isolate);
   5329   Handle<WeakCell> weak_cell1;
   5330   {
   5331     HandleScope inner_scope(isolate);
   5332     Handle<HeapObject> value = factory->NewFixedArray(1, NOT_TENURED);
   5333     weak_cell1 = inner_scope.CloseAndEscape(factory->NewWeakCell(value));
   5334   }
   5335 
   5336   Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
   5337   Handle<WeakCell> weak_cell2;
   5338   {
   5339     HandleScope inner_scope(isolate);
   5340     weak_cell2 = inner_scope.CloseAndEscape(factory->NewWeakCell(survivor));
   5341   }
   5342   CHECK(weak_cell1->value()->IsFixedArray());
   5343   CHECK_EQ(*survivor, weak_cell2->value());
   5344   heap->CollectGarbage(NEW_SPACE);
   5345   CHECK(weak_cell1->value()->IsFixedArray());
   5346   CHECK_EQ(*survivor, weak_cell2->value());
   5347   heap->CollectGarbage(NEW_SPACE);
   5348   CHECK(weak_cell1->value()->IsFixedArray());
   5349   CHECK_EQ(*survivor, weak_cell2->value());
   5350   heap->CollectAllAvailableGarbage();
   5351   CHECK(weak_cell1->cleared());
   5352   CHECK_EQ(*survivor, weak_cell2->value());
   5353 }
   5354 
   5355 
   5356 TEST(WeakCellsWithIncrementalMarking) {
   5357   CcTest::InitializeVM();
   5358   Isolate* isolate = CcTest::i_isolate();
   5359   v8::internal::Heap* heap = CcTest::heap();
   5360   v8::internal::Factory* factory = isolate->factory();
   5361 
   5362   const int N = 16;
   5363   HandleScope outer_scope(isolate);
   5364   Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
   5365   Handle<WeakCell> weak_cells[N];
   5366 
   5367   for (int i = 0; i < N; i++) {
   5368     HandleScope inner_scope(isolate);
   5369     Handle<HeapObject> value =
   5370         i == 0 ? survivor : factory->NewFixedArray(1, NOT_TENURED);
   5371     Handle<WeakCell> weak_cell = factory->NewWeakCell(value);
   5372     CHECK(weak_cell->value()->IsFixedArray());
   5373     IncrementalMarking* marking = heap->incremental_marking();
   5374     if (marking->IsStopped()) {
   5375       heap->StartIncrementalMarking();
   5376     }
   5377     marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   5378     heap->CollectGarbage(NEW_SPACE);
   5379     CHECK(weak_cell->value()->IsFixedArray());
   5380     weak_cells[i] = inner_scope.CloseAndEscape(weak_cell);
   5381   }
   5382   // Call collect all twice to make sure that we also cleared
   5383   // weak cells that were allocated on black pages.
   5384   heap->CollectAllGarbage();
   5385   heap->CollectAllGarbage();
   5386   CHECK_EQ(*survivor, weak_cells[0]->value());
   5387   for (int i = 1; i < N; i++) {
   5388     CHECK(weak_cells[i]->cleared());
   5389   }
   5390 }
   5391 
   5392 
   5393 #ifdef DEBUG
   5394 TEST(AddInstructionChangesNewSpacePromotion) {
   5395   i::FLAG_allow_natives_syntax = true;
   5396   i::FLAG_expose_gc = true;
   5397   i::FLAG_stress_compaction = true;
   5398   i::FLAG_gc_interval = 1000;
   5399   CcTest::InitializeVM();
   5400   if (!i::FLAG_allocation_site_pretenuring) return;
   5401   v8::HandleScope scope(CcTest::isolate());
   5402   Isolate* isolate = CcTest::i_isolate();
   5403   Heap* heap = isolate->heap();
   5404   LocalContext env;
   5405   CompileRun(
   5406       "function add(a, b) {"
   5407       "  return a + b;"
   5408       "}"
   5409       "add(1, 2);"
   5410       "add(\"a\", \"b\");"
   5411       "var oldSpaceObject;"
   5412       "gc();"
   5413       "function crash(x) {"
   5414       "  var object = {a: null, b: null};"
   5415       "  var result = add(1.5, x | 0);"
   5416       "  object.a = result;"
   5417       "  oldSpaceObject = object;"
   5418       "  return object;"
   5419       "}"
   5420       "crash(1);"
   5421       "crash(1);"
   5422       "%OptimizeFunctionOnNextCall(crash);"
   5423       "crash(1);");
   5424 
   5425   v8::Local<v8::Object> global = CcTest::global();
   5426   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   5427       global->Get(env.local(), v8_str("crash")).ToLocalChecked());
   5428   v8::Local<v8::Value> args1[] = {v8_num(1)};
   5429   heap->DisableInlineAllocation();
   5430   heap->set_allocation_timeout(1);
   5431   g->Call(env.local(), global, 1, args1).ToLocalChecked();
   5432   heap->CollectAllGarbage();
   5433 }
   5434 
   5435 
   5436 void OnFatalErrorExpectOOM(const char* location, const char* message) {
   5437   // Exit with 0 if the location matches our expectation.
   5438   exit(strcmp(location, "CALL_AND_RETRY_LAST"));
   5439 }
   5440 
   5441 
   5442 TEST(CEntryStubOOM) {
   5443   i::FLAG_allow_natives_syntax = true;
   5444   CcTest::InitializeVM();
   5445   v8::HandleScope scope(CcTest::isolate());
   5446   CcTest::isolate()->SetFatalErrorHandler(OnFatalErrorExpectOOM);
   5447 
   5448   v8::Local<v8::Value> result = CompileRun(
   5449       "%SetFlags('--gc-interval=1');"
   5450       "var a = [];"
   5451       "a.__proto__ = [];"
   5452       "a.unshift(1)");
   5453 
   5454   CHECK(result->IsNumber());
   5455 }
   5456 
   5457 #endif  // DEBUG
   5458 
   5459 
   5460 static void InterruptCallback357137(v8::Isolate* isolate, void* data) { }
   5461 
   5462 
   5463 static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5464   CcTest::isolate()->RequestInterrupt(&InterruptCallback357137, NULL);
   5465 }
   5466 
   5467 
   5468 UNINITIALIZED_TEST(Regress538257) {
   5469   i::FLAG_manual_evacuation_candidates_selection = true;
   5470   v8::Isolate::CreateParams create_params;
   5471   // Set heap limits.
   5472   create_params.constraints.set_max_semi_space_size(1 * Page::kPageSize / MB);
   5473   create_params.constraints.set_max_old_space_size(6 * Page::kPageSize / MB);
   5474   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
   5475   v8::Isolate* isolate = v8::Isolate::New(create_params);
   5476   isolate->Enter();
   5477   {
   5478     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   5479     Heap* heap = i_isolate->heap();
   5480     HandleScope handle_scope(i_isolate);
   5481     PagedSpace* old_space = heap->old_space();
   5482     const int kMaxObjects = 10000;
   5483     const int kFixedArrayLen = 512;
   5484     Handle<FixedArray> objects[kMaxObjects];
   5485     for (int i = 0; (i < kMaxObjects) &&
   5486                     heap->CanExpandOldGeneration(old_space->AreaSize());
   5487          i++) {
   5488       objects[i] = i_isolate->factory()->NewFixedArray(kFixedArrayLen, TENURED);
   5489       Page::FromAddress(objects[i]->address())
   5490           ->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
   5491     }
   5492     heap::SimulateFullSpace(old_space);
   5493     heap->CollectGarbage(OLD_SPACE);
   5494     // If we get this far, we've successfully aborted compaction. Any further
   5495     // allocations might trigger OOM.
   5496   }
   5497   isolate->Exit();
   5498   isolate->Dispose();
   5499 }
   5500 
   5501 
   5502 TEST(Regress357137) {
   5503   CcTest::InitializeVM();
   5504   v8::Isolate* isolate = CcTest::isolate();
   5505   v8::HandleScope hscope(isolate);
   5506   v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   5507   global->Set(
   5508       v8::String::NewFromUtf8(isolate, "interrupt", v8::NewStringType::kNormal)
   5509           .ToLocalChecked(),
   5510       v8::FunctionTemplate::New(isolate, RequestInterrupt));
   5511   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
   5512   CHECK(!context.IsEmpty());
   5513   v8::Context::Scope cscope(context);
   5514 
   5515   v8::Local<v8::Value> result = CompileRun(
   5516       "var locals = '';"
   5517       "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';"
   5518       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
   5519       "interrupt();"  // This triggers a fake stack overflow in f.
   5520       "f()()");
   5521   CHECK_EQ(42.0, result->ToNumber(context).ToLocalChecked()->Value());
   5522 }
   5523 
   5524 
   5525 TEST(Regress507979) {
   5526   const int kFixedArrayLen = 10;
   5527   CcTest::InitializeVM();
   5528   Isolate* isolate = CcTest::i_isolate();
   5529   Heap* heap = isolate->heap();
   5530   HandleScope handle_scope(isolate);
   5531 
   5532   Handle<FixedArray> o1 = isolate->factory()->NewFixedArray(kFixedArrayLen);
   5533   Handle<FixedArray> o2 = isolate->factory()->NewFixedArray(kFixedArrayLen);
   5534   CHECK(heap->InNewSpace(*o1));
   5535   CHECK(heap->InNewSpace(*o2));
   5536 
   5537   HeapIterator it(heap, i::HeapIterator::kFilterUnreachable);
   5538 
   5539   // Replace parts of an object placed before a live object with a filler. This
   5540   // way the filler object shares the mark bits with the following live object.
   5541   o1->Shrink(kFixedArrayLen - 1);
   5542 
   5543   for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
   5544     // Let's not optimize the loop away.
   5545     CHECK(obj->address() != nullptr);
   5546   }
   5547 }
   5548 
   5549 
   5550 UNINITIALIZED_TEST(PromotionQueue) {
   5551   i::FLAG_expose_gc = true;
   5552   i::FLAG_max_semi_space_size = 2 * Page::kPageSize / MB;
   5553   i::FLAG_min_semi_space_size = i::FLAG_max_semi_space_size;
   5554   v8::Isolate::CreateParams create_params;
   5555   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
   5556   v8::Isolate* isolate = v8::Isolate::New(create_params);
   5557   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   5558   {
   5559     v8::Isolate::Scope isolate_scope(isolate);
   5560     v8::HandleScope handle_scope(isolate);
   5561     v8::Context::New(isolate)->Enter();
   5562     Heap* heap = i_isolate->heap();
   5563     NewSpace* new_space = heap->new_space();
   5564 
   5565     // In this test we will try to overwrite the promotion queue which is at the
   5566     // end of to-space. To actually make that possible, we need at least two
   5567     // semi-space pages and take advantage of fragmentation.
   5568     // (1) Use a semi-space consisting of two pages.
   5569     // (2) Create a few small long living objects and call the scavenger to
   5570     // move them to the other semi-space.
   5571     // (3) Create a huge object, i.e., remainder of first semi-space page and
   5572     // create another huge object which should be of maximum allocatable memory
   5573     // size of the second semi-space page.
   5574     // (4) Call the scavenger again.
   5575     // What will happen is: the scavenger will promote the objects created in
   5576     // (2) and will create promotion queue entries at the end of the second
   5577     // semi-space page during the next scavenge when it promotes the objects to
   5578     // the old generation. The first allocation of (3) will fill up the first
   5579     // semi-space page. The second allocation in (3) will not fit into the
   5580     // first semi-space page, but it will overwrite the promotion queue which
   5581     // are in the second semi-space page. If the right guards are in place, the
   5582     // promotion queue will be evacuated in that case.
   5583 
   5584 
   5585     CHECK(new_space->IsAtMaximumCapacity());
   5586     CHECK(i::FLAG_min_semi_space_size * MB == new_space->TotalCapacity());
   5587 
   5588     // Call the scavenger two times to get an empty new space
   5589     heap->CollectGarbage(NEW_SPACE);
   5590     heap->CollectGarbage(NEW_SPACE);
   5591 
   5592     // First create a few objects which will survive a scavenge, and will get
   5593     // promoted to the old generation later on. These objects will create
   5594     // promotion queue entries at the end of the second semi-space page.
   5595     const int number_handles = 12;
   5596     Handle<FixedArray> handles[number_handles];
   5597     for (int i = 0; i < number_handles; i++) {
   5598       handles[i] = i_isolate->factory()->NewFixedArray(1, NOT_TENURED);
   5599     }
   5600 
   5601     heap->CollectGarbage(NEW_SPACE);
   5602     CHECK(i::FLAG_min_semi_space_size * MB == new_space->TotalCapacity());
   5603 
   5604     // Fill-up the first semi-space page.
   5605     heap::FillUpOnePage(new_space);
   5606 
   5607     // Create a small object to initialize the bump pointer on the second
   5608     // semi-space page.
   5609     Handle<FixedArray> small =
   5610         i_isolate->factory()->NewFixedArray(1, NOT_TENURED);
   5611     CHECK(heap->InNewSpace(*small));
   5612 
   5613     // Fill-up the second semi-space page.
   5614     heap::FillUpOnePage(new_space);
   5615 
   5616     // This scavenge will corrupt memory if the promotion queue is not
   5617     // evacuated.
   5618     heap->CollectGarbage(NEW_SPACE);
   5619   }
   5620   isolate->Dispose();
   5621 }
   5622 
   5623 
   5624 TEST(Regress388880) {
   5625   i::FLAG_expose_gc = true;
   5626   CcTest::InitializeVM();
   5627   v8::HandleScope scope(CcTest::isolate());
   5628   Isolate* isolate = CcTest::i_isolate();
   5629   Factory* factory = isolate->factory();
   5630   Heap* heap = isolate->heap();
   5631 
   5632   Handle<Map> map1 = Map::Create(isolate, 1);
   5633   Handle<String> name = factory->NewStringFromStaticChars("foo");
   5634   name = factory->InternalizeString(name);
   5635   Handle<Map> map2 =
   5636       Map::CopyWithField(map1, name, FieldType::Any(isolate), NONE,
   5637                          Representation::Tagged(), OMIT_TRANSITION)
   5638           .ToHandleChecked();
   5639 
   5640   int desired_offset = Page::kPageSize - map1->instance_size();
   5641 
   5642   // Allocate padding objects in old pointer space so, that object allocated
   5643   // afterwards would end at the end of the page.
   5644   heap::SimulateFullSpace(heap->old_space());
   5645   int padding_size = desired_offset - Page::kObjectStartOffset;
   5646   heap::CreatePadding(heap, padding_size, TENURED);
   5647 
   5648   Handle<JSObject> o = factory->NewJSObjectFromMap(map1, TENURED);
   5649   o->set_properties(*factory->empty_fixed_array());
   5650 
   5651   // Ensure that the object allocated where we need it.
   5652   Page* page = Page::FromAddress(o->address());
   5653   CHECK_EQ(desired_offset, page->Offset(o->address()));
   5654 
   5655   // Now we have an object right at the end of the page.
   5656 
   5657   // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes()
   5658   // that would cause crash.
   5659   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   5660   marking->Stop();
   5661   CcTest::heap()->StartIncrementalMarking();
   5662   CHECK(marking->IsMarking());
   5663 
   5664   // Now everything is set up for crashing in JSObject::MigrateFastToFast()
   5665   // when it calls heap->AdjustLiveBytes(...).
   5666   JSObject::MigrateToMap(o, map2);
   5667 }
   5668 
   5669 
   5670 TEST(Regress3631) {
   5671   i::FLAG_expose_gc = true;
   5672   CcTest::InitializeVM();
   5673   v8::HandleScope scope(CcTest::isolate());
   5674   Isolate* isolate = CcTest::i_isolate();
   5675   Heap* heap = isolate->heap();
   5676   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
   5677   v8::Local<v8::Value> result = CompileRun(
   5678       "var weak_map = new WeakMap();"
   5679       "var future_keys = [];"
   5680       "for (var i = 0; i < 50; i++) {"
   5681       "  var key = {'k' : i + 0.1};"
   5682       "  weak_map.set(key, 1);"
   5683       "  future_keys.push({'x' : i + 0.2});"
   5684       "}"
   5685       "weak_map");
   5686   if (marking->IsStopped()) {
   5687     CcTest::heap()->StartIncrementalMarking();
   5688   }
   5689   // Incrementally mark the backing store.
   5690   Handle<JSReceiver> obj =
   5691       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(result));
   5692   Handle<JSWeakCollection> weak_map(reinterpret_cast<JSWeakCollection*>(*obj));
   5693   while (!Marking::IsBlack(
   5694              Marking::MarkBitFrom(HeapObject::cast(weak_map->table()))) &&
   5695          !marking->IsStopped()) {
   5696     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   5697   }
   5698   // Stash the backing store in a handle.
   5699   Handle<Object> save(weak_map->table(), isolate);
   5700   // The following line will update the backing store.
   5701   CompileRun(
   5702       "for (var i = 0; i < 50; i++) {"
   5703       "  weak_map.set(future_keys[i], i);"
   5704       "}");
   5705   heap->incremental_marking()->set_should_hurry(true);
   5706   heap->CollectGarbage(OLD_SPACE);
   5707 }
   5708 
   5709 
   5710 TEST(Regress442710) {
   5711   CcTest::InitializeVM();
   5712   Isolate* isolate = CcTest::i_isolate();
   5713   Heap* heap = isolate->heap();
   5714   Factory* factory = isolate->factory();
   5715 
   5716   HandleScope sc(isolate);
   5717   Handle<JSGlobalObject> global(
   5718       CcTest::i_isolate()->context()->global_object());
   5719   Handle<JSArray> array = factory->NewJSArray(2);
   5720 
   5721   Handle<String> name = factory->InternalizeUtf8String("testArray");
   5722   JSReceiver::SetProperty(global, name, array, SLOPPY).Check();
   5723   CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();");
   5724   heap->CollectGarbage(OLD_SPACE);
   5725 }
   5726 
   5727 
   5728 HEAP_TEST(NumberStringCacheSize) {
   5729   // Test that the number-string cache has not been resized in the snapshot.
   5730   CcTest::InitializeVM();
   5731   Isolate* isolate = CcTest::i_isolate();
   5732   if (!isolate->snapshot_available()) return;
   5733   Heap* heap = isolate->heap();
   5734   CHECK_EQ(Heap::kInitialNumberStringCacheSize * 2,
   5735            heap->number_string_cache()->length());
   5736 }
   5737 
   5738 
   5739 TEST(Regress3877) {
   5740   CcTest::InitializeVM();
   5741   Isolate* isolate = CcTest::i_isolate();
   5742   Heap* heap = isolate->heap();
   5743   Factory* factory = isolate->factory();
   5744   HandleScope scope(isolate);
   5745   CompileRun("function cls() { this.x = 10; }");
   5746   Handle<WeakCell> weak_prototype;
   5747   {
   5748     HandleScope inner_scope(isolate);
   5749     v8::Local<v8::Value> result = CompileRun("cls.prototype");
   5750     Handle<JSReceiver> proto =
   5751         v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(result));
   5752     weak_prototype = inner_scope.CloseAndEscape(factory->NewWeakCell(proto));
   5753   }
   5754   CHECK(!weak_prototype->cleared());
   5755   CompileRun(
   5756       "var a = { };"
   5757       "a.x = new cls();"
   5758       "cls.prototype = null;");
   5759   for (int i = 0; i < 4; i++) {
   5760     heap->CollectAllGarbage();
   5761   }
   5762   // The map of a.x keeps prototype alive
   5763   CHECK(!weak_prototype->cleared());
   5764   // Change the map of a.x and make the previous map garbage collectable.
   5765   CompileRun("a.x.__proto__ = {};");
   5766   for (int i = 0; i < 4; i++) {
   5767     heap->CollectAllGarbage();
   5768   }
   5769   CHECK(weak_prototype->cleared());
   5770 }
   5771 
   5772 
   5773 Handle<WeakCell> AddRetainedMap(Isolate* isolate, Heap* heap) {
   5774     HandleScope inner_scope(isolate);
   5775     Handle<Map> map = Map::Create(isolate, 1);
   5776     v8::Local<v8::Value> result =
   5777         CompileRun("(function () { return {x : 10}; })();");
   5778     Handle<JSReceiver> proto =
   5779         v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(result));
   5780     Map::SetPrototype(map, proto);
   5781     heap->AddRetainedMap(map);
   5782     return inner_scope.CloseAndEscape(Map::WeakCellForMap(map));
   5783 }
   5784 
   5785 
   5786 void CheckMapRetainingFor(int n) {
   5787   FLAG_retain_maps_for_n_gc = n;
   5788   Isolate* isolate = CcTest::i_isolate();
   5789   Heap* heap = isolate->heap();
   5790   Handle<WeakCell> weak_cell = AddRetainedMap(isolate, heap);
   5791   CHECK(!weak_cell->cleared());
   5792   for (int i = 0; i < n; i++) {
   5793     heap::SimulateIncrementalMarking(heap);
   5794     heap->CollectGarbage(OLD_SPACE);
   5795   }
   5796   CHECK(!weak_cell->cleared());
   5797   heap::SimulateIncrementalMarking(heap);
   5798   heap->CollectGarbage(OLD_SPACE);
   5799   CHECK(weak_cell->cleared());
   5800 }
   5801 
   5802 
   5803 TEST(MapRetaining) {
   5804   CcTest::InitializeVM();
   5805   v8::HandleScope scope(CcTest::isolate());
   5806   CheckMapRetainingFor(FLAG_retain_maps_for_n_gc);
   5807   CheckMapRetainingFor(0);
   5808   CheckMapRetainingFor(1);
   5809   CheckMapRetainingFor(7);
   5810 }
   5811 
   5812 
   5813 TEST(RegressArrayListGC) {
   5814   FLAG_retain_maps_for_n_gc = 1;
   5815   FLAG_incremental_marking = 0;
   5816   FLAG_gc_global = true;
   5817   CcTest::InitializeVM();
   5818   v8::HandleScope scope(CcTest::isolate());
   5819   Isolate* isolate = CcTest::i_isolate();
   5820   Heap* heap = isolate->heap();
   5821   AddRetainedMap(isolate, heap);
   5822   Handle<Map> map = Map::Create(isolate, 1);
   5823   heap->CollectGarbage(OLD_SPACE);
   5824   // Force GC in old space on next addition of retained map.
   5825   Map::WeakCellForMap(map);
   5826   heap::SimulateFullSpace(CcTest::heap()->new_space());
   5827   for (int i = 0; i < 10; i++) {
   5828     heap->AddRetainedMap(map);
   5829   }
   5830   heap->CollectGarbage(OLD_SPACE);
   5831 }
   5832 
   5833 
   5834 #ifdef DEBUG
   5835 TEST(PathTracer) {
   5836   CcTest::InitializeVM();
   5837   v8::HandleScope scope(CcTest::isolate());
   5838 
   5839   v8::Local<v8::Value> result = CompileRun("'abc'");
   5840   Handle<Object> o = v8::Utils::OpenHandle(*result);
   5841   CcTest::i_isolate()->heap()->TracePathToObject(*o);
   5842 }
   5843 #endif  // DEBUG
   5844 
   5845 
   5846 TEST(WritableVsImmortalRoots) {
   5847   for (int i = 0; i < Heap::kStrongRootListLength; ++i) {
   5848     Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(i);
   5849     bool writable = Heap::RootCanBeWrittenAfterInitialization(root_index);
   5850     bool immortal = Heap::RootIsImmortalImmovable(root_index);
   5851     // A root value can be writable, immortal, or neither, but not both.
   5852     CHECK(!immortal || !writable);
   5853   }
   5854 }
   5855 
   5856 
   5857 static void TestRightTrimFixedTypedArray(i::ExternalArrayType type,
   5858                                          int initial_length,
   5859                                          int elements_to_trim) {
   5860   v8::HandleScope scope(CcTest::isolate());
   5861   Isolate* isolate = CcTest::i_isolate();
   5862   Factory* factory = isolate->factory();
   5863   Heap* heap = isolate->heap();
   5864 
   5865   Handle<FixedTypedArrayBase> array =
   5866       factory->NewFixedTypedArray(initial_length, type, true);
   5867   int old_size = array->size();
   5868   heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array,
   5869                                                          elements_to_trim);
   5870 
   5871   // Check that free space filler is at the right place and did not smash the
   5872   // array header.
   5873   CHECK(array->IsFixedArrayBase());
   5874   CHECK_EQ(initial_length - elements_to_trim, array->length());
   5875   int new_size = array->size();
   5876   if (new_size != old_size) {
   5877     // Free space filler should be created in this case.
   5878     Address next_obj_address = array->address() + array->size();
   5879     CHECK(HeapObject::FromAddress(next_obj_address)->IsFiller());
   5880   }
   5881   heap->CollectAllAvailableGarbage();
   5882 }
   5883 
   5884 
   5885 TEST(Regress472513) {
   5886   CcTest::InitializeVM();
   5887   v8::HandleScope scope(CcTest::isolate());
   5888 
   5889   // The combination of type/initial_length/elements_to_trim triggered
   5890   // typed array header smashing with free space filler (crbug/472513).
   5891 
   5892   // 64-bit cases.
   5893   TestRightTrimFixedTypedArray(i::kExternalUint8Array, 32, 6);
   5894   TestRightTrimFixedTypedArray(i::kExternalUint8Array, 32 - 7, 6);
   5895   TestRightTrimFixedTypedArray(i::kExternalUint16Array, 16, 6);
   5896   TestRightTrimFixedTypedArray(i::kExternalUint16Array, 16 - 3, 6);
   5897   TestRightTrimFixedTypedArray(i::kExternalUint32Array, 8, 6);
   5898   TestRightTrimFixedTypedArray(i::kExternalUint32Array, 8 - 1, 6);
   5899 
   5900   // 32-bit cases.
   5901   TestRightTrimFixedTypedArray(i::kExternalUint8Array, 16, 3);
   5902   TestRightTrimFixedTypedArray(i::kExternalUint8Array, 16 - 3, 3);
   5903   TestRightTrimFixedTypedArray(i::kExternalUint16Array, 8, 3);
   5904   TestRightTrimFixedTypedArray(i::kExternalUint16Array, 8 - 1, 3);
   5905   TestRightTrimFixedTypedArray(i::kExternalUint32Array, 4, 3);
   5906 }
   5907 
   5908 
   5909 TEST(WeakFixedArray) {
   5910   CcTest::InitializeVM();
   5911   v8::HandleScope scope(CcTest::isolate());
   5912 
   5913   Handle<HeapNumber> number = CcTest::i_isolate()->factory()->NewHeapNumber(1);
   5914   Handle<WeakFixedArray> array = WeakFixedArray::Add(Handle<Object>(), number);
   5915   array->Remove(number);
   5916   array->Compact<WeakFixedArray::NullCallback>();
   5917   WeakFixedArray::Add(array, number);
   5918 }
   5919 
   5920 
   5921 TEST(PreprocessStackTrace) {
   5922   // Do not automatically trigger early GC.
   5923   FLAG_gc_interval = -1;
   5924   CcTest::InitializeVM();
   5925   v8::HandleScope scope(CcTest::isolate());
   5926   v8::TryCatch try_catch(CcTest::isolate());
   5927   CompileRun("throw new Error();");
   5928   CHECK(try_catch.HasCaught());
   5929   Isolate* isolate = CcTest::i_isolate();
   5930   Handle<Object> exception = v8::Utils::OpenHandle(*try_catch.Exception());
   5931   Handle<Name> key = isolate->factory()->stack_trace_symbol();
   5932   Handle<Object> stack_trace =
   5933       Object::GetProperty(exception, key).ToHandleChecked();
   5934   Handle<Object> code =
   5935       Object::GetElement(isolate, stack_trace, 3).ToHandleChecked();
   5936   CHECK(code->IsCode());
   5937 
   5938   isolate->heap()->CollectAllAvailableGarbage("stack trace preprocessing");
   5939 
   5940   Handle<Object> pos =
   5941       Object::GetElement(isolate, stack_trace, 3).ToHandleChecked();
   5942   CHECK(pos->IsSmi());
   5943 
   5944   Handle<JSArray> stack_trace_array = Handle<JSArray>::cast(stack_trace);
   5945   int array_length = Smi::cast(stack_trace_array->length())->value();
   5946   for (int i = 0; i < array_length; i++) {
   5947     Handle<Object> element =
   5948         Object::GetElement(isolate, stack_trace, i).ToHandleChecked();
   5949     CHECK(!element->IsCode());
   5950   }
   5951 }
   5952 
   5953 
   5954 static bool utils_has_been_collected = false;
   5955 
   5956 static void UtilsHasBeenCollected(
   5957     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
   5958   utils_has_been_collected = true;
   5959   data.GetParameter()->Reset();
   5960 }
   5961 
   5962 
   5963 TEST(BootstrappingExports) {
   5964   // Expose utils object and delete it to observe that it is indeed
   5965   // being garbage-collected.
   5966   FLAG_expose_natives_as = "utils";
   5967   CcTest::InitializeVM();
   5968   v8::Isolate* isolate = CcTest::isolate();
   5969   LocalContext env;
   5970 
   5971   if (Snapshot::HaveASnapshotToStartFrom(CcTest::i_isolate())) return;
   5972 
   5973   utils_has_been_collected = false;
   5974 
   5975   v8::Persistent<v8::Object> utils;
   5976 
   5977   {
   5978     v8::HandleScope scope(isolate);
   5979     v8::Local<v8::String> name = v8_str("utils");
   5980     utils.Reset(isolate, CcTest::global()
   5981                              ->Get(env.local(), name)
   5982                              .ToLocalChecked()
   5983                              ->ToObject(env.local())
   5984                              .ToLocalChecked());
   5985     CHECK(CcTest::global()->Delete(env.local(), name).FromJust());
   5986   }
   5987 
   5988   utils.SetWeak(&utils, UtilsHasBeenCollected,
   5989                 v8::WeakCallbackType::kParameter);
   5990 
   5991   CcTest::heap()->CollectAllAvailableGarbage("fire weak callbacks");
   5992 
   5993   CHECK(utils_has_been_collected);
   5994 }
   5995 
   5996 
   5997 TEST(Regress1878) {
   5998   FLAG_allow_natives_syntax = true;
   5999   CcTest::InitializeVM();
   6000   v8::Isolate* isolate = CcTest::isolate();
   6001   v8::HandleScope scope(isolate);
   6002   v8::Local<v8::Function> constructor = v8::Utils::CallableToLocal(
   6003       CcTest::i_isolate()->internal_array_function());
   6004   LocalContext env;
   6005   CHECK(CcTest::global()
   6006             ->Set(env.local(), v8_str("InternalArray"), constructor)
   6007             .FromJust());
   6008 
   6009   v8::TryCatch try_catch(isolate);
   6010 
   6011   CompileRun(
   6012       "var a = Array();"
   6013       "for (var i = 0; i < 1000; i++) {"
   6014       "  var ai = new InternalArray(10000);"
   6015       "  if (%HaveSameMap(ai, a)) throw Error();"
   6016       "  if (!%HasFastObjectElements(ai)) throw Error();"
   6017       "}"
   6018       "for (var i = 0; i < 1000; i++) {"
   6019       "  var ai = new InternalArray(10000);"
   6020       "  if (%HaveSameMap(ai, a)) throw Error();"
   6021       "  if (!%HasFastObjectElements(ai)) throw Error();"
   6022       "}");
   6023 
   6024   CHECK(!try_catch.HasCaught());
   6025 }
   6026 
   6027 
   6028 void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) {
   6029   CHECK(bytes >= FixedArray::kHeaderSize);
   6030   CHECK(bytes % kPointerSize == 0);
   6031   Factory* factory = isolate->factory();
   6032   HandleScope scope(isolate);
   6033   AlwaysAllocateScope always_allocate(isolate);
   6034   int elements =
   6035       static_cast<int>((bytes - FixedArray::kHeaderSize) / kPointerSize);
   6036   Handle<FixedArray> array = factory->NewFixedArray(
   6037       elements, space == NEW_SPACE ? NOT_TENURED : TENURED);
   6038   CHECK((space == NEW_SPACE) == isolate->heap()->InNewSpace(*array));
   6039   CHECK_EQ(bytes, static_cast<size_t>(array->Size()));
   6040 }
   6041 
   6042 
   6043 TEST(NewSpaceAllocationCounter) {
   6044   CcTest::InitializeVM();
   6045   v8::HandleScope scope(CcTest::isolate());
   6046   Isolate* isolate = CcTest::i_isolate();
   6047   Heap* heap = isolate->heap();
   6048   size_t counter1 = heap->NewSpaceAllocationCounter();
   6049   heap->CollectGarbage(NEW_SPACE);
   6050   const size_t kSize = 1024;
   6051   AllocateInSpace(isolate, kSize, NEW_SPACE);
   6052   size_t counter2 = heap->NewSpaceAllocationCounter();
   6053   CHECK_EQ(kSize, counter2 - counter1);
   6054   heap->CollectGarbage(NEW_SPACE);
   6055   size_t counter3 = heap->NewSpaceAllocationCounter();
   6056   CHECK_EQ(0U, counter3 - counter2);
   6057   // Test counter overflow.
   6058   size_t max_counter = -1;
   6059   heap->set_new_space_allocation_counter(max_counter - 10 * kSize);
   6060   size_t start = heap->NewSpaceAllocationCounter();
   6061   for (int i = 0; i < 20; i++) {
   6062     AllocateInSpace(isolate, kSize, NEW_SPACE);
   6063     size_t counter = heap->NewSpaceAllocationCounter();
   6064     CHECK_EQ(kSize, counter - start);
   6065     start = counter;
   6066   }
   6067 }
   6068 
   6069 
   6070 TEST(OldSpaceAllocationCounter) {
   6071   CcTest::InitializeVM();
   6072   v8::HandleScope scope(CcTest::isolate());
   6073   Isolate* isolate = CcTest::i_isolate();
   6074   Heap* heap = isolate->heap();
   6075   size_t counter1 = heap->OldGenerationAllocationCounter();
   6076   heap->CollectGarbage(NEW_SPACE);
   6077   heap->CollectGarbage(NEW_SPACE);
   6078   const size_t kSize = 1024;
   6079   AllocateInSpace(isolate, kSize, OLD_SPACE);
   6080   size_t counter2 = heap->OldGenerationAllocationCounter();
   6081   // TODO(ulan): replace all CHECK_LE with CHECK_EQ after v8:4148 is fixed.
   6082   CHECK_LE(kSize, counter2 - counter1);
   6083   heap->CollectGarbage(NEW_SPACE);
   6084   size_t counter3 = heap->OldGenerationAllocationCounter();
   6085   CHECK_EQ(0u, counter3 - counter2);
   6086   AllocateInSpace(isolate, kSize, OLD_SPACE);
   6087   heap->CollectGarbage(OLD_SPACE);
   6088   size_t counter4 = heap->OldGenerationAllocationCounter();
   6089   CHECK_LE(kSize, counter4 - counter3);
   6090   // Test counter overflow.
   6091   size_t max_counter = -1;
   6092   heap->set_old_generation_allocation_counter(max_counter - 10 * kSize);
   6093   size_t start = heap->OldGenerationAllocationCounter();
   6094   for (int i = 0; i < 20; i++) {
   6095     AllocateInSpace(isolate, kSize, OLD_SPACE);
   6096     size_t counter = heap->OldGenerationAllocationCounter();
   6097     CHECK_LE(kSize, counter - start);
   6098     start = counter;
   6099   }
   6100 }
   6101 
   6102 
   6103 TEST(NewSpaceAllocationThroughput) {
   6104   CcTest::InitializeVM();
   6105   v8::HandleScope scope(CcTest::isolate());
   6106   Isolate* isolate = CcTest::i_isolate();
   6107   Heap* heap = isolate->heap();
   6108   GCTracer* tracer = heap->tracer();
   6109   tracer->ResetForTesting();
   6110   int time1 = 100;
   6111   size_t counter1 = 1000;
   6112   tracer->SampleAllocation(time1, counter1, 0);
   6113   int time2 = 200;
   6114   size_t counter2 = 2000;
   6115   tracer->SampleAllocation(time2, counter2, 0);
   6116   size_t throughput =
   6117       tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
   6118   CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput);
   6119   int time3 = 1000;
   6120   size_t counter3 = 30000;
   6121   tracer->SampleAllocation(time3, counter3, 0);
   6122   throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
   6123   CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput);
   6124 }
   6125 
   6126 
   6127 TEST(NewSpaceAllocationThroughput2) {
   6128   CcTest::InitializeVM();
   6129   v8::HandleScope scope(CcTest::isolate());
   6130   Isolate* isolate = CcTest::i_isolate();
   6131   Heap* heap = isolate->heap();
   6132   GCTracer* tracer = heap->tracer();
   6133   tracer->ResetForTesting();
   6134   int time1 = 100;
   6135   size_t counter1 = 1000;
   6136   tracer->SampleAllocation(time1, counter1, 0);
   6137   int time2 = 200;
   6138   size_t counter2 = 2000;
   6139   tracer->SampleAllocation(time2, counter2, 0);
   6140   size_t throughput =
   6141       tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(100);
   6142   CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput);
   6143   int time3 = 1000;
   6144   size_t counter3 = 30000;
   6145   tracer->SampleAllocation(time3, counter3, 0);
   6146   throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(100);
   6147   CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput);
   6148 }
   6149 
   6150 
   6151 static void CheckLeak(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6152   Isolate* isolate = CcTest::i_isolate();
   6153   Object* message =
   6154       *reinterpret_cast<Object**>(isolate->pending_message_obj_address());
   6155   CHECK(message->IsTheHole(isolate));
   6156 }
   6157 
   6158 
   6159 TEST(MessageObjectLeak) {
   6160   CcTest::InitializeVM();
   6161   v8::Isolate* isolate = CcTest::isolate();
   6162   v8::HandleScope scope(isolate);
   6163   v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   6164   global->Set(
   6165       v8::String::NewFromUtf8(isolate, "check", v8::NewStringType::kNormal)
   6166           .ToLocalChecked(),
   6167       v8::FunctionTemplate::New(isolate, CheckLeak));
   6168   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
   6169   v8::Context::Scope cscope(context);
   6170 
   6171   const char* test =
   6172       "try {"
   6173       "  throw 'message 1';"
   6174       "} catch (e) {"
   6175       "}"
   6176       "check();"
   6177       "L: try {"
   6178       "  throw 'message 2';"
   6179       "} finally {"
   6180       "  break L;"
   6181       "}"
   6182       "check();";
   6183   CompileRun(test);
   6184 
   6185   const char* flag = "--turbo-filter=*";
   6186   FlagList::SetFlagsFromString(flag, StrLength(flag));
   6187   FLAG_always_opt = true;
   6188 
   6189   CompileRun(test);
   6190 }
   6191 
   6192 
   6193 static void CheckEqualSharedFunctionInfos(
   6194     const v8::FunctionCallbackInfo<v8::Value>& args) {
   6195   Handle<Object> obj1 = v8::Utils::OpenHandle(*args[0]);
   6196   Handle<Object> obj2 = v8::Utils::OpenHandle(*args[1]);
   6197   Handle<JSFunction> fun1 = Handle<JSFunction>::cast(obj1);
   6198   Handle<JSFunction> fun2 = Handle<JSFunction>::cast(obj2);
   6199   CHECK(fun1->shared() == fun2->shared());
   6200 }
   6201 
   6202 
   6203 static void RemoveCodeAndGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6204   Isolate* isolate = CcTest::i_isolate();
   6205   Handle<Object> obj = v8::Utils::OpenHandle(*args[0]);
   6206   Handle<JSFunction> fun = Handle<JSFunction>::cast(obj);
   6207   fun->ReplaceCode(*isolate->builtins()->CompileLazy());
   6208   fun->shared()->ReplaceCode(*isolate->builtins()->CompileLazy());
   6209   fun->shared()->ClearBytecodeArray();  // Bytecode is code too.
   6210   isolate->heap()->CollectAllAvailableGarbage("remove code and gc");
   6211 }
   6212 
   6213 
   6214 TEST(CanonicalSharedFunctionInfo) {
   6215   CcTest::InitializeVM();
   6216   v8::Isolate* isolate = CcTest::isolate();
   6217   v8::HandleScope scope(isolate);
   6218   v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   6219   global->Set(isolate, "check", v8::FunctionTemplate::New(
   6220                                     isolate, CheckEqualSharedFunctionInfos));
   6221   global->Set(isolate, "remove",
   6222               v8::FunctionTemplate::New(isolate, RemoveCodeAndGC));
   6223   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
   6224   v8::Context::Scope cscope(context);
   6225   CompileRun(
   6226       "function f() { return function g() {}; }"
   6227       "var g1 = f();"
   6228       "remove(f);"
   6229       "var g2 = f();"
   6230       "check(g1, g2);");
   6231 
   6232   CompileRun(
   6233       "function f() { return (function() { return function g() {}; })(); }"
   6234       "var g1 = f();"
   6235       "remove(f);"
   6236       "var g2 = f();"
   6237       "check(g1, g2);");
   6238 }
   6239 
   6240 TEST(RemoveCodeFromSharedFunctionInfoButNotFromClosure) {
   6241   CcTest::InitializeVM();
   6242   v8::Isolate* isolate = CcTest::isolate();
   6243   v8::HandleScope scope(isolate);
   6244   v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   6245   global->Set(isolate, "check", v8::FunctionTemplate::New(
   6246                                     isolate, CheckEqualSharedFunctionInfos));
   6247   global->Set(isolate, "remove",
   6248               v8::FunctionTemplate::New(isolate, RemoveCodeAndGC));
   6249   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
   6250   v8::Context::Scope cscope(context);
   6251   CompileRun(
   6252       "function f() { return function g() {}; }"
   6253       "var g1 = f();"
   6254       "var g2 = f();"
   6255       "check(g1, g2);"
   6256       "g1();"
   6257       "g2();"
   6258       "remove(g1);"
   6259       "g2();"
   6260       "check(g1, g2);");
   6261 }
   6262 
   6263 TEST(OldGenerationAllocationThroughput) {
   6264   CcTest::InitializeVM();
   6265   v8::HandleScope scope(CcTest::isolate());
   6266   Isolate* isolate = CcTest::i_isolate();
   6267   Heap* heap = isolate->heap();
   6268   GCTracer* tracer = heap->tracer();
   6269   tracer->ResetForTesting();
   6270   int time1 = 100;
   6271   size_t counter1 = 1000;
   6272   tracer->SampleAllocation(time1, 0, counter1);
   6273   int time2 = 200;
   6274   size_t counter2 = 2000;
   6275   tracer->SampleAllocation(time2, 0, counter2);
   6276   size_t throughput = static_cast<size_t>(
   6277       tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(100));
   6278   CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput);
   6279   int time3 = 1000;
   6280   size_t counter3 = 30000;
   6281   tracer->SampleAllocation(time3, 0, counter3);
   6282   throughput = static_cast<size_t>(
   6283       tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(100));
   6284   CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput);
   6285 }
   6286 
   6287 
   6288 TEST(AllocationThroughput) {
   6289   CcTest::InitializeVM();
   6290   v8::HandleScope scope(CcTest::isolate());
   6291   Isolate* isolate = CcTest::i_isolate();
   6292   Heap* heap = isolate->heap();
   6293   GCTracer* tracer = heap->tracer();
   6294   tracer->ResetForTesting();
   6295   int time1 = 100;
   6296   size_t counter1 = 1000;
   6297   tracer->SampleAllocation(time1, counter1, counter1);
   6298   int time2 = 200;
   6299   size_t counter2 = 2000;
   6300   tracer->SampleAllocation(time2, counter2, counter2);
   6301   size_t throughput = static_cast<size_t>(
   6302       tracer->AllocationThroughputInBytesPerMillisecond(100));
   6303   CHECK_EQ(2 * (counter2 - counter1) / (time2 - time1), throughput);
   6304   int time3 = 1000;
   6305   size_t counter3 = 30000;
   6306   tracer->SampleAllocation(time3, counter3, counter3);
   6307   throughput = tracer->AllocationThroughputInBytesPerMillisecond(100);
   6308   CHECK_EQ(2 * (counter3 - counter1) / (time3 - time1), throughput);
   6309 }
   6310 
   6311 
   6312 TEST(ContextMeasure) {
   6313   CcTest::InitializeVM();
   6314   v8::HandleScope scope(CcTest::isolate());
   6315   Isolate* isolate = CcTest::i_isolate();
   6316   LocalContext context;
   6317 
   6318   int size_upper_limit = 0;
   6319   int count_upper_limit = 0;
   6320   HeapIterator it(CcTest::heap());
   6321   for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
   6322     size_upper_limit += obj->Size();
   6323     count_upper_limit++;
   6324   }
   6325 
   6326   ContextMeasure measure(*isolate->native_context());
   6327 
   6328   PrintF("Context size        : %d bytes\n", measure.Size());
   6329   PrintF("Context object count: %d\n", measure.Count());
   6330 
   6331   CHECK_LE(1000, measure.Count());
   6332   CHECK_LE(50000, measure.Size());
   6333 
   6334   CHECK_LE(measure.Count(), count_upper_limit);
   6335   CHECK_LE(measure.Size(), size_upper_limit);
   6336 }
   6337 
   6338 
   6339 TEST(ScriptIterator) {
   6340   CcTest::InitializeVM();
   6341   v8::HandleScope scope(CcTest::isolate());
   6342   Isolate* isolate = CcTest::i_isolate();
   6343   Heap* heap = CcTest::heap();
   6344   LocalContext context;
   6345 
   6346   heap->CollectAllGarbage();
   6347 
   6348   int script_count = 0;
   6349   {
   6350     HeapIterator it(heap);
   6351     for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
   6352       if (obj->IsScript()) script_count++;
   6353     }
   6354   }
   6355 
   6356   {
   6357     Script::Iterator iterator(isolate);
   6358     while (iterator.Next()) script_count--;
   6359   }
   6360 
   6361   CHECK_EQ(0, script_count);
   6362 }
   6363 
   6364 
   6365 TEST(SharedFunctionInfoIterator) {
   6366   CcTest::InitializeVM();
   6367   v8::HandleScope scope(CcTest::isolate());
   6368   Isolate* isolate = CcTest::i_isolate();
   6369   Heap* heap = CcTest::heap();
   6370   LocalContext context;
   6371 
   6372   heap->CollectAllGarbage();
   6373   heap->CollectAllGarbage();
   6374 
   6375   int sfi_count = 0;
   6376   {
   6377     HeapIterator it(heap);
   6378     for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
   6379       if (!obj->IsSharedFunctionInfo()) continue;
   6380       sfi_count++;
   6381     }
   6382   }
   6383 
   6384   {
   6385     SharedFunctionInfo::Iterator iterator(isolate);
   6386     while (iterator.Next()) sfi_count--;
   6387   }
   6388 
   6389   CHECK_EQ(0, sfi_count);
   6390 }
   6391 
   6392 
   6393 template <typename T>
   6394 static UniqueId MakeUniqueId(const Persistent<T>& p) {
   6395   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
   6396 }
   6397 
   6398 
   6399 TEST(Regress519319) {
   6400   CcTest::InitializeVM();
   6401   v8::Isolate* isolate = CcTest::isolate();
   6402   v8::HandleScope scope(isolate);
   6403   Heap* heap = CcTest::heap();
   6404   LocalContext context;
   6405 
   6406   v8::Persistent<Value> parent;
   6407   v8::Persistent<Value> child;
   6408 
   6409   parent.Reset(isolate, v8::Object::New(isolate));
   6410   child.Reset(isolate, v8::Object::New(isolate));
   6411 
   6412   heap::SimulateFullSpace(heap->old_space());
   6413   heap->CollectGarbage(OLD_SPACE);
   6414   {
   6415     UniqueId id = MakeUniqueId(parent);
   6416     isolate->SetObjectGroupId(parent, id);
   6417     isolate->SetReferenceFromGroup(id, child);
   6418   }
   6419   // The CollectGarbage call above starts sweeper threads.
   6420   // The crash will happen if the following two functions
   6421   // are called before sweeping finishes.
   6422   heap->StartIncrementalMarking();
   6423   heap->FinalizeIncrementalMarkingIfComplete("test");
   6424 }
   6425 
   6426 
   6427 HEAP_TEST(TestMemoryReducerSampleJsCalls) {
   6428   CcTest::InitializeVM();
   6429   v8::HandleScope scope(CcTest::isolate());
   6430   Heap* heap = CcTest::heap();
   6431   Isolate* isolate = CcTest::i_isolate();
   6432   MemoryReducer* memory_reducer = heap->memory_reducer_;
   6433   memory_reducer->SampleAndGetJsCallsPerMs(0);
   6434   isolate->IncrementJsCallsFromApiCounter();
   6435   isolate->IncrementJsCallsFromApiCounter();
   6436   isolate->IncrementJsCallsFromApiCounter();
   6437   double calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(1);
   6438   CheckDoubleEquals(3, calls_per_ms);
   6439 
   6440   calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(2);
   6441   CheckDoubleEquals(0, calls_per_ms);
   6442 
   6443   isolate->IncrementJsCallsFromApiCounter();
   6444   isolate->IncrementJsCallsFromApiCounter();
   6445   isolate->IncrementJsCallsFromApiCounter();
   6446   isolate->IncrementJsCallsFromApiCounter();
   6447   calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(4);
   6448   CheckDoubleEquals(2, calls_per_ms);
   6449 }
   6450 
   6451 HEAP_TEST(Regress587004) {
   6452   FLAG_concurrent_sweeping = false;
   6453 #ifdef VERIFY_HEAP
   6454   FLAG_verify_heap = false;
   6455 #endif
   6456   CcTest::InitializeVM();
   6457   v8::HandleScope scope(CcTest::isolate());
   6458   Heap* heap = CcTest::heap();
   6459   Isolate* isolate = CcTest::i_isolate();
   6460   Factory* factory = isolate->factory();
   6461   const int N = (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) /
   6462                 kPointerSize;
   6463   Handle<FixedArray> array = factory->NewFixedArray(N, TENURED);
   6464   CHECK(heap->old_space()->Contains(*array));
   6465   Handle<Object> number = factory->NewHeapNumber(1.0);
   6466   CHECK(heap->InNewSpace(*number));
   6467   for (int i = 0; i < N; i++) {
   6468     array->set(i, *number);
   6469   }
   6470   heap->CollectGarbage(OLD_SPACE);
   6471   heap::SimulateFullSpace(heap->old_space());
   6472   heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, N - 1);
   6473   heap->mark_compact_collector()->EnsureSweepingCompleted();
   6474   ByteArray* byte_array;
   6475   const int M = 256;
   6476   // Don't allow old space expansion. The test works without this flag too,
   6477   // but becomes very slow.
   6478   heap->set_force_oom(true);
   6479   while (heap->AllocateByteArray(M, TENURED).To(&byte_array)) {
   6480     for (int j = 0; j < M; j++) {
   6481       byte_array->set(j, 0x31);
   6482     }
   6483   }
   6484   // Re-enable old space expansion to avoid OOM crash.
   6485   heap->set_force_oom(false);
   6486   heap->CollectGarbage(NEW_SPACE);
   6487 }
   6488 
   6489 HEAP_TEST(Regress589413) {
   6490   FLAG_stress_compaction = true;
   6491   FLAG_manual_evacuation_candidates_selection = true;
   6492   FLAG_parallel_compaction = false;
   6493   FLAG_concurrent_sweeping = false;
   6494   CcTest::InitializeVM();
   6495   v8::HandleScope scope(CcTest::isolate());
   6496   Heap* heap = CcTest::heap();
   6497   // Get the heap in clean state.
   6498   heap->CollectGarbage(OLD_SPACE);
   6499   heap->CollectGarbage(OLD_SPACE);
   6500   Isolate* isolate = CcTest::i_isolate();
   6501   Factory* factory = isolate->factory();
   6502   // Fill the new space with byte arrays with elements looking like pointers.
   6503   const int M = 256;
   6504   ByteArray* byte_array;
   6505   while (heap->AllocateByteArray(M).To(&byte_array)) {
   6506     for (int j = 0; j < M; j++) {
   6507       byte_array->set(j, 0x31);
   6508     }
   6509     // Add the array in root set.
   6510     handle(byte_array);
   6511   }
   6512   // Make sure the byte arrays will be promoted on the next GC.
   6513   heap->CollectGarbage(NEW_SPACE);
   6514   // This number is close to large free list category threshold.
   6515   const int N = 0x3eee;
   6516   {
   6517     std::vector<FixedArray*> arrays;
   6518     std::set<Page*> pages;
   6519     FixedArray* array;
   6520     // Fill all pages with fixed arrays.
   6521     heap->set_force_oom(true);
   6522     while (heap->AllocateFixedArray(N, TENURED).To(&array)) {
   6523       arrays.push_back(array);
   6524       pages.insert(Page::FromAddress(array->address()));
   6525       // Add the array in root set.
   6526       handle(array);
   6527     }
   6528     // Expand and full one complete page with fixed arrays.
   6529     heap->set_force_oom(false);
   6530     while (heap->AllocateFixedArray(N, TENURED).To(&array)) {
   6531       arrays.push_back(array);
   6532       pages.insert(Page::FromAddress(array->address()));
   6533       // Add the array in root set.
   6534       handle(array);
   6535       // Do not expand anymore.
   6536       heap->set_force_oom(true);
   6537     }
   6538     // Expand and mark the new page as evacuation candidate.
   6539     heap->set_force_oom(false);
   6540     {
   6541       AlwaysAllocateScope always_allocate(isolate);
   6542       Handle<HeapObject> ec_obj = factory->NewFixedArray(5000, TENURED);
   6543       Page* ec_page = Page::FromAddress(ec_obj->address());
   6544       ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
   6545       // Make all arrays point to evacuation candidate so that
   6546       // slots are recorded for them.
   6547       for (size_t j = 0; j < arrays.size(); j++) {
   6548         array = arrays[j];
   6549         for (int i = 0; i < N; i++) {
   6550           array->set(i, *ec_obj);
   6551         }
   6552       }
   6553     }
   6554     heap::SimulateIncrementalMarking(heap);
   6555     for (size_t j = 0; j < arrays.size(); j++) {
   6556       heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(arrays[j], N - 1);
   6557     }
   6558   }
   6559   // Force allocation from the free list.
   6560   heap->set_force_oom(true);
   6561   heap->CollectGarbage(OLD_SPACE);
   6562 }
   6563 
   6564 TEST(Regress598319) {
   6565   // This test ensures that no white objects can cross the progress bar of large
   6566   // objects during incremental marking. It checks this by using Shift() during
   6567   // incremental marking.
   6568   CcTest::InitializeVM();
   6569   v8::HandleScope scope(CcTest::isolate());
   6570   Heap* heap = CcTest::heap();
   6571   Isolate* isolate = heap->isolate();
   6572 
   6573   const int kNumberOfObjects = Page::kMaxRegularHeapObjectSize / kPointerSize;
   6574 
   6575   struct Arr {
   6576     Arr(Isolate* isolate, int number_of_objects) {
   6577       root = isolate->factory()->NewFixedArray(1, TENURED);
   6578       {
   6579         // Temporary scope to avoid getting any other objects into the root set.
   6580         v8::HandleScope scope(CcTest::isolate());
   6581         Handle<FixedArray> tmp =
   6582             isolate->factory()->NewFixedArray(number_of_objects);
   6583         root->set(0, *tmp);
   6584         for (int i = 0; i < get()->length(); i++) {
   6585           tmp = isolate->factory()->NewFixedArray(100, TENURED);
   6586           get()->set(i, *tmp);
   6587         }
   6588       }
   6589     }
   6590 
   6591     FixedArray* get() { return FixedArray::cast(root->get(0)); }
   6592 
   6593     Handle<FixedArray> root;
   6594   } arr(isolate, kNumberOfObjects);
   6595 
   6596   CHECK_EQ(arr.get()->length(), kNumberOfObjects);
   6597   CHECK(heap->lo_space()->Contains(arr.get()));
   6598   LargePage* page = heap->lo_space()->FindPage(arr.get()->address());
   6599   CHECK_NOT_NULL(page);
   6600 
   6601   // GC to cleanup state
   6602   heap->CollectGarbage(OLD_SPACE);
   6603   MarkCompactCollector* collector = heap->mark_compact_collector();
   6604   if (collector->sweeping_in_progress()) {
   6605     collector->EnsureSweepingCompleted();
   6606   }
   6607 
   6608   CHECK(heap->lo_space()->Contains(arr.get()));
   6609   CHECK(Marking::IsWhite(Marking::MarkBitFrom(arr.get())));
   6610   for (int i = 0; i < arr.get()->length(); i++) {
   6611     CHECK(Marking::IsWhite(
   6612         Marking::MarkBitFrom(HeapObject::cast(arr.get()->get(i)))));
   6613   }
   6614 
   6615   // Start incremental marking.
   6616   IncrementalMarking* marking = heap->incremental_marking();
   6617   CHECK(marking->IsMarking() || marking->IsStopped());
   6618   if (marking->IsStopped()) {
   6619     heap->StartIncrementalMarking();
   6620   }
   6621   CHECK(marking->IsMarking());
   6622 
   6623   // Check that we have not marked the interesting array during root scanning.
   6624   for (int i = 0; i < arr.get()->length(); i++) {
   6625     CHECK(Marking::IsWhite(
   6626         Marking::MarkBitFrom(HeapObject::cast(arr.get()->get(i)))));
   6627   }
   6628 
   6629   // Now we search for a state where we are in incremental marking and have
   6630   // only partially marked the large object.
   6631   while (!marking->IsComplete()) {
   6632     marking->Step(i::KB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   6633     if (page->IsFlagSet(Page::HAS_PROGRESS_BAR) && page->progress_bar() > 0) {
   6634       CHECK_NE(page->progress_bar(), arr.get()->Size());
   6635       {
   6636         // Shift by 1, effectively moving one white object across the progress
   6637         // bar, meaning that we will miss marking it.
   6638         v8::HandleScope scope(CcTest::isolate());
   6639         Handle<JSArray> js_array = isolate->factory()->NewJSArrayWithElements(
   6640             Handle<FixedArray>(arr.get()));
   6641         js_array->GetElementsAccessor()->Shift(js_array);
   6642       }
   6643       break;
   6644     }
   6645   }
   6646 
   6647   // Finish marking with bigger steps to speed up test.
   6648   while (!marking->IsComplete()) {
   6649     marking->Step(10 * i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   6650     if (marking->IsReadyToOverApproximateWeakClosure()) {
   6651       marking->FinalizeIncrementally();
   6652     }
   6653   }
   6654   CHECK(marking->IsComplete());
   6655 
   6656   // All objects need to be black after marking. If a white object crossed the
   6657   // progress bar, we would fail here.
   6658   for (int i = 0; i < arr.get()->length(); i++) {
   6659     CHECK(Marking::IsBlack(
   6660         Marking::MarkBitFrom(HeapObject::cast(arr.get()->get(i)))));
   6661   }
   6662 }
   6663 
   6664 TEST(Regress609761) {
   6665   CcTest::InitializeVM();
   6666   v8::HandleScope scope(CcTest::isolate());
   6667   Heap* heap = CcTest::heap();
   6668   Isolate* isolate = heap->isolate();
   6669 
   6670   intptr_t size_before = heap->SizeOfObjects();
   6671   Handle<FixedArray> array = isolate->factory()->NewFixedArray(200000);
   6672   array->Shrink(1);
   6673   intptr_t size_after = heap->SizeOfObjects();
   6674   CHECK_EQ(size_after, size_before + array->Size());
   6675 }
   6676 
   6677 TEST(Regress615489) {
   6678   FLAG_black_allocation = true;
   6679   CcTest::InitializeVM();
   6680   v8::HandleScope scope(CcTest::isolate());
   6681   Heap* heap = CcTest::heap();
   6682   Isolate* isolate = heap->isolate();
   6683   heap->CollectAllGarbage();
   6684 
   6685   i::MarkCompactCollector* collector = heap->mark_compact_collector();
   6686   i::IncrementalMarking* marking = heap->incremental_marking();
   6687   if (collector->sweeping_in_progress()) {
   6688     collector->EnsureSweepingCompleted();
   6689   }
   6690   CHECK(marking->IsMarking() || marking->IsStopped());
   6691   if (marking->IsStopped()) {
   6692     heap->StartIncrementalMarking();
   6693   }
   6694   CHECK(marking->IsMarking());
   6695   marking->StartBlackAllocationForTesting();
   6696   {
   6697     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   6698     v8::HandleScope inner(CcTest::isolate());
   6699     isolate->factory()->NewFixedArray(500, TENURED)->Size();
   6700   }
   6701   while (!marking->IsComplete()) {
   6702     marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
   6703     if (marking->IsReadyToOverApproximateWeakClosure()) {
   6704       marking->FinalizeIncrementally();
   6705     }
   6706   }
   6707   CHECK(marking->IsComplete());
   6708   intptr_t size_before = heap->SizeOfObjects();
   6709   CcTest::heap()->CollectAllGarbage();
   6710   intptr_t size_after = heap->SizeOfObjects();
   6711   // Live size does not increase after garbage collection.
   6712   CHECK_LE(size_after, size_before);
   6713 }
   6714 
   6715 TEST(Regress618958) {
   6716   CcTest::InitializeVM();
   6717   v8::HandleScope scope(CcTest::isolate());
   6718   Heap* heap = CcTest::heap();
   6719   bool isolate_is_locked = true;
   6720   heap->update_external_memory(100 * MB);
   6721   int mark_sweep_count_before = heap->ms_count();
   6722   heap->MemoryPressureNotification(MemoryPressureLevel::kCritical,
   6723                                    isolate_is_locked);
   6724   int mark_sweep_count_after = heap->ms_count();
   6725   int mark_sweeps_performed = mark_sweep_count_after - mark_sweep_count_before;
   6726   // The memory pressuer handler either performed two GCs or performed one and
   6727   // started incremental marking.
   6728   CHECK(mark_sweeps_performed == 2 ||
   6729         (mark_sweeps_performed == 1 &&
   6730          !heap->incremental_marking()->IsStopped()));
   6731 }
   6732 
   6733 }  // namespace internal
   6734 }  // namespace v8
   6735