Home | History | Annotate | Download | only in ic
      1 // Copyright 2014 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/v8.h"
      6 
      7 #include "src/ic/handler-compiler.h"
      8 #include "src/ic/ic-inl.h"
      9 #include "src/ic/ic-compiler.h"
     10 
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
     17                                       Handle<Map> stub_holder, Code::Kind kind,
     18                                       ExtraICState extra_state,
     19                                       CacheHolderFlag cache_holder) {
     20   Code::Flags flags =
     21       Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder);
     22   Object* probe = stub_holder->FindInCodeCache(*name, flags);
     23   if (probe->IsCode()) return handle(Code::cast(probe));
     24   return Handle<Code>::null();
     25 }
     26 
     27 
     28 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
     29   for (int i = 0; i < types->length(); ++i) {
     30     if (types->at(i)->Is(HeapType::Number())) return true;
     31   }
     32   return false;
     33 }
     34 
     35 
     36 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
     37                                                     Handle<Code> handler,
     38                                                     Handle<Name> name,
     39                                                     IcCheckType check) {
     40   TypeHandleList types(1);
     41   CodeHandleList handlers(1);
     42   types.Add(type);
     43   handlers.Add(handler);
     44   Code::StubType stub_type = handler->type();
     45   return CompilePolymorphic(&types, &handlers, name, stub_type, check);
     46 }
     47 
     48 
     49 Handle<Code> PropertyICCompiler::ComputeMonomorphic(
     50     Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
     51     Handle<Code> handler, ExtraICState extra_ic_state) {
     52   Isolate* isolate = name->GetIsolate();
     53   if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
     54       handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
     55     name = isolate->factory()->normal_ic_symbol();
     56   }
     57 
     58   CacheHolderFlag flag;
     59   Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
     60 
     61   Handle<Code> ic;
     62   // There are multiple string maps that all use the same prototype. That
     63   // prototype cannot hold multiple handlers, one for each of the string maps,
     64   // for a single name. Hence, turn off caching of the IC.
     65   bool can_be_cached = !type->Is(HeapType::String());
     66   if (can_be_cached) {
     67     ic = Find(name, stub_holder, kind, extra_ic_state, flag);
     68     if (!ic.is_null()) return ic;
     69   }
     70 
     71 #ifdef DEBUG
     72   if (kind == Code::KEYED_STORE_IC) {
     73     DCHECK(STANDARD_STORE ==
     74            KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
     75   }
     76 #endif
     77 
     78   PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
     79   ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
     80 
     81   if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
     82   return ic;
     83 }
     84 
     85 
     86 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
     87     Handle<Map> receiver_map) {
     88   Isolate* isolate = receiver_map->GetIsolate();
     89   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
     90   Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
     91 
     92   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
     93   if (probe->IsCode()) return Handle<Code>::cast(probe);
     94 
     95   ElementsKind elements_kind = receiver_map->elements_kind();
     96   Handle<Code> stub;
     97   if (receiver_map->has_indexed_interceptor()) {
     98     stub = LoadIndexedInterceptorStub(isolate).GetCode();
     99   } else if (receiver_map->has_sloppy_arguments_elements()) {
    100     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
    101   } else if (receiver_map->has_fast_elements() ||
    102              receiver_map->has_external_array_elements() ||
    103              receiver_map->has_fixed_typed_array_elements()) {
    104     stub = LoadFastElementStub(isolate,
    105                                receiver_map->instance_type() == JS_ARRAY_TYPE,
    106                                elements_kind).GetCode();
    107   } else {
    108     stub = LoadDictionaryElementStub(isolate).GetCode();
    109   }
    110   PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
    111   Handle<Code> code =
    112       compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
    113                                   isolate->factory()->empty_string(), ELEMENT);
    114 
    115   Map::UpdateCodeCache(receiver_map, name, code);
    116   return code;
    117 }
    118 
    119 
    120 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
    121     Handle<Map> receiver_map, StrictMode strict_mode,
    122     KeyedAccessStoreMode store_mode) {
    123   Isolate* isolate = receiver_map->GetIsolate();
    124   ExtraICState extra_state =
    125       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
    126   Code::Flags flags =
    127       Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
    128 
    129   DCHECK(store_mode == STANDARD_STORE ||
    130          store_mode == STORE_AND_GROW_NO_TRANSITION ||
    131          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
    132          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
    133 
    134   Handle<String> name = isolate->factory()->KeyedStoreMonomorphic_string();
    135   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
    136   if (probe->IsCode()) return Handle<Code>::cast(probe);
    137 
    138   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
    139   Handle<Code> code =
    140       compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
    141 
    142   Map::UpdateCodeCache(receiver_map, name, code);
    143   DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
    144          store_mode);
    145   return code;
    146 }
    147 
    148 
    149 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
    150                                              ExtraICState state) {
    151   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
    152   UnseededNumberDictionary* dictionary =
    153       isolate->heap()->non_monomorphic_cache();
    154   int entry = dictionary->FindEntry(isolate, flags);
    155   DCHECK(entry != -1);
    156   Object* code = dictionary->ValueAt(entry);
    157   // This might be called during the marking phase of the collector
    158   // hence the unchecked cast.
    159   return reinterpret_cast<Code*>(code);
    160 }
    161 
    162 
    163 static void FillCache(Isolate* isolate, Handle<Code> code) {
    164   Handle<UnseededNumberDictionary> dictionary = UnseededNumberDictionary::Set(
    165       isolate->factory()->non_monomorphic_cache(), code->flags(), code);
    166   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
    167 }
    168 
    169 
    170 Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
    171                                              InlineCacheState ic_state,
    172                                              ExtraICState extra_state) {
    173   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
    174   Handle<UnseededNumberDictionary> cache =
    175       isolate->factory()->non_monomorphic_cache();
    176   int entry = cache->FindEntry(isolate, flags);
    177   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    178 
    179   PropertyICCompiler compiler(isolate, Code::LOAD_IC);
    180   Handle<Code> code;
    181   if (ic_state == UNINITIALIZED) {
    182     code = compiler.CompileLoadInitialize(flags);
    183   } else if (ic_state == PREMONOMORPHIC) {
    184     code = compiler.CompileLoadPreMonomorphic(flags);
    185   } else {
    186     UNREACHABLE();
    187   }
    188   FillCache(isolate, code);
    189   return code;
    190 }
    191 
    192 
    193 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
    194                                               InlineCacheState ic_state,
    195                                               ExtraICState extra_state) {
    196   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
    197   Handle<UnseededNumberDictionary> cache =
    198       isolate->factory()->non_monomorphic_cache();
    199   int entry = cache->FindEntry(isolate, flags);
    200   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    201 
    202   PropertyICCompiler compiler(isolate, Code::STORE_IC);
    203   Handle<Code> code;
    204   if (ic_state == UNINITIALIZED) {
    205     code = compiler.CompileStoreInitialize(flags);
    206   } else if (ic_state == PREMONOMORPHIC) {
    207     code = compiler.CompileStorePreMonomorphic(flags);
    208   } else if (ic_state == GENERIC) {
    209     code = compiler.CompileStoreGeneric(flags);
    210   } else if (ic_state == MEGAMORPHIC) {
    211     code = compiler.CompileStoreMegamorphic(flags);
    212   } else {
    213     UNREACHABLE();
    214   }
    215 
    216   FillCache(isolate, code);
    217   return code;
    218 }
    219 
    220 
    221 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
    222                                                    CompareNilICStub* stub) {
    223   Isolate* isolate = receiver_map->GetIsolate();
    224   Handle<String> name(isolate->heap()->empty_string());
    225   if (!receiver_map->is_dictionary_map()) {
    226     Handle<Code> cached_ic =
    227         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
    228     if (!cached_ic.is_null()) return cached_ic;
    229   }
    230 
    231   Code::FindAndReplacePattern pattern;
    232   pattern.Add(isolate->factory()->meta_map(), receiver_map);
    233   Handle<Code> ic = stub->GetCodeCopy(pattern);
    234 
    235   if (!receiver_map->is_dictionary_map()) {
    236     Map::UpdateCodeCache(receiver_map, name, ic);
    237   }
    238 
    239   return ic;
    240 }
    241 
    242 
    243 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
    244 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
    245     MapHandleList* receiver_maps) {
    246   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
    247   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
    248   Handle<PolymorphicCodeCache> cache =
    249       isolate->factory()->polymorphic_code_cache();
    250   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
    251   if (probe->IsCode()) return Handle<Code>::cast(probe);
    252 
    253   TypeHandleList types(receiver_maps->length());
    254   for (int i = 0; i < receiver_maps->length(); i++) {
    255     types.Add(HeapType::Class(receiver_maps->at(i), isolate));
    256   }
    257   CodeHandleList handlers(receiver_maps->length());
    258   ElementHandlerCompiler compiler(isolate);
    259   compiler.CompileElementHandlers(receiver_maps, &handlers);
    260   PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
    261   Handle<Code> code = ic_compiler.CompilePolymorphic(
    262       &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
    263       ELEMENT);
    264 
    265   isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
    266 
    267   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
    268   return code;
    269 }
    270 
    271 
    272 Handle<Code> PropertyICCompiler::ComputePolymorphic(
    273     Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
    274     int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
    275   Handle<Code> handler = handlers->at(0);
    276   Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
    277   DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
    278   PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
    279   return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
    280 }
    281 
    282 
    283 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
    284     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
    285     StrictMode strict_mode) {
    286   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
    287   DCHECK(store_mode == STANDARD_STORE ||
    288          store_mode == STORE_AND_GROW_NO_TRANSITION ||
    289          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
    290          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
    291   Handle<PolymorphicCodeCache> cache =
    292       isolate->factory()->polymorphic_code_cache();
    293   ExtraICState extra_state =
    294       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
    295   Code::Flags flags =
    296       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
    297   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
    298   if (probe->IsCode()) return Handle<Code>::cast(probe);
    299 
    300   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
    301   Handle<Code> code =
    302       compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
    303   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
    304   return code;
    305 }
    306 
    307 
    308 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
    309   LoadIC::GenerateInitialize(masm());
    310   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
    311   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
    312   return code;
    313 }
    314 
    315 
    316 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
    317   LoadIC::GeneratePreMonomorphic(masm());
    318   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
    319   PROFILE(isolate(),
    320           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
    321   return code;
    322 }
    323 
    324 
    325 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
    326   StoreIC::GenerateInitialize(masm());
    327   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
    328   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
    329   return code;
    330 }
    331 
    332 
    333 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
    334   StoreIC::GeneratePreMonomorphic(masm());
    335   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
    336   PROFILE(isolate(),
    337           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
    338   return code;
    339 }
    340 
    341 
    342 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
    343   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
    344   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
    345   GenerateRuntimeSetProperty(masm(), strict_mode);
    346   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
    347   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
    348   return code;
    349 }
    350 
    351 
    352 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
    353   StoreIC::GenerateMegamorphic(masm());
    354   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
    355   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
    356   return code;
    357 }
    358 
    359 
    360 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
    361                                          Handle<Name> name,
    362                                          InlineCacheState state) {
    363   Code::Flags flags =
    364       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
    365   Handle<Code> code = GetCodeWithFlags(flags, name);
    366   IC::RegisterWeakMapDependency(code);
    367   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
    368   return code;
    369 }
    370 
    371 
    372 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
    373     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
    374   // Collect MONOMORPHIC stubs for all |receiver_maps|.
    375   CodeHandleList handlers(receiver_maps->length());
    376   MapHandleList transitioned_maps(receiver_maps->length());
    377   for (int i = 0; i < receiver_maps->length(); ++i) {
    378     Handle<Map> receiver_map(receiver_maps->at(i));
    379     Handle<Code> cached_stub;
    380     Handle<Map> transitioned_map =
    381         receiver_map->FindTransitionedMap(receiver_maps);
    382 
    383     // TODO(mvstanton): The code below is doing pessimistic elements
    384     // transitions. I would like to stop doing that and rely on Allocation Site
    385     // Tracking to do a better job of ensuring the data types are what they need
    386     // to be. Not all the elements are in place yet, pessimistic elements
    387     // transitions are still important for performance.
    388     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
    389     ElementsKind elements_kind = receiver_map->elements_kind();
    390     if (!transitioned_map.is_null()) {
    391       cached_stub =
    392           ElementsTransitionAndStoreStub(isolate(), elements_kind,
    393                                          transitioned_map->elements_kind(),
    394                                          is_js_array, store_mode).GetCode();
    395     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
    396       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
    397     } else {
    398       if (receiver_map->has_fast_elements() ||
    399           receiver_map->has_external_array_elements() ||
    400           receiver_map->has_fixed_typed_array_elements()) {
    401         cached_stub = StoreFastElementStub(isolate(), is_js_array,
    402                                            elements_kind, store_mode).GetCode();
    403       } else {
    404         cached_stub = StoreElementStub(isolate(), elements_kind).GetCode();
    405       }
    406     }
    407     DCHECK(!cached_stub.is_null());
    408     handlers.Add(cached_stub);
    409     transitioned_maps.Add(transitioned_map);
    410   }
    411 
    412   Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
    413                                                    &transitioned_maps);
    414   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
    415   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
    416   return code;
    417 }
    418 
    419 
    420 #define __ ACCESS_MASM(masm())
    421 
    422 
    423 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
    424     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
    425   ElementsKind elements_kind = receiver_map->elements_kind();
    426   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
    427   Handle<Code> stub;
    428   if (receiver_map->has_fast_elements() ||
    429       receiver_map->has_external_array_elements() ||
    430       receiver_map->has_fixed_typed_array_elements()) {
    431     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
    432                                 store_mode).GetCode();
    433   } else {
    434     stub = StoreElementStub(isolate(), elements_kind).GetCode();
    435   }
    436 
    437   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
    438 
    439   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
    440 
    441   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
    442 }
    443 
    444 
    445 #undef __
    446 }
    447 }  // namespace v8::internal
    448