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