| OLD | NEW |
| (Empty) |
| 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.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(Assembler::target_address_at(result, | |
| 31 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, | |
| 97 Code* target, | |
| 98 ConstantPoolArray* constant_pool) { | |
| 99 DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub()); | |
| 100 Heap* heap = target->GetHeap(); | |
| 101 Code* old_target = GetTargetAtAddress(address, constant_pool); | |
| 102 #ifdef DEBUG | |
| 103 // STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark | |
| 104 // ICs as strict mode. The strict-ness of the IC must be preserved. | |
| 105 if (old_target->kind() == Code::STORE_IC || | |
| 106 old_target->kind() == Code::KEYED_STORE_IC) { | |
| 107 DCHECK(StoreIC::GetStrictMode(old_target->extra_ic_state()) == | |
| 108 StoreIC::GetStrictMode(target->extra_ic_state())); | |
| 109 } | |
| 110 #endif | |
| 111 Assembler::set_target_address_at( | |
| 112 address, constant_pool, target->instruction_start()); | |
| 113 if (heap->gc_state() == Heap::MARK_COMPACT) { | |
| 114 heap->mark_compact_collector()->RecordCodeTargetPatch(address, target); | |
| 115 } else { | |
| 116 heap->incremental_marking()->RecordCodeTargetPatch(address, target); | |
| 117 } | |
| 118 PostPatching(address, target, old_target); | |
| 119 } | |
| 120 | |
| 121 | |
| 122 template <class TypeClass> | |
| 123 JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) { | |
| 124 if (type->Is(TypeClass::Boolean())) { | |
| 125 return native_context->boolean_function(); | |
| 126 } else if (type->Is(TypeClass::Number())) { | |
| 127 return native_context->number_function(); | |
| 128 } else if (type->Is(TypeClass::String())) { | |
| 129 return native_context->string_function(); | |
| 130 } else if (type->Is(TypeClass::Symbol())) { | |
| 131 return native_context->symbol_function(); | |
| 132 } else { | |
| 133 return NULL; | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 | |
| 138 Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder, | |
| 139 Isolate* isolate, CacheHolderFlag* flag) { | |
| 140 Handle<Map> receiver_map = TypeToMap(type, isolate); | |
| 141 if (receiver_is_holder) { | |
| 142 *flag = kCacheOnReceiver; | |
| 143 return receiver_map; | |
| 144 } | |
| 145 Context* native_context = *isolate->native_context(); | |
| 146 JSFunction* builtin_ctor = GetRootConstructor(type, native_context); | |
| 147 if (builtin_ctor != NULL) { | |
| 148 *flag = kCacheOnPrototypeReceiverIsPrimitive; | |
| 149 return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map()); | |
| 150 } | |
| 151 *flag = receiver_map->is_dictionary_map() | |
| 152 ? kCacheOnPrototypeReceiverIsDictionary | |
| 153 : kCacheOnPrototype; | |
| 154 // Callers must ensure that the prototype is non-null. | |
| 155 return handle(JSObject::cast(receiver_map->prototype())->map()); | |
| 156 } | |
| 157 | |
| 158 | |
| 159 Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate, | |
| 160 CacheHolderFlag* flag) { | |
| 161 Context* native_context = *isolate->native_context(); | |
| 162 JSFunction* builtin_ctor = GetRootConstructor(type, native_context); | |
| 163 if (builtin_ctor != NULL) { | |
| 164 *flag = kCacheOnPrototype; | |
| 165 return handle(builtin_ctor->initial_map()); | |
| 166 } | |
| 167 *flag = kCacheOnReceiver; | |
| 168 return TypeToMap(type, isolate); | |
| 169 } | |
| 170 | |
| 171 | |
| 172 IC::State CallIC::FeedbackToState(Handle<FixedArray> vector, | |
| 173 Handle<Smi> slot) const { | |
| 174 IC::State state = UNINITIALIZED; | |
| 175 Object* feedback = vector->get(slot->value()); | |
| 176 | |
| 177 if (feedback == *TypeFeedbackInfo::MegamorphicSentinel(isolate())) { | |
| 178 state = GENERIC; | |
| 179 } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) { | |
| 180 state = MONOMORPHIC; | |
| 181 } else { | |
| 182 CHECK(feedback == *TypeFeedbackInfo::UninitializedSentinel(isolate())); | |
| 183 } | |
| 184 | |
| 185 return state; | |
| 186 } | |
| 187 } } // namespace v8::internal | |
| 188 | |
| 189 #endif // V8_IC_INL_H_ | |
| OLD | NEW |