ic.h 14.8 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_IC_H_
#define V8_IC_H_

8 9
#include "src/factory.h"
#include "src/feedback-vector.h"
10
#include "src/ic/ic-state.h"
11
#include "src/macro-assembler.h"
12
#include "src/messages.h"
13
#include "src/objects/map.h"
14

15 16
namespace v8 {
namespace internal {
17 18

//
verwaest@chromium.org's avatar
verwaest@chromium.org committed
19
// IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
20 21 22 23 24 25 26 27
//
class IC {
 public:
  // Alias the inline cache state type to make the IC code more readable.
  typedef InlineCacheState State;

  // The IC code is either invoked with no extra frames on the stack
  // or with a single extra frame for supporting calls.
28
  enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
29

30 31 32 33
  // A polymorphic IC can handle at most 4 distinct maps before transitioning
  // to megamorphic state.
  static constexpr int kMaxPolymorphicMapCount = 4;

34 35
  // Construct the IC structure with the given number of extra
  // JavaScript frames on the stack.
36
  IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);
37
  virtual ~IC() {}
38

39
  State state() const { return state_; }
40 41
  inline Address address() const;

42
  // Compute the current IC state based on the target stub, receiver and name.
43
  void UpdateState(Handle<Object> receiver, Handle<Object> name);
44

45 46 47
  bool RecomputeHandlerForName(Handle<Object> name);
  void MarkRecomputeHandler(Handle<Object> name) {
    DCHECK(RecomputeHandlerForName(name));
48
    old_state_ = state_;
49
    state_ = RECOMPUTE_HANDLER;
50
  }
51 52

  // Clear the inline cache to initial state.
53
  static void Clear(Isolate* isolate, Address address, Address constant_pool);
54

55 56
  bool IsAnyLoad() const {
    return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
57
  }
58
  bool IsAnyStore() const {
59 60
    return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
           IsKeyedStoreIC();
61
  }
62

63 64 65 66
  // The ICs that don't pass slot and vector through the stack have to
  // save/restore them in the dispatcher.
  static bool ShouldPushPopSlotAndVector(Code::Kind kind);

67 68
  static InlineCacheState StateFromCode(Code* code);

69 70
  static inline bool IsHandler(Object* object);

71
  // Nofity the IC system that a feedback has changed.
72
  static void OnFeedbackChanged(Isolate* isolate, JSFunction* host_function);
73

74 75 76
 protected:
  Address fp() const { return fp_; }
  Address pc() const { return *pc_address_; }
77 78 79 80

  void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }

  Address GetAbstractPC(int* line, int* column) const;
81
  Isolate* isolate() const { return isolate_; }
82

83 84
  // Get the caller function object.
  JSFunction* GetHostFunction() const;
85

86 87 88
  inline bool AddressIsDeoptimizedCode() const;
  inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
                                              Address address);
89

90
  // Set the call-site target.
91
  inline void set_target(Code* code);
92
  bool is_vector_set() { return vector_set_; }
93

94
  // Configure for most states.
95
  void ConfigureVectorState(IC::State new_state, Handle<Object> key);
96
  // Configure the vector for MONOMORPHIC.
97
  void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
98
                            Handle<Object> handler);
99
  // Configure the vector for POLYMORPHIC.
100
  void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
101
                            List<Handle<Object>>* handlers);
102

103
  char TransitionMarkFromState(IC::State state);
104
  void TraceIC(const char* type, Handle<Object> name);
105 106
  void TraceIC(const char* type, Handle<Object> name, State old_state,
               State new_state);
107

108 109
  MaybeHandle<Object> TypeError(MessageTemplate::Template,
                                Handle<Object> object, Handle<Object> key);
110
  MaybeHandle<Object> ReferenceError(Handle<Name> name);
111 112

  // Access the target code for the given IC address.
113
  static inline Code* GetTargetAtAddress(Address address,
114
                                         Address constant_pool);
115
  static inline void SetTargetAtAddress(Address address, Code* target,
116
                                        Address constant_pool);
117
  static void PostPatching(Address address, Code* target, Code* old_target);
118

119 120
  void TraceHandlerCacheHitStats(LookupIterator* lookup);

121
  // Compute the handler either by compiling or by retrieving a cached version.
122
  Handle<Object> ComputeHandler(LookupIterator* lookup);
123
  virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
124 125
    UNREACHABLE();
  }
126
  virtual Handle<Code> CompileHandler(LookupIterator* lookup) {
127 128
    UNREACHABLE();
  }
129

130 131 132
  void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
  bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
  void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
133

134 135
  StubCache* stub_cache();

136
  void CopyICToMegamorphicCache(Handle<Name> name);
137
  bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
138
  void PatchCache(Handle<Name> name, Handle<Object> code);
139 140 141 142
  FeedbackSlotKind kind() const { return kind_; }
  bool IsLoadIC() const { return IsLoadICKind(kind_); }
  bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
  bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
143
  bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
144
  bool IsStoreIC() const { return IsStoreICKind(kind_); }
145
  bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
146 147
  bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
  bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); }
