• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
6 #define V8_IC_H_
7 
8 #include "src/ic/ic-state.h"
9 #include "src/macro-assembler.h"
10 #include "src/messages.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 //
16 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
17 //
18 class IC {
19  public:
20   // Alias the inline cache state type to make the IC code more readable.
21   typedef InlineCacheState State;
22 
23   // The IC code is either invoked with no extra frames on the stack
24   // or with a single extra frame for supporting calls.
25   enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
26 
27   // Construct the IC structure with the given number of extra
28   // JavaScript frames on the stack.
29   IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);
~IC()30   virtual ~IC() {}
31 
state()32   State state() const { return state_; }
33   inline Address address() const;
34 
35   // Compute the current IC state based on the target stub, receiver and name.
36   void UpdateState(Handle<Object> receiver, Handle<Object> name);
37 
38   bool RecomputeHandlerForName(Handle<Object> name);
MarkRecomputeHandler(Handle<Object> name)39   void MarkRecomputeHandler(Handle<Object> name) {
40     DCHECK(RecomputeHandlerForName(name));
41     old_state_ = state_;
42     state_ = RECOMPUTE_HANDLER;
43   }
44 
45   // Clear the inline cache to initial state.
46   static void Clear(Isolate* isolate, Address address, Address constant_pool);
47 
48 #ifdef DEBUG
IsLoadStub()49   bool IsLoadStub() const {
50     return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC ||
51            kind_ == Code::KEYED_LOAD_IC;
52   }
IsStoreStub()53   bool IsStoreStub() const {
54     return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC;
55   }
IsCallStub()56   bool IsCallStub() const { return kind_ == Code::CALL_IC; }
57 #endif
58 
59   static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
60                                                   bool receiver_is_holder,
61                                                   Isolate* isolate,
62                                                   CacheHolderFlag* flag);
63   static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map,
64                                              Isolate* isolate,
65                                              CacheHolderFlag* flag);
66 
IsCleared(FeedbackNexus * nexus)67   static bool IsCleared(FeedbackNexus* nexus) {
68     InlineCacheState state = nexus->StateFromFeedback();
69     return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
70   }
71 
ICUseVector(Code::Kind kind)72   static bool ICUseVector(Code::Kind kind) {
73     return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
74            kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC ||
75            kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC;
76   }
77 
78   static InlineCacheState StateFromCode(Code* code);
79 
80  protected:
fp()81   Address fp() const { return fp_; }
pc()82   Address pc() const { return *pc_address_; }
isolate()83   Isolate* isolate() const { return isolate_; }
84 
85   // Get the shared function info of the caller.
86   SharedFunctionInfo* GetSharedFunctionInfo() const;
87   // Get the code object of the caller.
88   Code* GetCode() const;
89 
90   bool AddressIsOptimizedCode() const;
91   inline bool AddressIsDeoptimizedCode() const;
92   inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
93                                               Address address);
94 
95   // Set the call-site target.
96   inline void set_target(Code* code);
is_vector_set()97   bool is_vector_set() { return vector_set_; }
98 
UseVector()99   bool UseVector() const {
100     bool use = ICUseVector(kind());
101     // If we are supposed to use the nexus, verify the nexus is non-null.
102     DCHECK(!use || nexus_ != nullptr);
103     return use;
104   }
105 
106   // Configure for most states.
107   void ConfigureVectorState(IC::State new_state, Handle<Object> key);
108   // Configure the vector for MONOMORPHIC.
109   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
110                             Handle<Code> handler);
111   // Configure the vector for POLYMORPHIC.
112   void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
113                             CodeHandleList* handlers);
114   // Configure the vector for POLYMORPHIC with transitions (only for element
115   // keyed stores).
116   void ConfigureVectorState(MapHandleList* maps,
117                             MapHandleList* transitioned_maps,
118                             CodeHandleList* handlers);
119 
120   char TransitionMarkFromState(IC::State state);
121   void TraceIC(const char* type, Handle<Object> name);
122   void TraceIC(const char* type, Handle<Object> name, State old_state,
123                State new_state);
124 
125   MaybeHandle<Object> TypeError(MessageTemplate::Template,
126                                 Handle<Object> object, Handle<Object> key);
127   MaybeHandle<Object> ReferenceError(Handle<Name> name);
128 
129   // Access the target code for the given IC address.
130   static inline Code* GetTargetAtAddress(Address address,
131                                          Address constant_pool);
132   static inline void SetTargetAtAddress(Address address, Code* target,
133                                         Address constant_pool);
134   // As a vector-based IC, type feedback must be updated differently.
135   static void OnTypeFeedbackChanged(Isolate* isolate, Code* host);
136   static void PostPatching(Address address, Code* target, Code* old_target);
137 
138   // Compute the handler either by compiling or by retrieving a cached version.
139   Handle<Code> ComputeHandler(LookupIterator* lookup,
140                               Handle<Object> value = Handle<Code>::null());
GetMapIndependentHandler(LookupIterator * lookup)141   virtual Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) {
142     UNREACHABLE();
143     return Handle<Code>::null();
144   }
CompileHandler(LookupIterator * lookup,Handle<Object> value,CacheHolderFlag cache_holder)145   virtual Handle<Code> CompileHandler(LookupIterator* lookup,
146                                       Handle<Object> value,
147                                       CacheHolderFlag cache_holder) {
148     UNREACHABLE();
149     return Handle<Code>::null();
150   }
151 
152   void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
153   bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
154   void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
155 
156   void CopyICToMegamorphicCache(Handle<Name> name);
157   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
158   void PatchCache(Handle<Name> name, Handle<Code> code);
kind()159   Code::Kind kind() const { return kind_; }
is_keyed()160   bool is_keyed() const {
161     return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC;
162   }
handler_kind()163   Code::Kind handler_kind() const {
164     if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC;
165     DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC ||
166            kind_ == Code::KEYED_STORE_IC);
167     return kind_;
168   }
169   bool ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name);
170 
extra_ic_state()171   ExtraICState extra_ic_state() const { return extra_ic_state_; }
172 
receiver_map()173   Handle<Map> receiver_map() { return receiver_map_; }
update_receiver_map(Handle<Object> receiver)174   void update_receiver_map(Handle<Object> receiver) {
175     if (receiver->IsSmi()) {
176       receiver_map_ = isolate_->factory()->heap_number_map();
177     } else {
178       receiver_map_ = handle(HeapObject::cast(*receiver)->map());
179     }
180   }
181 
TargetMaps(MapHandleList * list)182   void TargetMaps(MapHandleList* list) {
183     FindTargetMaps();
184     for (int i = 0; i < target_maps_.length(); i++) {
185       list->Add(target_maps_.at(i));
186     }
187   }
188 
FirstTargetMap()189   Map* FirstTargetMap() {
190     FindTargetMaps();
191     return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
192   }
193 
vector()194   Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); }
slot()195   FeedbackVectorSlot slot() const { return nexus()->slot(); }
saved_state()196   State saved_state() const {
197     return state() == RECOMPUTE_HANDLER ? old_state_ : state();
198   }
199 
200   template <class NexusClass>
casted_nexus()201   NexusClass* casted_nexus() {
202     return static_cast<NexusClass*>(nexus_);
203   }
nexus()204   FeedbackNexus* nexus() const { return nexus_; }
205 
206   inline Code* get_host();
207   inline Code* target() const;
208 
209  private:
210   inline Address constant_pool() const;
211   inline Address raw_constant_pool() const;
212 
FindTargetMaps()213   void FindTargetMaps() {
214     if (target_maps_set_) return;
215     target_maps_set_ = true;
216     DCHECK(UseVector());
217     nexus()->ExtractMaps(&target_maps_);
218   }
219 
220   // Frame pointer for the frame that uses (calls) the IC.
221   Address fp_;
222 
223   // All access to the program counter and constant pool of an IC structure is
224   // indirect to make the code GC safe. This feature is crucial since
225   // GetProperty and SetProperty are called and they in turn might
226   // invoke the garbage collector.
227   Address* pc_address_;
228 
229   // The constant pool of the code which originally called the IC (which might
230   // be for the breakpointed copy of the original code).
231   Address* constant_pool_address_;
232 
233   Isolate* isolate_;
234 
235   bool vector_set_;
236   State old_state_;  // For saving if we marked as prototype failure.
237   State state_;
238   Code::Kind kind_;
239   Handle<Map> receiver_map_;
240   MaybeHandle<Code> maybe_handler_;
241 
242   ExtraICState extra_ic_state_;
243   MapHandleList target_maps_;
244   bool target_maps_set_;
245 
246   FeedbackNexus* nexus_;
247 
248   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
249 };
250 
251 
252 class CallIC : public IC {
253  public:
CallIC(Isolate * isolate,CallICNexus * nexus)254   CallIC(Isolate* isolate, CallICNexus* nexus)
255       : IC(EXTRA_CALL_FRAME, isolate, nexus) {
256     DCHECK(nexus != NULL);
257   }
258 
259   void HandleMiss(Handle<Object> function);
260 
261   // Code generator routines.
262   static Handle<Code> initialize_stub_in_optimized_code(
263       Isolate* isolate, int argc, ConvertReceiverMode mode,
264       TailCallMode tail_call_mode);
265 
266   static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
267 };
268 
269 
270 class LoadIC : public IC {
271  public:
272   LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
IC(depth,isolate,nexus)273       : IC(depth, isolate, nexus) {
274     DCHECK(nexus != NULL);
275     DCHECK(IsLoadStub());
276   }
277 
ShouldThrowReferenceError()278   bool ShouldThrowReferenceError() const {
279     return kind() == Code::LOAD_GLOBAL_IC &&
280            LoadGlobalICState::GetTypeofMode(extra_ic_state()) ==
281                NOT_INSIDE_TYPEOF;
282   }
283 
284   // Code generator routines.
285 
286   static void GenerateMiss(MacroAssembler* masm);
287   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
288   static void GenerateNormal(MacroAssembler* masm);
289 
290   static Handle<Code> initialize_stub_in_optimized_code(Isolate* isolate);
291 
292   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
293                                            Handle<Name> name);
294 
295   static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
296 
297  protected:
slow_stub()298   virtual Handle<Code> slow_stub() const {
299     return isolate()->builtins()->LoadIC_Slow();
300   }
301 
302   // Update the inline cache and the global stub cache based on the
303   // lookup result.
304   void UpdateCaches(LookupIterator* lookup);
305 
306   Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) override;
307 
308   Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
309                               CacheHolderFlag cache_holder) override;
310 
311  private:
312   Handle<Code> SimpleFieldLoad(FieldIndex index);
313 
314   friend class IC;
315 };
316 
317 class LoadGlobalIC : public LoadIC {
318  public:
319   LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
LoadIC(depth,isolate,nexus)320       : LoadIC(depth, isolate, nexus) {}
321 
322   static Handle<Code> initialize_stub_in_optimized_code(
323       Isolate* isolate, ExtraICState extra_state);
324 
325   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);
326 
327   static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus);
328 
329  protected:
slow_stub()330   Handle<Code> slow_stub() const override {
331     return isolate()->builtins()->LoadGlobalIC_Slow();
332   }
333 };
334 
335 class KeyedLoadIC : public LoadIC {
336  public:
337   KeyedLoadIC(FrameDepth depth, Isolate* isolate,
338               KeyedLoadICNexus* nexus = NULL)
LoadIC(depth,isolate,nexus)339       : LoadIC(depth, isolate, nexus) {
340     DCHECK(nexus != NULL);
341   }
342 
343   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
344                                            Handle<Object> key);
345 
346   // Code generator routines.
347   static void GenerateMiss(MacroAssembler* masm);
348   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
349   static void GenerateMegamorphic(MacroAssembler* masm);
350 
351   static Handle<Code> initialize_stub_in_optimized_code(
352       Isolate* isolate, ExtraICState extra_state);
353   static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
354                                             ExtraICState extra_state);
355 
356   static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
357 
358  protected:
359   // receiver is HeapObject because it could be a String or a JSObject
360   void UpdateLoadElement(Handle<HeapObject> receiver);
361 
362  private:
363   friend class IC;
364 };
365 
366 
367 class StoreIC : public IC {
368  public:
369   StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
IC(depth,isolate,nexus)370       : IC(depth, isolate, nexus) {
371     DCHECK(IsStoreStub());
372   }
373 
language_mode()374   LanguageMode language_mode() const {
375     return StoreICState::GetLanguageMode(extra_ic_state());
376   }
377 
378   // Code generators for stub routines. Only called once at startup.
379   static void GenerateSlow(MacroAssembler* masm);
380   static void GenerateMiss(MacroAssembler* masm);
381   static void GenerateNormal(MacroAssembler* masm);
382 
383   static Handle<Code> initialize_stub_in_optimized_code(
384       Isolate* isolate, LanguageMode language_mode);
385 
386   MUST_USE_RESULT MaybeHandle<Object> Store(
387       Handle<Object> object, Handle<Name> name, Handle<Object> value,
388       JSReceiver::StoreFromKeyed store_mode =
389           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
390 
391   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
392                       JSReceiver::StoreFromKeyed store_mode);
393 
394   static void Clear(Isolate* isolate, Code* host, StoreICNexus* nexus);
395 
396  protected:
397   // Stub accessors.
slow_stub()398   Handle<Code> slow_stub() const {
399     return isolate()->builtins()->StoreIC_Slow();
400   }
401 
402   // Update the inline cache and the global stub cache based on the
403   // lookup result.
404   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
405                     JSReceiver::StoreFromKeyed store_mode);
406   Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) override;
407   Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> value,
408                               CacheHolderFlag cache_holder) override;
409 
410  private:
411   friend class IC;
412 };
413 
414 
415 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
416 
417 
418 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
419 
420 
421 class KeyedStoreIC : public StoreIC {
422  public:
GetKeyedAccessStoreMode()423   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
424     return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
425   }
426 
427   KeyedStoreIC(FrameDepth depth, Isolate* isolate,
428                KeyedStoreICNexus* nexus = NULL)
StoreIC(depth,isolate,nexus)429       : StoreIC(depth, isolate, nexus) {}
430 
431   MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
432                                             Handle<Object> name,
433                                             Handle<Object> value);
434 
435   // Code generators for stub routines.  Only called once at startup.
436   static void GenerateMiss(MacroAssembler* masm);
437   static void GenerateSlow(MacroAssembler* masm);
438   static void GenerateMegamorphic(MacroAssembler* masm,
439                                   LanguageMode language_mode);
440 
441   static Handle<Code> initialize_stub_in_optimized_code(
442       Isolate* isolate, LanguageMode language_mode);
443   static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
444                                             ExtraICState extra_state);
445 
446   static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus);
447 
448  protected:
449   void UpdateStoreElement(Handle<Map> receiver_map,
450                           KeyedAccessStoreMode store_mode);
451 
452  private:
453   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
454                                      KeyedAccessStoreMode store_mode);
455 
456   friend class IC;
457 };
458 
459 
460 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
461 class BinaryOpIC : public IC {
462  public:
BinaryOpIC(Isolate * isolate)463   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
464 
465   MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site,
466                                  Handle<Object> left,
467                                  Handle<Object> right) WARN_UNUSED_RESULT;
468 };
469 
470 
471 class CompareIC : public IC {
472  public:
CompareIC(Isolate * isolate,Token::Value op)473   CompareIC(Isolate* isolate, Token::Value op)
474       : IC(EXTRA_CALL_FRAME, isolate), op_(op) {}
475 
476   // Update the inline cache for the given operands.
477   Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
478 
479   // Helper function for computing the condition for a compare operation.
480   static Condition ComputeCondition(Token::Value op);
481 
482   // Factory method for getting an uninitialized compare stub.
483   static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
484 
485  private:
486   static bool HasInlinedSmiCode(Address address);
487 
strict()488   bool strict() const { return op_ == Token::EQ_STRICT; }
GetCondition()489   Condition GetCondition() const { return ComputeCondition(op_); }
490 
491   static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
492 
493   static void Clear(Isolate* isolate, Address address, Code* target,
494                     Address constant_pool);
495 
496   Token::Value op_;
497 
498   friend class IC;
499 };
500 
501 
502 class ToBooleanIC : public IC {
503  public:
ToBooleanIC(Isolate * isolate)504   explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
505 
506   Handle<Object> ToBoolean(Handle<Object> object);
507 };
508 
509 
510 // Helper for BinaryOpIC and CompareIC.
511 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
512 void PatchInlinedSmiCode(Isolate* isolate, Address address,
513                          InlinedSmiCheck check);
514 
515 }  // namespace internal
516 }  // namespace v8
517 
518 #endif  // V8_IC_H_
519