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
15namespace v8 {
16namespace internal {
17
18
19Address 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
51ConstantPoolArray* 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
75ConstantPoolArray* 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
84Code* 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
96void 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
121void 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
130void 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
139void 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
147void 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
154Code* IC::raw_target() const {
155  return GetTargetAtAddress(address(), constant_pool());
156}
157
158void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
159
160
161template <class TypeClass>
162JSFunction* 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
177Handle<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
198Handle<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
211IC::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