Home | History | Annotate | Download | only in ic
      1 // Copyright 2012 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 #ifndef V8_IC_INL_H_
      6 #define V8_IC_INL_H_
      7 
      8 #include "src/ic/ic.h"
      9 
     10 #include "src/compiler.h"
     11 #include "src/debug.h"
     12 #include "src/macro-assembler.h"
     13 #include "src/prototype.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 
     19 Address IC::address() const {
     20   // Get the address of the call.
     21   Address result = Assembler::target_address_from_return_address(pc());
     22 
     23   Debug* debug = isolate()->debug();
     24   // First check if any break points are active if not just return the address
     25   // of the call.
     26   if (!debug->has_break_points()) return result;
     27 
     28   // At least one break point is active perform additional test to ensure that
     29   // break point locations are updated correctly.
     30   if (debug->IsDebugBreak(
     31           Assembler::target_address_at(result, raw_constant_pool()))) {
     32     // If the call site is a call to debug break then return the address in
     33     // the original code instead of the address in the running code. This will
     34     // cause the original code to be updated and keeps the breakpoint active in
     35     // the running code.
     36     Code* code = GetCode();
     37     Code* original_code = GetOriginalCode();
     38     intptr_t delta =
     39         original_code->instruction_start() - code->instruction_start();
     40     // Return the address in the original code. This is the place where
     41     // the call which has been overwritten by the DebugBreakXXX resides
     42     // and the place where the inline cache system should look.
     43     return result + delta;
     44   } else {
     45     // No break point here just return the address of the call.
     46     return result;
     47   }
     48 }
     49 
     50 
     51 ConstantPoolArray* IC::constant_pool() const {
     52   if (!FLAG_enable_ool_constant_pool) {
     53     return NULL;
     54   } else {
     55     Handle<ConstantPoolArray> result = raw_constant_pool_;
     56     Debug* debug = isolate()->debug();
     57     // First check if any break points are active if not just return the
     58     // original constant pool.
     59     if (!debug->has_break_points()) return *result;
     60 
     61     // At least one break point is active perform additional test to ensure that
     62     // break point locations are updated correctly.
     63     Address target = Assembler::target_address_from_return_address(pc());
     64     if (debug->IsDebugBreak(
     65             Assembler::target_address_at(target, raw_constant_pool()))) {
     66       // If the call site is a call to debug break then we want to return the
     67       // constant pool for the original code instead of the breakpointed code.
     68       return GetOriginalCode()->constant_pool();
     69     }
     70     return *result;
     71   }
     72 }
     73 
     74 
     75 ConstantPoolArray* IC::raw_constant_pool() const {
     76   if (FLAG_enable_ool_constant_pool) {
     77     return *raw_constant_pool_;
     78   } else {
     79     return NULL;
     80   }
     81 }
     82 
     83 
     84 Code* IC::GetTargetAtAddress(Address address,
     85                              ConstantPoolArray* constant_pool) {
     86   // Get the target address of the IC.
     87   Address target = Assembler::target_address_at(address, constant_pool);
     88   // Convert target address to the code object. Code::GetCodeFromTargetAddress
     89   // is safe for use during GC where the map might be marked.
     90   Code* result = Code::GetCodeFromTargetAddress(target);
     91   DCHECK(result->is_inline_cache_stub());
     92   return result;
     93 }
     94 
     95 
     96 void IC::SetTargetAtAddress(Address address, Code* target,
     97                             ConstantPoolArray* constant_pool) {
     98   DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub());
     99   Heap* heap = target->GetHeap();
    100   Code* old_target = GetTargetAtAddress(address, constant_pool);
    101 #ifdef DEBUG
    102   // STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark
    103   // ICs as strict mode. The strict-ness of the IC must be preserved.
    104   if (old_target->kind() == Code::STORE_IC ||
    105       old_target->kind() == Code::KEYED_STORE_IC) {
    106     DCHECK(StoreIC::GetStrictMode(old_target->extra_ic_state()) ==
    107            StoreIC::GetStrictMode(target->extra_ic_state()));
    108   }
    109 #endif
    110   Assembler::set_target_address_at(address, constant_pool,
    111                                    target->instruction_start());
    112   if (heap->gc_state() == Heap::MARK_COMPACT) {
    113     heap->mark_compact_collector()->RecordCodeTargetPatch(address, target);
    114   } else {
    115     heap->incremental_marking()->RecordCodeTargetPatch(address, target);
    116   }
    117   PostPatching(address, target, old_target);
    118 }
    119 
    120 
    121 void IC::set_target(Code* code) {
    122 #ifdef VERIFY_HEAP
    123   code->VerifyEmbeddedObjectsDependency();
    124 #endif
    125   SetTargetAtAddress(address(), code, constant_pool());
    126   target_set_ = true;
    127 }
    128 
    129 
    130 void LoadIC::set_target(Code* code) {
    131   // The contextual mode must be preserved across IC patching.
    132   DCHECK(LoadICState::GetContextualMode(code->extra_ic_state()) ==
    133          LoadICState::GetContextualMode(target()->extra_ic_state()));
    134 
    135   IC::set_target(code);
    136 }
    137 
    138 
    139 void StoreIC::set_target(Code* code) {
    140   // Strict mode must be preserved across IC patching.
    141   DCHECK(GetStrictMode(code->extra_ic_state()) ==
    142          GetStrictMode(target()->extra_ic_state()));
    143   IC::set_target(code);
    144 }
    145 
    146 
    147 void KeyedStoreIC::set_target(Code* code) {
    148   // Strict mode must be preserved across IC patching.
    149   DCHECK(GetStrictMode(code->extra_ic_state()) == strict_mode());
    150   IC::set_target(code);
    151 }
    152 
    153 
    154 Code* IC::raw_target() const {
    155   return GetTargetAtAddress(address(), constant_pool());
    156 }
    157 
    158 void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
    159 
    160 
    161 template <class TypeClass>
    162 JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) {
    163   if (type->Is(TypeClass::Boolean())) {
    164     return native_context->boolean_function();
    165   } else if (type->Is(TypeClass::Number())) {
    166     return native_context->number_function();
    167   } else if (type->Is(TypeClass::String())) {
    168     return native_context->string_function();
    169   } else if (type->Is(TypeClass::Symbol())) {
    170     return native_context->symbol_function();
    171   } else {
    172     return NULL;
    173   }
    174 }
    175 
    176 
    177 Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder,
    178                                       Isolate* isolate, CacheHolderFlag* flag) {
    179   Handle<Map> receiver_map = TypeToMap(type, isolate);
    180   if (receiver_is_holder) {
    181     *flag = kCacheOnReceiver;
    182     return receiver_map;
    183   }
    184   Context* native_context = *isolate->native_context();
    185   JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
    186   if (builtin_ctor != NULL) {
    187     *flag = kCacheOnPrototypeReceiverIsPrimitive;
    188     return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map());
    189   }
    190   *flag = receiver_map->is_dictionary_map()
    191               ? kCacheOnPrototypeReceiverIsDictionary
    192               : kCacheOnPrototype;
    193   // Callers must ensure that the prototype is non-null.
    194   return handle(JSObject::cast(receiver_map->prototype())->map());
    195 }
    196 
    197 
    198 Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
    199                                  CacheHolderFlag* flag) {
    200   Context* native_context = *isolate->native_context();
    201   JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
    202   if (builtin_ctor != NULL) {
    203     *flag = kCacheOnPrototype;
    204     return handle(builtin_ctor->initial_map());
    205   }
    206   *flag = kCacheOnReceiver;
    207   return TypeToMap(type, isolate);
    208 }
    209 
    210 
    211 IC::State CallIC::FeedbackToState(Handle<TypeFeedbackVector> vector,
    212                                   Handle<Smi> slot) const {
    213   IC::State state = UNINITIALIZED;
    214   Object* feedback = vector->get(slot->value());
    215 
    216   if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate())) {
    217     state = GENERIC;
    218   } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
    219     state = MONOMORPHIC;
    220   } else {
    221     CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
    222   }
    223 
    224   return state;
    225 }
    226 }
    227 }  // namespace v8::internal
    228 
    229 #endif  // V8_IC_INL_H_
    230