Home | History | Annotate | Download | only in cctest
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/base/utils/random-number-generator.h"
      6 #include "src/ic/stub-cache.h"
      7 #include "src/isolate.h"
      8 #include "test/cctest/compiler/code-assembler-tester.h"
      9 #include "test/cctest/compiler/function-tester.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 using compiler::FunctionTester;
     15 using compiler::Node;
     16 
     17 typedef compiler::CodeAssemblerTesterImpl<CodeStubAssembler>
     18     CodeStubAssemblerTester;
     19 
     20 TEST(FixedArrayAccessSmiIndex) {
     21   Isolate* isolate(CcTest::InitIsolateOnce());
     22   VoidDescriptor descriptor(isolate);
     23   CodeStubAssemblerTester m(isolate, descriptor);
     24   Handle<FixedArray> array = isolate->factory()->NewFixedArray(5);
     25   array->set(4, Smi::FromInt(733));
     26   m.Return(m.LoadFixedArrayElement(m.HeapConstant(array),
     27                                    m.SmiTag(m.Int32Constant(4)), 0,
     28                                    CodeStubAssembler::SMI_PARAMETERS));
     29   Handle<Code> code = m.GenerateCode();
     30   FunctionTester ft(descriptor, code);
     31   MaybeHandle<Object> result = ft.Call();
     32   CHECK_EQ(733, Handle<Smi>::cast(result.ToHandleChecked())->value());
     33 }
     34 
     35 TEST(LoadHeapNumberValue) {
     36   Isolate* isolate(CcTest::InitIsolateOnce());
     37   VoidDescriptor descriptor(isolate);
     38   CodeStubAssemblerTester m(isolate, descriptor);
     39   Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(1234);
     40   m.Return(m.SmiTag(
     41       m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number)))));
     42   Handle<Code> code = m.GenerateCode();
     43   FunctionTester ft(descriptor, code);
     44   MaybeHandle<Object> result = ft.Call();
     45   CHECK_EQ(1234, Handle<Smi>::cast(result.ToHandleChecked())->value());
     46 }
     47 
     48 TEST(LoadInstanceType) {
     49   Isolate* isolate(CcTest::InitIsolateOnce());
     50   VoidDescriptor descriptor(isolate);
     51   CodeStubAssemblerTester m(isolate, descriptor);
     52   Handle<HeapObject> undefined = isolate->factory()->undefined_value();
     53   m.Return(m.SmiTag(m.LoadInstanceType(m.HeapConstant(undefined))));
     54   Handle<Code> code = m.GenerateCode();
     55   FunctionTester ft(descriptor, code);
     56   MaybeHandle<Object> result = ft.Call();
     57   CHECK_EQ(InstanceType::ODDBALL_TYPE,
     58            Handle<Smi>::cast(result.ToHandleChecked())->value());
     59 }
     60 
     61 TEST(BitFieldDecode) {
     62   Isolate* isolate(CcTest::InitIsolateOnce());
     63   VoidDescriptor descriptor(isolate);
     64   CodeStubAssemblerTester m(isolate, descriptor);
     65 
     66   class TestBitField : public BitField<unsigned, 3, 3> {};
     67   m.Return(m.SmiTag(m.BitFieldDecode<TestBitField>(m.Int32Constant(0x2f))));
     68   Handle<Code> code = m.GenerateCode();
     69   FunctionTester ft(descriptor, code);
     70   MaybeHandle<Object> result = ft.Call();
     71   // value  = 00101111
     72   // mask   = 00111000
     73   // result = 101
     74   CHECK_EQ(5, Handle<Smi>::cast(result.ToHandleChecked())->value());
     75 }
     76 
     77 TEST(JSFunction) {
     78   const int kNumParams = 3;  // Receiver, left, right.
     79   Isolate* isolate(CcTest::InitIsolateOnce());
     80   CodeStubAssemblerTester m(isolate, kNumParams);
     81   m.Return(m.SmiFromWord32(m.Int32Add(m.SmiToWord32(m.Parameter(1)),
     82                                       m.SmiToWord32(m.Parameter(2)))));
     83 
     84   Handle<Code> code = m.GenerateCode();
     85   FunctionTester ft(code, kNumParams);
     86 
     87   MaybeHandle<Object> result = ft.Call(isolate->factory()->undefined_value(),
     88                                        handle(Smi::FromInt(23), isolate),
     89                                        handle(Smi::FromInt(34), isolate));
     90   CHECK_EQ(57, Handle<Smi>::cast(result.ToHandleChecked())->value());
     91 }
     92 
     93 TEST(ComputeIntegerHash) {
     94   Isolate* isolate(CcTest::InitIsolateOnce());
     95   const int kNumParams = 2;
     96   CodeStubAssemblerTester m(isolate, kNumParams);
     97   m.Return(m.SmiFromWord32(m.ComputeIntegerHash(
     98       m.SmiToWord32(m.Parameter(0)), m.SmiToWord32(m.Parameter(1)))));
     99 
    100   Handle<Code> code = m.GenerateCode();
    101   FunctionTester ft(code, kNumParams);
    102 
    103   Handle<Smi> hash_seed = isolate->factory()->hash_seed();
    104 
    105   base::RandomNumberGenerator rand_gen(FLAG_random_seed);
    106 
    107   for (int i = 0; i < 1024; i++) {
    108     int k = rand_gen.NextInt(Smi::kMaxValue);
    109 
    110     Handle<Smi> key(Smi::FromInt(k), isolate);
    111     Handle<Object> result = ft.Call(key, hash_seed).ToHandleChecked();
    112 
    113     uint32_t hash = ComputeIntegerHash(k, hash_seed->value());
    114     Smi* expected = Smi::FromInt(hash & Smi::kMaxValue);
    115     CHECK_EQ(expected, Smi::cast(*result));
    116   }
    117 }
    118 
    119 TEST(TryToName) {
    120   typedef CodeStubAssembler::Label Label;
    121   typedef CodeStubAssembler::Variable Variable;
    122   Isolate* isolate(CcTest::InitIsolateOnce());
    123 
    124   const int kNumParams = 3;
    125   CodeStubAssemblerTester m(isolate, kNumParams);
    126 
    127   enum Result { kKeyIsIndex, kKeyIsUnique, kBailout };
    128   {
    129     Node* key = m.Parameter(0);
    130     Node* expected_result = m.Parameter(1);
    131     Node* expected_arg = m.Parameter(2);
    132 
    133     Label passed(&m), failed(&m);
    134     Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m);
    135     Variable var_index(&m, MachineRepresentation::kWord32);
    136 
    137     m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout);
    138 
    139     m.Bind(&if_keyisindex);
    140     m.GotoUnless(
    141         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
    142         &failed);
    143     m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_index.value()),
    144              &passed, &failed);
    145 
    146     m.Bind(&if_keyisunique);
    147     m.GotoUnless(
    148         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsUnique))),
    149         &failed);
    150     m.Branch(m.WordEqual(expected_arg, key), &passed, &failed);
    151 
    152     m.Bind(&if_bailout);
    153     m.Branch(
    154         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
    155         &passed, &failed);
    156 
    157     m.Bind(&passed);
    158     m.Return(m.BooleanConstant(true));
    159 
    160     m.Bind(&failed);
    161     m.Return(m.BooleanConstant(false));
    162   }
    163 
    164   Handle<Code> code = m.GenerateCode();
    165   FunctionTester ft(code, kNumParams);
    166 
    167   Handle<Object> expect_index(Smi::FromInt(kKeyIsIndex), isolate);
    168   Handle<Object> expect_unique(Smi::FromInt(kKeyIsUnique), isolate);
    169   Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
    170 
    171   {
    172     // TryToName(<zero smi>) => if_keyisindex: smi value.
    173     Handle<Object> key(Smi::FromInt(0), isolate);
    174     ft.CheckTrue(key, expect_index, key);
    175   }
    176 
    177   {
    178     // TryToName(<positive smi>) => if_keyisindex: smi value.
    179     Handle<Object> key(Smi::FromInt(153), isolate);
    180     ft.CheckTrue(key, expect_index, key);
    181   }
    182 
    183   {
    184     // TryToName(<negative smi>) => bailout.
    185     Handle<Object> key(Smi::FromInt(-1), isolate);
    186     ft.CheckTrue(key, expect_bailout);
    187   }
    188 
    189   {
    190     // TryToName(<symbol>) => if_keyisunique: <symbol>.
    191     Handle<Object> key = isolate->factory()->NewSymbol();
    192     ft.CheckTrue(key, expect_unique, key);
    193   }
    194 
    195   {
    196     // TryToName(<internalized string>) => if_keyisunique: <internalized string>
    197     Handle<Object> key = isolate->factory()->InternalizeUtf8String("test");
    198     ft.CheckTrue(key, expect_unique, key);
    199   }
    200 
    201   {
    202     // TryToName(<internalized number string>) => if_keyisindex: number.
    203     Handle<Object> key = isolate->factory()->InternalizeUtf8String("153");
    204     Handle<Object> index(Smi::FromInt(153), isolate);
    205     ft.CheckTrue(key, expect_index, index);
    206   }
    207 
    208   {
    209     // TryToName(<non-internalized string>) => bailout.
    210     Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test");
    211     ft.CheckTrue(key, expect_bailout);
    212   }
    213 }
    214 
    215 namespace {
    216 
    217 template <typename Dictionary>
    218 void TestNameDictionaryLookup() {
    219   typedef CodeStubAssembler::Label Label;
    220   typedef CodeStubAssembler::Variable Variable;
    221   Isolate* isolate(CcTest::InitIsolateOnce());
    222 
    223   const int kNumParams = 4;
    224   CodeStubAssemblerTester m(isolate, kNumParams);
    225 
    226   enum Result { kFound, kNotFound };
    227   {
    228     Node* dictionary = m.Parameter(0);
    229     Node* unique_name = m.Parameter(1);
    230     Node* expected_result = m.Parameter(2);
    231     Node* expected_arg = m.Parameter(3);
    232 
    233     Label passed(&m), failed(&m);
    234     Label if_found(&m), if_not_found(&m);
    235     Variable var_name_index(&m, MachineRepresentation::kWord32);
    236 
    237     m.NameDictionaryLookup<Dictionary>(dictionary, unique_name, &if_found,
    238                                        &var_name_index, &if_not_found);
    239     m.Bind(&if_found);
    240     m.GotoUnless(
    241         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
    242         &failed);
    243     m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_name_index.value()),
    244              &passed, &failed);
    245 
    246     m.Bind(&if_not_found);
    247     m.Branch(
    248         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
    249         &passed, &failed);
    250 
    251     m.Bind(&passed);
    252     m.Return(m.BooleanConstant(true));
    253 
    254     m.Bind(&failed);
    255     m.Return(m.BooleanConstant(false));
    256   }
    257 
    258   Handle<Code> code = m.GenerateCode();
    259   FunctionTester ft(code, kNumParams);
    260 
    261   Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
    262   Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
    263 
    264   Handle<Dictionary> dictionary = Dictionary::New(isolate, 40);
    265   PropertyDetails fake_details = PropertyDetails::Empty();
    266 
    267   Factory* factory = isolate->factory();
    268   Handle<Name> keys[] = {
    269       factory->InternalizeUtf8String("0"),
    270       factory->InternalizeUtf8String("42"),
    271       factory->InternalizeUtf8String("-153"),
    272       factory->InternalizeUtf8String("0.0"),
    273       factory->InternalizeUtf8String("4.2"),
    274       factory->InternalizeUtf8String(""),
    275       factory->InternalizeUtf8String("name"),
    276       factory->NewSymbol(),
    277       factory->NewPrivateSymbol(),
    278   };
    279 
    280   for (size_t i = 0; i < arraysize(keys); i++) {
    281     Handle<Object> value = factory->NewPropertyCell();
    282     dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details);
    283   }
    284 
    285   for (size_t i = 0; i < arraysize(keys); i++) {
    286     int entry = dictionary->FindEntry(keys[i]);
    287     int name_index =
    288         Dictionary::EntryToIndex(entry) + Dictionary::kEntryKeyIndex;
    289     CHECK_NE(Dictionary::kNotFound, entry);
    290 
    291     Handle<Object> expected_name_index(Smi::FromInt(name_index), isolate);
    292     ft.CheckTrue(dictionary, keys[i], expect_found, expected_name_index);
    293   }
    294 
    295   Handle<Name> non_existing_keys[] = {
    296       factory->InternalizeUtf8String("1"),
    297       factory->InternalizeUtf8String("-42"),
    298       factory->InternalizeUtf8String("153"),
    299       factory->InternalizeUtf8String("-1.0"),
    300       factory->InternalizeUtf8String("1.3"),
    301       factory->InternalizeUtf8String("a"),
    302       factory->InternalizeUtf8String("boom"),
    303       factory->NewSymbol(),
    304       factory->NewPrivateSymbol(),
    305   };
    306 
    307   for (size_t i = 0; i < arraysize(non_existing_keys); i++) {
    308     int entry = dictionary->FindEntry(non_existing_keys[i]);
    309     CHECK_EQ(Dictionary::kNotFound, entry);
    310 
    311     ft.CheckTrue(dictionary, non_existing_keys[i], expect_not_found);
    312   }
    313 }
    314 
    315 }  // namespace
    316 
    317 TEST(NameDictionaryLookup) { TestNameDictionaryLookup<NameDictionary>(); }
    318 
    319 TEST(GlobalDictionaryLookup) { TestNameDictionaryLookup<GlobalDictionary>(); }
    320 
    321 namespace {
    322 
    323 template <typename Dictionary>
    324 void TestNumberDictionaryLookup() {
    325   typedef CodeStubAssembler::Label Label;
    326   typedef CodeStubAssembler::Variable Variable;
    327   Isolate* isolate(CcTest::InitIsolateOnce());
    328 
    329   const int kNumParams = 4;
    330   CodeStubAssemblerTester m(isolate, kNumParams);
    331 
    332   enum Result { kFound, kNotFound };
    333   {
    334     Node* dictionary = m.Parameter(0);
    335     Node* key = m.SmiToWord32(m.Parameter(1));
    336     Node* expected_result = m.Parameter(2);
    337     Node* expected_arg = m.Parameter(3);
    338 
    339     Label passed(&m), failed(&m);
    340     Label if_found(&m), if_not_found(&m);
    341     Variable var_entry(&m, MachineRepresentation::kWord32);
    342 
    343     m.NumberDictionaryLookup<Dictionary>(dictionary, key, &if_found, &var_entry,
    344                                          &if_not_found);
    345     m.Bind(&if_found);
    346     m.GotoUnless(
    347         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
    348         &failed);
    349     m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()),
    350              &passed, &failed);
    351 
    352     m.Bind(&if_not_found);
    353     m.Branch(
    354         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
    355         &passed, &failed);
    356 
    357     m.Bind(&passed);
    358     m.Return(m.BooleanConstant(true));
    359 
    360     m.Bind(&failed);
    361     m.Return(m.BooleanConstant(false));
    362   }
    363 
    364   Handle<Code> code = m.GenerateCode();
    365   FunctionTester ft(code, kNumParams);
    366 
    367   Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
    368   Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
    369 
    370   const int kKeysCount = 1000;
    371   Handle<Dictionary> dictionary = Dictionary::New(isolate, kKeysCount);
    372   uint32_t keys[kKeysCount];
    373 
    374   Handle<Object> fake_value(Smi::FromInt(42), isolate);
    375   PropertyDetails fake_details = PropertyDetails::Empty();
    376 
    377   base::RandomNumberGenerator rand_gen(FLAG_random_seed);
    378 
    379   for (int i = 0; i < kKeysCount; i++) {
    380     int random_key = rand_gen.NextInt(Smi::kMaxValue);
    381     keys[i] = static_cast<uint32_t>(random_key);
    382     if (dictionary->FindEntry(keys[i]) != Dictionary::kNotFound) continue;
    383 
    384     dictionary = Dictionary::Add(dictionary, keys[i], fake_value, fake_details);
    385   }
    386 
    387   // Now try querying existing keys.
    388   for (int i = 0; i < kKeysCount; i++) {
    389     int entry = dictionary->FindEntry(keys[i]);
    390     CHECK_NE(Dictionary::kNotFound, entry);
    391 
    392     Handle<Object> key(Smi::FromInt(keys[i]), isolate);
    393     Handle<Object> expected_entry(Smi::FromInt(entry), isolate);
    394     ft.CheckTrue(dictionary, key, expect_found, expected_entry);
    395   }
    396 
    397   // Now try querying random keys which do not exist in the dictionary.
    398   for (int i = 0; i < kKeysCount;) {
    399     int random_key = rand_gen.NextInt(Smi::kMaxValue);
    400     int entry = dictionary->FindEntry(random_key);
    401     if (entry != Dictionary::kNotFound) continue;
    402     i++;
    403 
    404     Handle<Object> key(Smi::FromInt(random_key), isolate);
    405     ft.CheckTrue(dictionary, key, expect_not_found);
    406   }
    407 }
    408 
    409 }  // namespace
    410 
    411 TEST(SeededNumberDictionaryLookup) {
    412   TestNumberDictionaryLookup<SeededNumberDictionary>();
    413 }
    414 
    415 TEST(UnseededNumberDictionaryLookup) {
    416   TestNumberDictionaryLookup<UnseededNumberDictionary>();
    417 }
    418 
    419 namespace {
    420 
    421 void AddProperties(Handle<JSObject> object, Handle<Name> names[],
    422                    size_t count) {
    423   Isolate* isolate = object->GetIsolate();
    424   for (size_t i = 0; i < count; i++) {
    425     Handle<Object> value(Smi::FromInt(static_cast<int>(42 + i)), isolate);
    426     JSObject::AddProperty(object, names[i], value, NONE);
    427   }
    428 }
    429 
    430 Handle<AccessorPair> CreateAccessorPair(FunctionTester* ft,
    431                                         const char* getter_body,
    432                                         const char* setter_body) {
    433   Handle<AccessorPair> pair = ft->isolate->factory()->NewAccessorPair();
    434   if (getter_body) {
    435     pair->set_getter(*ft->NewFunction(getter_body));
    436   }
    437   if (setter_body) {
    438     pair->set_setter(*ft->NewFunction(setter_body));
    439   }
    440   return pair;
    441 }
    442 
    443 void AddProperties(Handle<JSObject> object, Handle<Name> names[],
    444                    size_t names_count, Handle<Object> values[],
    445                    size_t values_count, int seed = 0) {
    446   Isolate* isolate = object->GetIsolate();
    447   for (size_t i = 0; i < names_count; i++) {
    448     Handle<Object> value = values[(seed + i) % values_count];
    449     if (value->IsAccessorPair()) {
    450       Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
    451       Handle<Object> getter(pair->getter(), isolate);
    452       Handle<Object> setter(pair->setter(), isolate);
    453       JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check();
    454     } else {
    455       JSObject::AddProperty(object, names[i], value, NONE);
    456     }
    457   }
    458 }
    459 
    460 }  // namespace
    461 
    462 TEST(TryHasOwnProperty) {
    463   typedef CodeStubAssembler::Label Label;
    464   Isolate* isolate(CcTest::InitIsolateOnce());
    465 
    466   const int kNumParams = 4;
    467   CodeStubAssemblerTester m(isolate, kNumParams);
    468 
    469   enum Result { kFound, kNotFound, kBailout };
    470   {
    471     Node* object = m.Parameter(0);
    472     Node* unique_name = m.Parameter(1);
    473     Node* expected_result = m.Parameter(2);
    474 
    475     Label passed(&m), failed(&m);
    476     Label if_found(&m), if_not_found(&m), if_bailout(&m);
    477 
    478     Node* map = m.LoadMap(object);
    479     Node* instance_type = m.LoadMapInstanceType(map);
    480 
    481     m.TryHasOwnProperty(object, map, instance_type, unique_name, &if_found,
    482                         &if_not_found, &if_bailout);
    483 
    484     m.Bind(&if_found);
    485     m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
    486              &passed, &failed);
    487 
    488     m.Bind(&if_not_found);
    489     m.Branch(
    490         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
    491         &passed, &failed);
    492 
    493     m.Bind(&if_bailout);
    494     m.Branch(
    495         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
    496         &passed, &failed);
    497 
    498     m.Bind(&passed);
    499     m.Return(m.BooleanConstant(true));
    500 
    501     m.Bind(&failed);
    502     m.Return(m.BooleanConstant(false));
    503   }
    504 
    505   Handle<Code> code = m.GenerateCode();
    506   FunctionTester ft(code, kNumParams);
    507 
    508   Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
    509   Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
    510   Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
    511 
    512   Factory* factory = isolate->factory();
    513 
    514   Handle<Name> deleted_property_name =
    515       factory->InternalizeUtf8String("deleted");
    516 
    517   Handle<Name> names[] = {
    518       factory->InternalizeUtf8String("a"),
    519       factory->InternalizeUtf8String("bb"),
    520       factory->InternalizeUtf8String("ccc"),
    521       factory->InternalizeUtf8String("dddd"),
    522       factory->InternalizeUtf8String("eeeee"),
    523       factory->InternalizeUtf8String(""),
    524       factory->InternalizeUtf8String("name"),
    525       factory->NewSymbol(),
    526       factory->NewPrivateSymbol(),
    527   };
    528 
    529   std::vector<Handle<JSObject>> objects;
    530 
    531   {
    532     // Fast object, no inobject properties.
    533     int inobject_properties = 0;
    534     Handle<Map> map = Map::Create(isolate, inobject_properties);
    535     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    536     AddProperties(object, names, arraysize(names));
    537     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    538     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    539     CHECK(!object->map()->is_dictionary_map());
    540     objects.push_back(object);
    541   }
    542 
    543   {
    544     // Fast object, all inobject properties.
    545     int inobject_properties = arraysize(names) * 2;
    546     Handle<Map> map = Map::Create(isolate, inobject_properties);
    547     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    548     AddProperties(object, names, arraysize(names));
    549     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    550     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    551     CHECK(!object->map()->is_dictionary_map());
    552     objects.push_back(object);
    553   }
    554 
    555   {
    556     // Fast object, half inobject properties.
    557     int inobject_properties = arraysize(names) / 2;
    558     Handle<Map> map = Map::Create(isolate, inobject_properties);
    559     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    560     AddProperties(object, names, arraysize(names));
    561     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    562     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    563     CHECK(!object->map()->is_dictionary_map());
    564     objects.push_back(object);
    565   }
    566 
    567   {
    568     // Dictionary mode object.
    569     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
    570     Handle<JSObject> object = factory->NewJSObject(function);
    571     AddProperties(object, names, arraysize(names));
    572     JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test");
    573 
    574     JSObject::AddProperty(object, deleted_property_name, object, NONE);
    575     CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY)
    576               .FromJust());
    577 
    578     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    579     CHECK(object->map()->is_dictionary_map());
    580     objects.push_back(object);
    581   }
    582 
    583   {
    584     // Global object.
    585     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
    586     JSFunction::EnsureHasInitialMap(function);
    587     function->initial_map()->set_instance_type(JS_GLOBAL_OBJECT_TYPE);
    588     function->initial_map()->set_is_prototype_map(true);
    589     function->initial_map()->set_dictionary_map(true);
    590     Handle<JSObject> object = factory->NewJSGlobalObject(function);
    591     AddProperties(object, names, arraysize(names));
    592 
    593     JSObject::AddProperty(object, deleted_property_name, object, NONE);
    594     CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY)
    595               .FromJust());
    596 
    597     CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type());
    598     CHECK(object->map()->is_dictionary_map());
    599     objects.push_back(object);
    600   }
    601 
    602   {
    603     for (Handle<JSObject> object : objects) {
    604       for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
    605         Handle<Name> name = names[name_index];
    606         CHECK(JSReceiver::HasProperty(object, name).FromJust());
    607         ft.CheckTrue(object, name, expect_found);
    608       }
    609     }
    610   }
    611 
    612   {
    613     Handle<Name> non_existing_names[] = {
    614         factory->NewSymbol(),
    615         factory->InternalizeUtf8String("ne_a"),
    616         factory->InternalizeUtf8String("ne_bb"),
    617         factory->NewPrivateSymbol(),
    618         factory->InternalizeUtf8String("ne_ccc"),
    619         factory->InternalizeUtf8String("ne_dddd"),
    620         deleted_property_name,
    621     };
    622     for (Handle<JSObject> object : objects) {
    623       for (size_t key_index = 0; key_index < arraysize(non_existing_names);
    624            key_index++) {
    625         Handle<Name> name = non_existing_names[key_index];
    626         CHECK(!JSReceiver::HasProperty(object, name).FromJust());
    627         ft.CheckTrue(object, name, expect_not_found);
    628       }
    629     }
    630   }
    631 
    632   {
    633     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
    634     Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]);
    635     CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type());
    636     ft.CheckTrue(object, names[0], expect_bailout);
    637   }
    638 
    639   {
    640     Handle<JSObject> object = isolate->global_proxy();
    641     CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type());
    642     ft.CheckTrue(object, names[0], expect_bailout);
    643   }
    644 }
    645 
    646 TEST(TryGetOwnProperty) {
    647   typedef CodeStubAssembler::Label Label;
    648   typedef CodeStubAssembler::Variable Variable;
    649   Isolate* isolate(CcTest::InitIsolateOnce());
    650   Factory* factory = isolate->factory();
    651 
    652   const int kNumParams = 2;
    653   CodeStubAssemblerTester m(isolate, kNumParams);
    654 
    655   Handle<Symbol> not_found_symbol = factory->NewSymbol();
    656   Handle<Symbol> bailout_symbol = factory->NewSymbol();
    657   {
    658     Node* object = m.Parameter(0);
    659     Node* unique_name = m.Parameter(1);
    660     Node* context = m.Parameter(kNumParams + 2);
    661 
    662     Variable var_value(&m, MachineRepresentation::kTagged);
    663     Label if_found(&m), if_not_found(&m), if_bailout(&m);
    664 
    665     Node* map = m.LoadMap(object);
    666     Node* instance_type = m.LoadMapInstanceType(map);
    667 
    668     m.TryGetOwnProperty(context, object, object, map, instance_type,
    669                         unique_name, &if_found, &var_value, &if_not_found,
    670                         &if_bailout);
    671 
    672     m.Bind(&if_found);
    673     m.Return(var_value.value());
    674 
    675     m.Bind(&if_not_found);
    676     m.Return(m.HeapConstant(not_found_symbol));
    677 
    678     m.Bind(&if_bailout);
    679     m.Return(m.HeapConstant(bailout_symbol));
    680   }
    681 
    682   Handle<Code> code = m.GenerateCode();
    683   FunctionTester ft(code, kNumParams);
    684 
    685   Handle<Name> deleted_property_name =
    686       factory->InternalizeUtf8String("deleted");
    687 
    688   Handle<Name> names[] = {
    689       factory->InternalizeUtf8String("bb"),
    690       factory->NewSymbol(),
    691       factory->InternalizeUtf8String("a"),
    692       factory->InternalizeUtf8String("ccc"),
    693       factory->InternalizeUtf8String("esajefe"),
    694       factory->NewPrivateSymbol(),
    695       factory->InternalizeUtf8String("eeeee"),
    696       factory->InternalizeUtf8String("p1"),
    697       factory->InternalizeUtf8String("acshw23e"),
    698       factory->InternalizeUtf8String(""),
    699       factory->InternalizeUtf8String("dddd"),
    700       factory->NewPrivateSymbol(),
    701       factory->InternalizeUtf8String("name"),
    702       factory->InternalizeUtf8String("p2"),
    703       factory->InternalizeUtf8String("p3"),
    704       factory->InternalizeUtf8String("p4"),
    705       factory->NewPrivateSymbol(),
    706   };
    707   Handle<Object> values[] = {
    708       factory->NewFunction(factory->empty_string()),
    709       factory->NewSymbol(),
    710       factory->InternalizeUtf8String("a"),
    711       CreateAccessorPair(&ft, "() => 188;", "() => 199;"),
    712       factory->NewFunction(factory->InternalizeUtf8String("bb")),
    713       factory->InternalizeUtf8String("ccc"),
    714       CreateAccessorPair(&ft, "() => 88;", nullptr),
    715       handle(Smi::FromInt(1), isolate),
    716       factory->InternalizeUtf8String(""),
    717       CreateAccessorPair(&ft, nullptr, "() => 99;"),
    718       factory->NewHeapNumber(4.2),
    719       handle(Smi::FromInt(153), isolate),
    720       factory->NewJSObject(factory->NewFunction(factory->empty_string())),
    721       factory->NewPrivateSymbol(),
    722   };
    723   STATIC_ASSERT(arraysize(values) < arraysize(names));
    724 
    725   base::RandomNumberGenerator rand_gen(FLAG_random_seed);
    726 
    727   std::vector<Handle<JSObject>> objects;
    728 
    729   {
    730     // Fast object, no inobject properties.
    731     int inobject_properties = 0;
    732     Handle<Map> map = Map::Create(isolate, inobject_properties);
    733     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    734     AddProperties(object, names, arraysize(names), values, arraysize(values),
    735                   rand_gen.NextInt());
    736     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    737     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    738     CHECK(!object->map()->is_dictionary_map());
    739     objects.push_back(object);
    740   }
    741 
    742   {
    743     // Fast object, all inobject properties.
    744     int inobject_properties = arraysize(names) * 2;
    745     Handle<Map> map = Map::Create(isolate, inobject_properties);
    746     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    747     AddProperties(object, names, arraysize(names), values, arraysize(values),
    748                   rand_gen.NextInt());
    749     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    750     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    751     CHECK(!object->map()->is_dictionary_map());
    752     objects.push_back(object);
    753   }
    754 
    755   {
    756     // Fast object, half inobject properties.
    757     int inobject_properties = arraysize(names) / 2;
    758     Handle<Map> map = Map::Create(isolate, inobject_properties);
    759     Handle<JSObject> object = factory->NewJSObjectFromMap(map);
    760     AddProperties(object, names, arraysize(names), values, arraysize(values),
    761                   rand_gen.NextInt());
    762     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    763     CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties());
    764     CHECK(!object->map()->is_dictionary_map());
    765     objects.push_back(object);
    766   }
    767 
    768   {
    769     // Dictionary mode object.
    770     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
    771     Handle<JSObject> object = factory->NewJSObject(function);
    772     AddProperties(object, names, arraysize(names), values, arraysize(values),
    773                   rand_gen.NextInt());
    774     JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test");
    775 
    776     JSObject::AddProperty(object, deleted_property_name, object, NONE);
    777     CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY)
    778               .FromJust());
    779 
    780     CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type());
    781     CHECK(object->map()->is_dictionary_map());
    782     objects.push_back(object);
    783   }
    784 
    785   {
    786     // Global object.
    787     Handle<JSGlobalObject> object = isolate->global_object();
    788     AddProperties(object, names, arraysize(names), values, arraysize(values),
    789                   rand_gen.NextInt());
    790 
    791     JSObject::AddProperty(object, deleted_property_name, object, NONE);
    792     CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY)
    793               .FromJust());
    794 
    795     CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type());
    796     CHECK(object->map()->is_dictionary_map());
    797     objects.push_back(object);
    798   }
    799 
    800   // TODO(ishell): test proxy and interceptors when they are supported.
    801 
    802   {
    803     for (Handle<JSObject> object : objects) {
    804       for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
    805         Handle<Name> name = names[name_index];
    806         Handle<Object> expected_value =
    807             JSReceiver::GetProperty(object, name).ToHandleChecked();
    808         Handle<Object> value = ft.Call(object, name).ToHandleChecked();
    809         CHECK(expected_value->SameValue(*value));
    810       }
    811     }
    812   }
    813 
    814   {
    815     Handle<Name> non_existing_names[] = {
    816         factory->NewSymbol(),
    817         factory->InternalizeUtf8String("ne_a"),
    818         factory->InternalizeUtf8String("ne_bb"),
    819         factory->NewPrivateSymbol(),
    820         factory->InternalizeUtf8String("ne_ccc"),
    821         factory->InternalizeUtf8String("ne_dddd"),
    822         deleted_property_name,
    823     };
    824     for (Handle<JSObject> object : objects) {
    825       for (size_t key_index = 0; key_index < arraysize(non_existing_names);
    826            key_index++) {
    827         Handle<Name> name = non_existing_names[key_index];
    828         Handle<Object> expected_value =
    829             JSReceiver::GetProperty(object, name).ToHandleChecked();
    830         CHECK(expected_value->IsUndefined(isolate));
    831         Handle<Object> value = ft.Call(object, name).ToHandleChecked();
    832         CHECK_EQ(*not_found_symbol, *value);
    833       }
    834     }
    835   }
    836 
    837   {
    838     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
    839     Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]);
    840     CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type());
    841     Handle<Object> value = ft.Call(object, names[0]).ToHandleChecked();
    842     // Proxies are not supported yet.
    843     CHECK_EQ(*bailout_symbol, *value);
    844   }
    845 
    846   {
    847     Handle<JSObject> object = isolate->global_proxy();
    848     CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type());
    849     // Global proxies are not supported yet.
    850     Handle<Object> value = ft.Call(object, names[0]).ToHandleChecked();
    851     CHECK_EQ(*bailout_symbol, *value);
    852   }
    853 }
    854 
    855 namespace {
    856 
    857 void AddElement(Handle<JSObject> object, uint32_t index, Handle<Object> value,
    858                 PropertyAttributes attributes = NONE) {
    859   JSObject::AddDataElement(object, index, value, attributes).ToHandleChecked();
    860 }
    861 
    862 }  // namespace
    863 
    864 TEST(TryLookupElement) {
    865   typedef CodeStubAssembler::Label Label;
    866   Isolate* isolate(CcTest::InitIsolateOnce());
    867 
    868   const int kNumParams = 3;
    869   CodeStubAssemblerTester m(isolate, kNumParams);
    870 
    871   enum Result { kFound, kNotFound, kBailout };
    872   {
    873     Node* object = m.Parameter(0);
    874     Node* index = m.SmiToWord32(m.Parameter(1));
    875     Node* expected_result = m.Parameter(2);
    876 
    877     Label passed(&m), failed(&m);
    878     Label if_found(&m), if_not_found(&m), if_bailout(&m);
    879 
    880     Node* map = m.LoadMap(object);
    881     Node* instance_type = m.LoadMapInstanceType(map);
    882 
    883     m.TryLookupElement(object, map, instance_type, index, &if_found,
    884                        &if_not_found, &if_bailout);
    885 
    886     m.Bind(&if_found);
    887     m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
    888              &passed, &failed);
    889 
    890     m.Bind(&if_not_found);
    891     m.Branch(
    892         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
    893         &passed, &failed);
    894 
    895     m.Bind(&if_bailout);
    896     m.Branch(
    897         m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
    898         &passed, &failed);
    899 
    900     m.Bind(&passed);
    901     m.Return(m.BooleanConstant(true));
    902 
    903     m.Bind(&failed);
    904     m.Return(m.BooleanConstant(false));
    905   }
    906 
    907   Handle<Code> code = m.GenerateCode();
    908   FunctionTester ft(code, kNumParams);
    909 
    910   Factory* factory = isolate->factory();
    911   Handle<Object> smi0(Smi::FromInt(0), isolate);
    912   Handle<Object> smi1(Smi::FromInt(1), isolate);
    913   Handle<Object> smi7(Smi::FromInt(7), isolate);
    914   Handle<Object> smi13(Smi::FromInt(13), isolate);
    915   Handle<Object> smi42(Smi::FromInt(42), isolate);
    916 
    917   Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
    918   Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
    919   Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
    920 
    921 #define CHECK_FOUND(object, index)                         \
    922   CHECK(JSReceiver::HasElement(object, index).FromJust()); \
    923   ft.CheckTrue(object, smi##index, expect_found);
    924 
    925 #define CHECK_NOT_FOUND(object, index)                      \
    926   CHECK(!JSReceiver::HasElement(object, index).FromJust()); \
    927   ft.CheckTrue(object, smi##index, expect_not_found);
    928 
    929   {
    930     Handle<JSArray> object = factory->NewJSArray(0, FAST_SMI_ELEMENTS);
    931     AddElement(object, 0, smi0);
    932     AddElement(object, 1, smi0);
    933     CHECK_EQ(FAST_SMI_ELEMENTS, object->map()->elements_kind());
    934 
    935     CHECK_FOUND(object, 0);
    936     CHECK_FOUND(object, 1);
    937     CHECK_NOT_FOUND(object, 7);
    938     CHECK_NOT_FOUND(object, 13);
    939     CHECK_NOT_FOUND(object, 42);
    940   }
    941 
    942   {
    943     Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
    944     AddElement(object, 0, smi0);
    945     AddElement(object, 13, smi0);
    946     CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, object->map()->elements_kind());
    947 
    948     CHECK_FOUND(object, 0);
    949     CHECK_NOT_FOUND(object, 1);
    950     CHECK_NOT_FOUND(object, 7);
    951     CHECK_FOUND(object, 13);
    952     CHECK_NOT_FOUND(object, 42);
    953   }
    954 
    955   {
    956     Handle<JSArray> object = factory->NewJSArray(0, FAST_ELEMENTS);
    957     AddElement(object, 0, smi0);
    958     AddElement(object, 1, smi0);
    959     CHECK_EQ(FAST_ELEMENTS, object->map()->elements_kind());
    960 
    961     CHECK_FOUND(object, 0);
    962     CHECK_FOUND(object, 1);
    963     CHECK_NOT_FOUND(object, 7);
    964     CHECK_NOT_FOUND(object, 13);
    965     CHECK_NOT_FOUND(object, 42);
    966   }
    967 
    968   {
    969     Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_ELEMENTS);
    970     AddElement(object, 0, smi0);
    971     AddElement(object, 13, smi0);
    972     CHECK_EQ(FAST_HOLEY_ELEMENTS, object->map()->elements_kind());
    973 
    974     CHECK_FOUND(object, 0);
    975     CHECK_NOT_FOUND(object, 1);
    976     CHECK_NOT_FOUND(object, 7);
    977     CHECK_FOUND(object, 13);
    978     CHECK_NOT_FOUND(object, 42);
    979   }
    980 
    981   {
    982     Handle<JSFunction> constructor = isolate->string_function();
    983     Handle<JSObject> object = factory->NewJSObject(constructor);
    984     Handle<String> str = factory->InternalizeUtf8String("ab");
    985     Handle<JSValue>::cast(object)->set_value(*str);
    986     AddElement(object, 13, smi0);
    987     CHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind());
    988 
    989     CHECK_FOUND(object, 0);
    990     CHECK_FOUND(object, 1);
    991     CHECK_NOT_FOUND(object, 7);
    992     CHECK_FOUND(object, 13);
    993     CHECK_NOT_FOUND(object, 42);
    994   }
    995 
    996   {
    997     Handle<JSFunction> constructor = isolate->string_function();
    998     Handle<JSObject> object = factory->NewJSObject(constructor);
    999     Handle<String> str = factory->InternalizeUtf8String("ab");
   1000     Handle<JSValue>::cast(object)->set_value(*str);
   1001     AddElement(object, 13, smi0);
   1002     JSObject::NormalizeElements(object);
   1003     CHECK_EQ(SLOW_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind());
   1004 
   1005     CHECK_FOUND(object, 0);
   1006     CHECK_FOUND(object, 1);
   1007     CHECK_NOT_FOUND(object, 7);
   1008     CHECK_FOUND(object, 13);
   1009     CHECK_NOT_FOUND(object, 42);
   1010   }
   1011 
   1012 // TODO(ishell): uncomment once NO_ELEMENTS kind is supported.
   1013 //  {
   1014 //    Handle<Map> map = Map::Create(isolate, 0);
   1015 //    map->set_elements_kind(NO_ELEMENTS);
   1016 //    Handle<JSObject> object = factory->NewJSObjectFromMap(map);
   1017 //    CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind());
   1018 //
   1019 //    CHECK_NOT_FOUND(object, 0);
   1020 //    CHECK_NOT_FOUND(object, 1);
   1021 //    CHECK_NOT_FOUND(object, 7);
   1022 //    CHECK_NOT_FOUND(object, 13);
   1023 //    CHECK_NOT_FOUND(object, 42);
   1024 //  }
   1025 
   1026 #undef CHECK_FOUND
   1027 #undef CHECK_NOT_FOUND
   1028 
   1029   {
   1030     Handle<JSArray> handler = factory->NewJSArray(0);
   1031     Handle<JSFunction> function = factory->NewFunction(factory->empty_string());
   1032     Handle<JSProxy> object = factory->NewJSProxy(function, handler);
   1033     CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type());
   1034     ft.CheckTrue(object, smi0, expect_bailout);
   1035   }
   1036 
   1037   {
   1038     Handle<JSObject> object = isolate->global_object();
   1039     CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type());
   1040     ft.CheckTrue(object, smi0, expect_bailout);
   1041   }
   1042 
   1043   {
   1044     Handle<JSObject> object = isolate->global_proxy();
   1045     CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type());
   1046     ft.CheckTrue(object, smi0, expect_bailout);
   1047   }
   1048 }
   1049 
   1050 TEST(DeferredCodePhiHints) {
   1051   typedef compiler::Node Node;
   1052   typedef CodeStubAssembler::Label Label;
   1053   typedef CodeStubAssembler::Variable Variable;
   1054   Isolate* isolate(CcTest::InitIsolateOnce());
   1055   VoidDescriptor descriptor(isolate);
   1056   CodeStubAssemblerTester m(isolate, descriptor);
   1057   Label block1(&m, Label::kDeferred);
   1058   m.Goto(&block1);
   1059   m.Bind(&block1);
   1060   {
   1061     Variable var_object(&m, MachineRepresentation::kTagged);
   1062     Label loop(&m, &var_object);
   1063     var_object.Bind(m.IntPtrConstant(0));
   1064     m.Goto(&loop);
   1065     m.Bind(&loop);
   1066     {
   1067       Node* map = m.LoadMap(var_object.value());
   1068       var_object.Bind(map);
   1069       m.Goto(&loop);
   1070     }
   1071   }
   1072   CHECK(!m.GenerateCode().is_null());
   1073 }
   1074 
   1075 TEST(TestOutOfScopeVariable) {
   1076   typedef CodeStubAssembler::Label Label;
   1077   typedef CodeStubAssembler::Variable Variable;
   1078   Isolate* isolate(CcTest::InitIsolateOnce());
   1079   VoidDescriptor descriptor(isolate);
   1080   CodeStubAssemblerTester m(isolate, descriptor);
   1081   Label block1(&m);
   1082   Label block2(&m);
   1083   Label block3(&m);
   1084   Label block4(&m);
   1085   m.Branch(m.WordEqual(m.Parameter(0), m.IntPtrConstant(0)), &block1, &block4);
   1086   m.Bind(&block4);
   1087   {
   1088     Variable var_object(&m, MachineRepresentation::kTagged);
   1089     m.Branch(m.WordEqual(m.Parameter(0), m.IntPtrConstant(0)), &block2,
   1090              &block3);
   1091 
   1092     m.Bind(&block2);
   1093     var_object.Bind(m.IntPtrConstant(55));
   1094     m.Goto(&block1);
   1095 
   1096     m.Bind(&block3);
   1097     var_object.Bind(m.IntPtrConstant(66));
   1098     m.Goto(&block1);
   1099   }
   1100   m.Bind(&block1);
   1101   CHECK(!m.GenerateCode().is_null());
   1102 }
   1103 
   1104 namespace {
   1105 
   1106 void TestStubCacheOffsetCalculation(StubCache::Table table,
   1107                                     Code::Kind handler_kind) {
   1108   Isolate* isolate(CcTest::InitIsolateOnce());
   1109   const int kNumParams = 2;
   1110   CodeStubAssemblerTester m(isolate, kNumParams);
   1111 
   1112   Code::Flags code_flags =
   1113       Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(handler_kind));
   1114   {
   1115     Node* name = m.Parameter(0);
   1116     Node* map = m.Parameter(1);
   1117     Node* primary_offset = m.StubCachePrimaryOffset(name, code_flags, map);
   1118     Node* result;
   1119     if (table == StubCache::kPrimary) {
   1120       result = primary_offset;
   1121     } else {
   1122       CHECK_EQ(StubCache::kSecondary, table);
   1123       result = m.StubCacheSecondaryOffset(name, code_flags, primary_offset);
   1124     }
   1125     m.Return(m.SmiFromWord32(result));
   1126   }
   1127 
   1128   Handle<Code> code = m.GenerateCode();
   1129   FunctionTester ft(code, kNumParams);
   1130 
   1131   Factory* factory = isolate->factory();
   1132   Handle<Name> names[] = {
   1133       factory->NewSymbol(),
   1134       factory->InternalizeUtf8String("a"),
   1135       factory->InternalizeUtf8String("bb"),
   1136       factory->InternalizeUtf8String("ccc"),
   1137       factory->NewPrivateSymbol(),
   1138       factory->InternalizeUtf8String("dddd"),
   1139       factory->InternalizeUtf8String("eeeee"),
   1140       factory->InternalizeUtf8String("name"),
   1141       factory->NewSymbol(),
   1142       factory->NewPrivateSymbol(),
   1143   };
   1144 
   1145   Handle<Map> maps[] = {
   1146       Handle<Map>(nullptr, isolate),
   1147       factory->cell_map(),
   1148       Map::Create(isolate, 0),
   1149       factory->meta_map(),
   1150       factory->code_map(),
   1151       Map::Create(isolate, 0),
   1152       factory->hash_table_map(),
   1153       factory->symbol_map(),
   1154       factory->string_map(),
   1155       Map::Create(isolate, 0),
   1156       factory->sloppy_arguments_elements_map(),
   1157   };
   1158 
   1159   for (int name_index = 0; name_index < arraysize(names); name_index++) {
   1160     Handle<Name> name = names[name_index];
   1161     for (int map_index = 0; map_index < arraysize(maps); map_index++) {
   1162       Handle<Map> map = maps[map_index];
   1163 
   1164       int expected_result;
   1165       {
   1166         int primary_offset =
   1167             StubCache::PrimaryOffsetForTesting(*name, code_flags, *map);
   1168         if (table == StubCache::kPrimary) {
   1169           expected_result = primary_offset;
   1170         } else {
   1171           expected_result = StubCache::SecondaryOffsetForTesting(
   1172               *name, code_flags, primary_offset);
   1173         }
   1174       }
   1175       Handle<Object> result = ft.Call(name, map).ToHandleChecked();
   1176 
   1177       Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue);
   1178       CHECK_EQ(expected, Smi::cast(*result));
   1179     }
   1180   }
   1181 }
   1182 
   1183 }  // namespace
   1184 
   1185 TEST(StubCachePrimaryOffsetLoadIC) {
   1186   TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::LOAD_IC);
   1187 }
   1188 
   1189 TEST(StubCachePrimaryOffsetStoreIC) {
   1190   TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::STORE_IC);
   1191 }
   1192 
   1193 TEST(StubCacheSecondaryOffsetLoadIC) {
   1194   TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::LOAD_IC);
   1195 }
   1196 
   1197 TEST(StubCacheSecondaryOffsetStoreIC) {
   1198   TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::STORE_IC);
   1199 }
   1200 
   1201 namespace {
   1202 
   1203 Handle<Code> CreateCodeWithFlags(Code::Flags flags) {
   1204   Isolate* isolate(CcTest::InitIsolateOnce());
   1205   CodeStubAssemblerTester m(isolate, flags);
   1206   m.Return(m.UndefinedConstant());
   1207   return m.GenerateCodeCloseAndEscape();
   1208 }
   1209 
   1210 }  // namespace
   1211 
   1212 TEST(TryProbeStubCache) {
   1213   typedef CodeStubAssembler::Label Label;
   1214   typedef CodeStubAssembler::Variable Variable;
   1215   Isolate* isolate(CcTest::InitIsolateOnce());
   1216   const int kNumParams = 3;
   1217   CodeStubAssemblerTester m(isolate, kNumParams);
   1218 
   1219   Code::Flags flags_to_query =
   1220       Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC));
   1221 
   1222   StubCache stub_cache(isolate);
   1223   stub_cache.Clear();
   1224 
   1225   {
   1226     Node* receiver = m.Parameter(0);
   1227     Node* name = m.Parameter(1);
   1228     Node* expected_handler = m.Parameter(2);
   1229 
   1230     Label passed(&m), failed(&m);
   1231 
   1232     Variable var_handler(&m, MachineRepresentation::kTagged);
   1233     Label if_handler(&m), if_miss(&m);
   1234 
   1235     m.TryProbeStubCache(&stub_cache, flags_to_query, receiver, name,
   1236                         &if_handler, &var_handler, &if_miss);
   1237     m.Bind(&if_handler);
   1238     m.BranchIfWordEqual(expected_handler, var_handler.value(), &passed,
   1239                         &failed);
   1240 
   1241     m.Bind(&if_miss);
   1242     m.BranchIfWordEqual(expected_handler, m.IntPtrConstant(0), &passed,
   1243                         &failed);
   1244 
   1245     m.Bind(&passed);
   1246     m.Return(m.BooleanConstant(true));
   1247 
   1248     m.Bind(&failed);
   1249     m.Return(m.BooleanConstant(false));
   1250   }
   1251 
   1252   Handle<Code> code = m.GenerateCode();
   1253   FunctionTester ft(code, kNumParams);
   1254 
   1255   std::vector<Handle<Name>> names;
   1256   std::vector<Handle<JSObject>> receivers;
   1257   std::vector<Handle<Code>> handlers;
   1258 
   1259   base::RandomNumberGenerator rand_gen(FLAG_random_seed);
   1260 
   1261   Factory* factory = isolate->factory();
   1262 
   1263   // Generate some number of names.
   1264   for (int i = 0; i < StubCache::kPrimaryTableSize / 7; i++) {
   1265     Handle<Name> name;
   1266     switch (rand_gen.NextInt(3)) {
   1267       case 0: {
   1268         // Generate string.
   1269         std::stringstream ss;
   1270         ss << "s" << std::hex
   1271            << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
   1272         name = factory->InternalizeUtf8String(ss.str().c_str());
   1273         break;
   1274       }
   1275       case 1: {
   1276         // Generate number string.
   1277         std::stringstream ss;
   1278         ss << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
   1279         name = factory->InternalizeUtf8String(ss.str().c_str());
   1280         break;
   1281       }
   1282       case 2: {
   1283         // Generate symbol.
   1284         name = factory->NewSymbol();
   1285         break;
   1286       }
   1287       default:
   1288         UNREACHABLE();
   1289     }
   1290     names.push_back(name);
   1291   }
   1292 
   1293   // Generate some number of receiver maps and receivers.
   1294   for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) {
   1295     Handle<Map> map = Map::Create(isolate, 0);
   1296     receivers.push_back(factory->NewJSObjectFromMap(map));
   1297   }
   1298 
   1299   // Generate some number of handlers.
   1300   for (int i = 0; i < 30; i++) {
   1301     Code::Kind code_kind;
   1302     switch (rand_gen.NextInt(4)) {
   1303       case 0:
   1304         code_kind = Code::LOAD_IC;
   1305         break;
   1306       case 1:
   1307         code_kind = Code::KEYED_LOAD_IC;
   1308         break;
   1309       case 2:
   1310         code_kind = Code::STORE_IC;
   1311         break;
   1312       case 3:
   1313         code_kind = Code::KEYED_STORE_IC;
   1314         break;
   1315       default:
   1316         UNREACHABLE();
   1317     }
   1318     Code::Flags flags =
   1319         Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(code_kind));
   1320     handlers.push_back(CreateCodeWithFlags(flags));
   1321   }
   1322 
   1323   // Ensure that GC does happen because from now on we are going to fill our
   1324   // own stub cache instance with raw values.
   1325   DisallowHeapAllocation no_gc;
   1326 
   1327   // Populate {stub_cache}.
   1328   const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize;
   1329   for (int i = 0; i < N; i++) {
   1330     int index = rand_gen.NextInt();
   1331     Handle<Name> name = names[index % names.size()];
   1332     Handle<JSObject> receiver = receivers[index % receivers.size()];
   1333     Handle<Code> handler = handlers[index % handlers.size()];
   1334     stub_cache.Set(*name, receiver->map(), *handler);
   1335   }
   1336 
   1337   // Perform some queries.
   1338   bool queried_existing = false;
   1339   bool queried_non_existing = false;
   1340   for (int i = 0; i < N; i++) {
   1341     int index = rand_gen.NextInt();
   1342     Handle<Name> name = names[index % names.size()];
   1343     Handle<JSObject> receiver = receivers[index % receivers.size()];
   1344     Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query);
   1345     if (handler == nullptr) {
   1346       queried_non_existing = true;
   1347     } else {
   1348       queried_existing = true;
   1349     }
   1350 
   1351     Handle<Code> expected_handler(handler, isolate);
   1352     ft.CheckTrue(receiver, name, expected_handler);
   1353   }
   1354 
   1355   for (int i = 0; i < N; i++) {
   1356     int index1 = rand_gen.NextInt();
   1357     int index2 = rand_gen.NextInt();
   1358     Handle<Name> name = names[index1 % names.size()];
   1359     Handle<JSObject> receiver = receivers[index2 % receivers.size()];
   1360     Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query);
   1361     if (handler == nullptr) {
   1362       queried_non_existing = true;
   1363     } else {
   1364       queried_existing = true;
   1365     }
   1366 
   1367     Handle<Code> expected_handler(handler, isolate);
   1368     ft.CheckTrue(receiver, name, expected_handler);
   1369   }
   1370   // Ensure we performed both kind of queries.
   1371   CHECK(queried_existing && queried_non_existing);
   1372 }
   1373 
   1374 }  // namespace internal
   1375 }  // namespace v8
   1376