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