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
address()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
constant_pool()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
raw_constant_pool()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
GetTargetAtAddress(Address address,ConstantPoolArray * constant_pool)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
SetTargetAtAddress(Address address,Code * target,ConstantPoolArray * constant_pool)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
set_target(Code * code)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
set_target(Code * code)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
set_target(Code * code)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
set_target(Code * code)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
raw_target()154 Code* IC::raw_target() const {
155 return GetTargetAtAddress(address(), constant_pool());
156 }
157
UpdateTarget()158 void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
159
160
161 template <class TypeClass>
GetRootConstructor(TypeClass * type,Context * native_context)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
GetHandlerCacheHolder(HeapType * type,bool receiver_is_holder,Isolate * isolate,CacheHolderFlag * flag)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
GetICCacheHolder(HeapType * type,Isolate * isolate,CacheHolderFlag * flag)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
FeedbackToState(Handle<TypeFeedbackVector> vector,Handle<Smi> slot)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