148
  Code::Kind handler_kind() const {
149 150 151
    if (IsAnyLoad()) return Code::LOAD_IC;
    DCHECK(IsAnyStore());
    return Code::STORE_IC;
152
  }
153
  bool ShouldRecomputeHandler(Handle<String> name);
154

155
  ExtraICState extra_ic_state() const { return extra_ic_state_; }
156

157 158 159 160 161 162 163
  Handle<Map> receiver_map() { return receiver_map_; }
  void update_receiver_map(Handle<Object> receiver) {
    if (receiver->IsSmi()) {
      receiver_map_ = isolate_->factory()->heap_number_map();
    } else {
      receiver_map_ = handle(HeapObject::cast(*receiver)->map());
    }
164
  }
165

166
  void TargetMaps(MapHandles* list) {
167
    FindTargetMaps();
168 169
    for (Handle<Map> map : target_maps_) {
      list->push_back(map);
170 171 172 173 174
    }
  }

  Map* FirstTargetMap() {
    FindTargetMaps();
175
    return !target_maps_.empty() ? *target_maps_[0] : NULL;
176 177
  }

178
  Handle<FeedbackVector> vector() const { return nexus()->vector_handle(); }
179
  FeedbackSlot slot() const { return nexus()->slot(); }
180
  State saved_state() const {
181
    return state() == RECOMPUTE_HANDLER ? old_state_ : state();
182 183 184 185 186 187 188 189
  }

  template <class NexusClass>
  NexusClass* casted_nexus() {
    return static_cast<NexusClass*>(nexus_);
  }
  FeedbackNexus* nexus() const { return nexus_; }

verwaest's avatar
verwaest committed
190
  inline Code* target() const;
191

192
 private:
193 194
  inline Address constant_pool() const;
  inline Address raw_constant_pool() const;
195

196 197 198
  void FindTargetMaps() {
    if (target_maps_set_) return;
    target_maps_set_ = true;
verwaest's avatar
verwaest committed
199
    nexus()->ExtractMaps(&target_maps_);
200 201
  }

202 203 204
  // Frame pointer for the frame that uses (calls) the IC.
  Address fp_;

205 206
  // All access to the program counter and constant pool of an IC structure is
  // indirect to make the code GC safe. This feature is crucial since
207 208 209
  // GetProperty and SetProperty are called and they in turn might
  // invoke the garbage collector.
  Address* pc_address_;
210

211 212
  // The constant pool of the code which originally called the IC (which might
  // be for the breakpointed copy of the original code).
213 214 215
  Address* constant_pool_address_;

  Isolate* isolate_;
216

217
  bool vector_set_;
218
  State old_state_;  // For saving if we marked as prototype failure.
219
  State state_;
220
  FeedbackSlotKind kind_;
221
  Handle<Map> receiver_map_;
222
  MaybeHandle<Object> maybe_handler_;
223

224
  ExtraICState extra_ic_state_;
225
  MapHandles target_maps_;
226
  bool target_maps_set_;
227

228 229
  const char* slow_stub_reason_;

230 231
  FeedbackNexus* nexus_;

232
  DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
233 234 235
};


236
class CallIC : public IC {
237
 public:
238 239 240 241
  CallIC(Isolate* isolate, CallICNexus* nexus)
      : IC(EXTRA_CALL_FRAME, isolate, nexus) {
    DCHECK(nexus != NULL);
  }
242 243 244
};


245
class LoadIC : public IC {
246
 public:
247 248
  LoadIC(Isolate* isolate, FeedbackNexus* nexus)
      : IC(NO_EXTRA_FRAME, isolate, nexus) {
249
    DCHECK(nexus != NULL);
250
    DCHECK(IsAnyLoad());
251 252
  }

253
  static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
254
    return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
255 256
  }

257
  bool ShouldThrowReferenceError() const {
258
    return ShouldThrowReferenceError(kind());
259 260
  }

261
  MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
262
                                           Handle<Name> name);
263

264
 protected:
265
  virtual Handle<Code> slow_stub() const {
266
    return isolate()->builtins()->LoadIC_Slow();
267 268
  }

269 270
  // Update the inline cache and the global stub cache based on the
  // lookup result.
271
  void UpdateCaches(LookupIterator* lookup);
272

273
  Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
274

275
  Handle<Code> CompileHandler(LookupIterator* lookup) override;
276

277
 private:
278
  // Creates a data handler that represents a load of a field by given index.
279
  static Handle<Smi> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
280 281 282

  // Creates a data handler that represents a prototype chain check followed
  // by given Smi-handler that encoded a load from the holder.
283
  // Can be used only if GetPrototypeCheckCount() returns non negative value.
284 285
  Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
                                   Handle<JSObject> holder, Handle<Name> name,
286
                                   Handle<Smi> smi_handler);
287

288
  // Creates a data handler that represents a load of a non-existent property.
289 290 291 292
  // {holder} is the object from which the property is loaded. If no holder is
  // needed (e.g., for "nonexistent"), null_value() may be passed in.
  Handle<Object> LoadFullChain(Handle<Map> receiver_map, Handle<Object> holder,
                               Handle<Name> name, Handle<Smi> smi_handler);
293

294
  friend class IC;
