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/ic/ic-compiler.h"
      6 
      7 #include "src/ic/handler-compiler.h"
      8 #include "src/ic/ic-inl.h"
      9 #include "src/profiler/cpu-profiler.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::IncludesNumberMap(MapHandleList* maps) {
     29   for (int i = 0; i < maps->length(); ++i) {
     30     if (maps->at(i)->instance_type() == HEAP_NUMBER_TYPE) return true;
     31   }
     32   return false;
     33 }
     34 
     35 
     36 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
     37     Handle<Map> receiver_map, ExtraICState extra_ic_state) {
     38   Isolate* isolate = receiver_map->GetIsolate();
     39   bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
     40   ElementsKind elements_kind = receiver_map->elements_kind();
     41 
     42   // No need to check for an elements-free prototype chain here, the generated
     43   // stub code needs to check that dynamically anyway.
     44   bool convert_hole_to_undefined =
     45       is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
     46       *receiver_map == isolate->get_initial_js_array_map(elements_kind) &&
     47       !(is_strong(LoadICState::GetLanguageMode(extra_ic_state)));
     48   Handle<Code> stub;
     49   if (receiver_map->has_indexed_interceptor()) {
     50     stub = LoadIndexedInterceptorStub(isolate).GetCode();
     51   } else if (receiver_map->IsStringMap()) {
     52     // We have a string.
     53     stub = LoadIndexedStringStub(isolate).GetCode();
     54   } else if (receiver_map->has_sloppy_arguments_elements()) {
     55     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
     56   } else if (receiver_map->has_fast_elements() ||
     57              receiver_map->has_fixed_typed_array_elements()) {
     58     stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
     59                                convert_hole_to_undefined).GetCode();
     60   } else {
     61     stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state))
     62                .GetCode();
     63   }
     64   return stub;
     65 }
     66 
     67 
     68 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
     69     Handle<Map> receiver_map, LanguageMode language_mode,
     70     KeyedAccessStoreMode store_mode) {
     71   Isolate* isolate = receiver_map->GetIsolate();
     72   ExtraICState extra_state =
     73       KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
     74 
     75   DCHECK(store_mode == STANDARD_STORE ||
     76          store_mode == STORE_AND_GROW_NO_TRANSITION ||
     77          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
     78          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
     79 
     80   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
     81   Handle<Code> code =
     82       compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
     83   return code;
     84 }
     85 
     86 
     87 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
     88                                              ExtraICState state) {
     89   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
     90   UnseededNumberDictionary* dictionary =
     91       isolate->heap()->non_monomorphic_cache();
     92   int entry = dictionary->FindEntry(isolate, flags);
     93   DCHECK(entry != -1);
     94   Object* code = dictionary->ValueAt(entry);
     95   // This might be called during the marking phase of the collector
     96   // hence the unchecked cast.
     97   return reinterpret_cast<Code*>(code);
     98 }
     99 
    100 
    101 static void FillCache(Isolate* isolate, Handle<Code> code) {
    102   Handle<UnseededNumberDictionary> dictionary = UnseededNumberDictionary::Set(
    103       isolate->factory()->non_monomorphic_cache(), code->flags(), code);
    104   isolate->heap()->SetRootNonMonomorphicCache(*dictionary);
    105 }
    106 
    107 
    108 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
    109                                               InlineCacheState ic_state,
    110                                               ExtraICState extra_state) {
    111   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
    112   Handle<UnseededNumberDictionary> cache =
    113       isolate->factory()->non_monomorphic_cache();
    114   int entry = cache->FindEntry(isolate, flags);
    115   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    116 
    117   PropertyICCompiler compiler(isolate, Code::STORE_IC);
    118   Handle<Code> code;
    119   if (ic_state == UNINITIALIZED) {
    120     code = compiler.CompileStoreInitialize(flags);
    121   } else if (ic_state == PREMONOMORPHIC) {
    122     code = compiler.CompileStorePreMonomorphic(flags);
    123   } else if (ic_state == GENERIC) {
    124     code = compiler.CompileStoreGeneric(flags);
    125   } else if (ic_state == MEGAMORPHIC) {
    126     code = compiler.CompileStoreMegamorphic(flags);
    127   } else {
    128     UNREACHABLE();
    129   }
    130 
    131   FillCache(isolate, code);
    132   return code;
    133 }
    134 
    135 
    136 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
    137                                                    CompareNilICStub* stub) {
    138   Isolate* isolate = receiver_map->GetIsolate();
    139   Handle<String> name(isolate->heap()->empty_string());
    140   if (!receiver_map->is_dictionary_map()) {
    141     Handle<Code> cached_ic =
    142         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
    143     if (!cached_ic.is_null()) return cached_ic;
    144   }
    145 
    146   Code::FindAndReplacePattern pattern;
    147   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
    148   pattern.Add(isolate->factory()->meta_map(), cell);
    149   Handle<Code> ic = stub->GetCodeCopy(pattern);
    150 
    151   if (!receiver_map->is_dictionary_map()) {
    152     Map::UpdateCodeCache(receiver_map, name, ic);
    153   }
    154 
    155   return ic;
    156 }
    157 
    158 
    159 void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
    160     MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
    161     CodeHandleList* handlers, KeyedAccessStoreMode store_mode,
    162     LanguageMode language_mode) {
    163   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
    164   DCHECK(store_mode == STANDARD_STORE ||
    165          store_mode == STORE_AND_GROW_NO_TRANSITION ||
    166          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
    167          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
    168   ExtraICState extra_state =
    169       KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
    170   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
    171   compiler.CompileKeyedStorePolymorphicHandlers(
    172       receiver_maps, transitioned_maps, handlers, store_mode);
    173 }
    174 
    175 
    176 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
    177   LoadIC::GenerateInitialize(masm());
    178   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
    179   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
    180   return code;
    181 }
    182 
    183 
    184 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
    185   StoreIC::GenerateInitialize(masm());
    186   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
    187   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
    188   return code;
    189 }
    190 
    191 
    192 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
    193   StoreIC::GeneratePreMonomorphic(masm());
    194   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
    195   PROFILE(isolate(),
    196           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
    197   return code;
    198 }
    199 
    200 
    201 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
    202   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
    203   LanguageMode language_mode = StoreICState::GetLanguageMode(extra_state);
    204   GenerateRuntimeSetProperty(masm(), language_mode);
    205   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
    206   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
    207   return code;
    208 }
    209 
    210 
    211 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
    212   StoreIC::GenerateMegamorphic(masm());
    213   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
    214   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
    215   return code;
    216 }
    217 
    218 
    219 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
    220                                          Handle<Name> name,
    221                                          InlineCacheState state) {
    222   Code::Flags flags =
    223       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
    224   Handle<Code> code = GetCodeWithFlags(flags, name);
    225   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
    226 #ifdef DEBUG
    227   code->VerifyEmbeddedObjects();
    228 #endif
    229   return code;
    230 }
    231 
    232 
    233 void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
    234     MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
    235     CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
    236   for (int i = 0; i < receiver_maps->length(); ++i) {
    237     Handle<Map> receiver_map(receiver_maps->at(i));
    238     Handle<Code> cached_stub;
    239     Handle<Map> transitioned_map =
    240         Map::FindTransitionedMap(receiver_map, receiver_maps);
    241 
    242     // TODO(mvstanton): The code below is doing pessimistic elements
    243     // transitions. I would like to stop doing that and rely on Allocation Site
    244     // Tracking to do a better job of ensuring the data types are what they need
    245     // to be. Not all the elements are in place yet, pessimistic elements
    246     // transitions are still important for performance.
    247     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
    248     ElementsKind elements_kind = receiver_map->elements_kind();
    249     if (!transitioned_map.is_null()) {
    250       cached_stub =
    251           ElementsTransitionAndStoreStub(isolate(), elements_kind,
    252                                          transitioned_map->elements_kind(),
    253                                          is_js_array, store_mode).GetCode();
    254     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
    255       // TODO(mvstanton): Consider embedding store_mode in the state of the slow
    256       // keyed store ic for uniformity.
    257       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
    258     } else {
    259       if (IsSloppyArgumentsElements(elements_kind)) {
    260         cached_stub =
    261             KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
    262       } else if (receiver_map->has_fast_elements() ||
    263                  receiver_map->has_fixed_typed_array_elements()) {
    264         cached_stub = StoreFastElementStub(isolate(), is_js_array,
    265                                            elements_kind, store_mode).GetCode();
    266       } else {
    267         cached_stub =
    268             StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
    269       }
    270     }
    271     DCHECK(!cached_stub.is_null());
    272     handlers->Add(cached_stub);
    273     transitioned_maps->Add(transitioned_map);
    274   }
    275 }
    276 
    277 
    278 #define __ ACCESS_MASM(masm())
    279 
    280 
    281 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
    282     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
    283   ElementsKind elements_kind = receiver_map->elements_kind();
    284   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
    285   Handle<Code> stub;
    286   if (receiver_map->has_sloppy_arguments_elements()) {
    287     stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
    288   } else if (receiver_map->has_fast_elements() ||
    289              receiver_map->has_fixed_typed_array_elements()) {
    290     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
    291                                 store_mode).GetCode();
    292   } else {
    293     stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
    294   }
    295   return stub;
    296 }
    297 
    298 
    299 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
    300     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
    301   Handle<Code> stub =
    302       CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
    303 
    304   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
    305 
    306   __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
    307                      DO_SMI_CHECK);
    308 
    309   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
    310 
    311   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
    312 }
    313 
    314 
    315 #undef __
    316 }  // namespace internal
    317 }  // namespace v8
    318