295
  friend class NamedLoadHandlerCompiler;
296 297
};

298 299
class LoadGlobalIC : public LoadIC {
 public:
300 301
  LoadGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
      : LoadIC(isolate, nexus) {}
302 303 304 305 306

  MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);

 protected:
  Handle<Code> slow_stub() const override {
307
    return isolate()->builtins()->LoadGlobalIC_Slow();
308 309
  }
};
310

311
class KeyedLoadIC : public LoadIC {
danno@chromium.org's avatar
danno@chromium.org committed
312
 public:
313 314
  KeyedLoadIC(Isolate* isolate, KeyedLoadICNexus* nexus)
      : LoadIC(isolate, nexus) {
315
    DCHECK(nexus != NULL);
316
  }
317

318 319
  MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
                                           Handle<Object> key);
320

321
 protected:
322
  // receiver is HeapObject because it could be a String or a JSObject
323
  void UpdateLoadElement(Handle<HeapObject> receiver);
324

325
 private:
326
  friend class IC;
327 328 329

  Handle<Object> LoadElementHandler(Handle<Map> receiver_map);

330
  void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
331
                                      List<Handle<Object>>* handlers);
332 333 334
};


335
class StoreIC : public IC {
336
 public:
337 338
  StoreIC(Isolate* isolate, FeedbackNexus* nexus)
      : IC(NO_EXTRA_FRAME, isolate, nexus) {
339
    DCHECK(IsAnyStore());
340
  }
341

342
  LanguageMode language_mode() const {
343
    return nexus()->vector()->GetLanguageMode(nexus()->slot());
344
  }
345

346
  MUST_USE_RESULT MaybeHandle<Object> Store(
347
      Handle<Object> object, Handle<Name> name, Handle<Object> value,
348 349 350
      JSReceiver::StoreFromKeyed store_mode =
          JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);

351 352 353
  bool LookupForWrite(LookupIterator* it, Handle<Object> value,
                      JSReceiver::StoreFromKeyed store_mode);

354
 protected:
355
  // Stub accessors.
356
  Handle<Code> slow_stub() const {
357
    // All StoreICs share the same slow stub.
358
    return isolate()->builtins()->KeyedStoreIC_Slow();
359
  }
360

361 362
  // Update the inline cache and the global stub cache based on the
  // lookup result.
363 364
  void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
                    JSReceiver::StoreFromKeyed store_mode);
365
  Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
366
  Handle<Code> CompileHandler(LookupIterator* lookup) override;
367

368
 private:
369 370 371 372
  Handle<Object> StoreTransition(Handle<Map> receiver_map,
                                 Handle<JSObject> holder,
                                 Handle<Map> transition, Handle<Name> name);

373 374 375
  friend class IC;
};

376 377 378 379 380 381 382 383 384
class StoreGlobalIC : public StoreIC {
 public:
  StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
      : StoreIC(isolate, nexus) {}

  MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
                                            Handle<Name> name,
                                            Handle<Object> value);
};
385

386
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
387 388


389
enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
390 391


392
class KeyedStoreIC : public StoreIC {
393
 public:
394 395 396 397
  KeyedAccessStoreMode GetKeyedAccessStoreMode() {
    return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
  }

398 399
  KeyedStoreIC(Isolate* isolate, KeyedStoreICNexus* nexus)
      : StoreIC(isolate, nexus) {}
400

401 402 403
  MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
                                            Handle<Object> name,
                                            Handle<Object> value);
404

danno@chromium.org's avatar
danno@chromium.org committed
405
 protected:
406 407
  void UpdateStoreElement(Handle<Map> receiver_map,
                          KeyedAccessStoreMode store_mode);
408

409
 private:
410
  Handle<Map> ComputeTransitionedMap(Handle<Map> map,
411
                                     KeyedAccessStoreMode store_mode);
412

413 414 415
  Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
                                     KeyedAccessStoreMode store_mode);

416
  void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
417 418 419
                                       List<Handle<Object>>* handlers,
                                       KeyedAccessStoreMode store_mode);

420 421 422 423
  friend class IC;
};


424
class CompareIC : public IC {
425
 public:
426
  CompareIC(Isolate* isolate, Token::Value op)
427
      : IC(EXTRA_CALL_FRAME, isolate), op_(op) {}
428 429

  // Update the inline cache for the given operands.
430
  Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
431 432 433 434 435

  // Helper function for computing the condition for a compare operation.
  static Condition ComputeCondition(Token::Value op);

 private:
436 437
  static bool HasInlinedSmiCode(Address address);

438 439 440
  bool strict() const { return op_ == Token::EQ_STRICT; }
  Condition GetCondition() const { return ComputeCondition(op_); }

441
  static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
442

443
  static void Clear(Isolate* isolate, Address address, Code* target,
444
                    Address constant_pool);
445

446
  Token::Value op_;
447 448

  friend class IC;
449 450
};

451
// Helper for CompareIC.
452
enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
453 454
void PatchInlinedSmiCode(Isolate* isolate, Address address,
                         InlinedSmiCheck check);
455

456 457
}  // namespace internal
}  // namespace v8
458 459

#endif  // V8_IC_H_