ic.h 12.9 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
#ifndef V8_IC_IC_H_
#define V8_IC_IC_H_
7

8 9
#include <vector>

10 11
#include "src/factory.h"
#include "src/feedback-vector.h"
12 13
#include "src/ic/stub-cache.h"
#include "src/isolate.h"
14
#include "src/macro-assembler.h"
15
#include "src/messages.h"
16
#include "src/objects/map.h"
17

18 19
namespace v8 {
namespace internal {
20 21

//
verwaest@chromium.org's avatar
verwaest@chromium.org committed
22
// IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
23 24 25 26 27 28 29 30
//
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.
31
  enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
32

33 34
  static constexpr int kMaxKeyedPolymorphism = 4;

35 36 37 38
  // A polymorphic IC can handle at most 4 distinct maps before transitioning
  // to megamorphic state.
  static constexpr int kMaxPolymorphicMapCount = 4;

39 40
  // Construct the IC structure with the given number of extra
  // JavaScript frames on the stack.
41 42
  IC(FrameDepth depth, Isolate* isolate, Handle<FeedbackVector> vector,
     FeedbackSlot slot);
43
  virtual ~IC() {}
44

45
  State state() const { return state_; }
46 47
  inline Address address() const;

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

51 52 53
  bool RecomputeHandlerForName(Handle<Object> name);
  void MarkRecomputeHandler(Handle<Object> name) {
    DCHECK(RecomputeHandlerForName(name));
54
    old_state_ = state_;
55
    state_ = RECOMPUTE_HANDLER;
56
  }
57

58 59
  bool IsAnyLoad() const {
    return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
60
  }
61
  bool IsAnyStore() const {
62
    return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
63
           IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
64
  }
65

66 67
  static inline bool IsHandler(Object* object);

68
  // Nofity the IC system that a feedback has changed.
69
  static void OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector,
70 71
                                FeedbackSlot slot, JSFunction* host_function,
                                const char* reason);
72

73 74 75
  static void OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
                                JSFunction* host_function, const char* reason);

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

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

82
  Isolate* isolate() const { return isolate_; }
83

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

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

91
  bool is_vector_set() { return vector_set_; }
92 93 94 95 96
  bool vector_needs_update() {
    return (!vector_set_ &&
            (state() != MEGAMORPHIC ||
             Smi::ToInt(nexus()->GetFeedbackExtra()) != ELEMENT));
  }
97

98
  // Configure for most states.
99
  bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
100
  // Configure the vector for MONOMORPHIC.
101
  void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
102
                            Handle<Object> handler);
103
  // Configure the vector for POLYMORPHIC.
104
  void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
105
                            ObjectHandles* handlers);
106

107
  char TransitionMarkFromState(IC::State state);
108
  void TraceIC(const char* type, Handle<Object> name);
109 110
  void TraceIC(const char* type, Handle<Object> name, State old_state,
               State new_state);
111

112 113
  MaybeHandle<Object> TypeError(MessageTemplate::Template,
                                Handle<Object> object, Handle<Object> key);
114
  MaybeHandle<Object> ReferenceError(Handle<Name> name);
115

116 117
  void TraceHandlerCacheHitStats(LookupIterator* lookup);

118 119 120
  void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
  bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
  void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
121

122 123
  StubCache* stub_cache();

124
  void CopyICToMegamorphicCache(Handle<Name> name);
125
  bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
126
  void PatchCache(Handle<Name> name, Handle<Object> code);
127
  FeedbackSlotKind kind() const { return kind_; }
128
  bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
129 130 131
  bool IsLoadIC() const { return IsLoadICKind(kind_); }
  bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
  bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
132
  bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
133
  bool IsStoreIC() const { return IsStoreICKind(kind_); }
134
  bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
135
  bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
136 137 138 139
  bool is_keyed() const {
    return IsKeyedLoadIC() || IsKeyedStoreIC() ||
           IsStoreInArrayLiteralICKind(kind_);
  }
140
  bool ShouldRecomputeHandler(Handle<String> name);
141

142 143 144 145 146 147 148
  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());
    }
149
  }
150

151
  void TargetMaps(MapHandles* list) {
152
    FindTargetMaps();
153 154
    for (Handle<Map> map : target_maps_) {
      list->push_back(map);
155 156 157 158 159
    }
  }

  Map* FirstTargetMap() {
    FindTargetMaps();
160
    return !target_maps_.empty() ? *target_maps_[0] : nullptr;
161 162
  }

163
  State saved_state() const {
164
    return state() == RECOMPUTE_HANDLER ? old_state_ : state();
165 166
  }

167 168
  const FeedbackNexus* nexus() const { return &nexus_; }
  FeedbackNexus* nexus() { return &nexus_; }
169

170
 private:
171 172
  inline Address constant_pool() const;
  inline Address raw_constant_pool() const;
173

174 175 176
  void FindTargetMaps() {
    if (target_maps_set_) return;
    target_maps_set_ = true;
verwaest's avatar
verwaest committed
177
    nexus()->ExtractMaps(&target_maps_);
178 179
  }

180 181 182
  // Frame pointer for the frame that uses (calls) the IC.
  Address fp_;

183 184
  // 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
185 186 187
  // GetProperty and SetProperty are called and they in turn might
  // invoke the garbage collector.
  Address* pc_address_;
188

189 190
  // The constant pool of the code which originally called the IC (which might
  // be for the breakpointed copy of the original code).
191 192 193
  Address* constant_pool_address_;

  Isolate* isolate_;
194

195
  bool vector_set_;
196
  State old_state_;  // For saving if we marked as prototype failure.
197
  State state_;
198
  FeedbackSlotKind kind_;
199
  Handle<Map> receiver_map_;
200
  MaybeHandle<Object> maybe_handler_;
201

202
  MapHandles target_maps_;
203
  bool target_maps_set_;
204

205 206
  const char* slow_stub_reason_;

207
  FeedbackNexus nexus_;
208

209
  DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
210 211 212
};


213
class CallIC : public IC {
214
 public:
215 216
  CallIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
      : IC(EXTRA_CALL_FRAME, isolate, vector, slot) {}
217 218 219
};


220
class LoadIC : public IC {
221
 public:
222 223
  LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
      : IC(NO_EXTRA_FRAME, isolate, vector, slot) {
224
    DCHECK(IsAnyLoad());
225 226
  }

227
  static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
228
    return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
229 230
  }

231
  bool ShouldThrowReferenceError() const {
232
    return ShouldThrowReferenceError(kind());
233 234
  }

235
  MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
236
                                           Handle<Name> name);
237

238
 protected:
239
  virtual Handle<Code> slow_stub() const {
240
    return BUILTIN_CODE(isolate(), LoadIC_Slow);
241 242
  }

243 244
  // Update the inline cache and the global stub cache based on the
  // lookup result.
245
  void UpdateCaches(LookupIterator* lookup);
246

247
 private:
248
  Handle<Object> ComputeHandler(LookupIterator* lookup);
249

250
  friend class IC;
251
  friend class NamedLoadHandlerCompiler;
252 253
};

254 255
class LoadGlobalIC : public LoadIC {
 public:
256 257 258
  LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
               FeedbackSlot slot)
      : LoadIC(isolate, vector, slot) {}
259 260 261 262 263

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

 protected:
  Handle<Code> slow_stub() const override {
264
    return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
265 266
  }
};
267

268
class KeyedLoadIC : public LoadIC {
danno@chromium.org's avatar
danno@chromium.org committed
269
 public:
270 271 272
  KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
              FeedbackSlot slot)
      : LoadIC(isolate, vector, slot) {}
273

274 275
  MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
                                           Handle<Object> key);
276

277
 protected:
278
  // receiver is HeapObject because it could be a String or a JSObject
279 280
  void UpdateLoadElement(Handle<HeapObject> receiver,
                         KeyedAccessLoadMode load_mode);
281

282
 private:
283
  friend class IC;
284

285 286
  Handle<Object> LoadElementHandler(Handle<Map> receiver_map,
                                    KeyedAccessLoadMode load_mode);
287

288
  void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
289 290
                                      ObjectHandles* handlers,
                                      KeyedAccessLoadMode load_mode);
291 292 293 294 295

  // Returns true if the receiver_map has a kElement or kIndexedString
  // handler in the nexus currently but didn't yet allow out of bounds
  // accesses.
  bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
296 297 298
};


299
class StoreIC : public IC {
300
 public:
301 302
  StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
      : IC(NO_EXTRA_FRAME, isolate, vector, slot) {
303
    DCHECK(IsAnyStore());
304
  }
305

306
  LanguageMode language_mode() const { return nexus()->GetLanguageMode(); }
307

308
  MUST_USE_RESULT MaybeHandle<Object> Store(
309
      Handle<Object> object, Handle<Name> name, Handle<Object> value,
310 311 312
      JSReceiver::StoreFromKeyed store_mode =
          JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);

313 314 315
  bool LookupForWrite(LookupIterator* it, Handle<Object> value,
                      JSReceiver::StoreFromKeyed store_mode);

316
 protected:
317
  // Stub accessors.
318
  virtual Handle<Code> slow_stub() const {
319
    // All StoreICs share the same slow stub.
320
    return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
321
  }
322

323 324
  // Update the inline cache and the global stub cache based on the
  // lookup result.
325
  void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
326
                    JSReceiver::StoreFromKeyed store_mode);
327

328
 private:
329 330
  Handle<Object> ComputeHandler(LookupIterator* lookup);

331
  friend class IC;
332 333

  bool created_new_transition_ = false;
334 335
};

336 337
class StoreGlobalIC : public StoreIC {
 public:
338 339 340
  StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
                FeedbackSlot slot)
      : StoreIC(isolate, vector, slot) {}
341

342
  MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Name> name,
343
                                            Handle<Object> value);
344 345 346 347 348

 protected:
  Handle<Code> slow_stub() const override {
    return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
  }
349
};
350

351
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
352 353


354
enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
355 356


357
class KeyedStoreIC : public StoreIC {
358
 public:
359
  KeyedAccessStoreMode GetKeyedAccessStoreMode() {
360
    return nexus()->GetKeyedAccessStoreMode();
361 362
  }

363 364 365
  KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
               FeedbackSlot slot)
      : StoreIC(isolate, vector, slot) {}
366

367 368 369
  MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
                                            Handle<Object> name,
                                            Handle<Object> value);
370

danno@chromium.org's avatar
danno@chromium.org committed
371
 protected:
372
  void UpdateStoreElement(Handle<Map> receiver_map,
373 374
                          KeyedAccessStoreMode store_mode,
                          bool receiver_was_cow);
375

376 377 378 379
  Handle<Code> slow_stub() const override {
    return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
  }

380
 private:
381
  Handle<Map> ComputeTransitionedMap(Handle<Map> map,
382
                                     KeyedAccessStoreMode store_mode);
383

384 385 386
  Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
                                     KeyedAccessStoreMode store_mode);

387
  void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
388
                                       ObjectHandles* handlers,
389 390
                                       KeyedAccessStoreMode store_mode);

391 392 393
  friend class IC;
};

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
class StoreInArrayLiteralIC : public KeyedStoreIC {
 public:
  StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
                        FeedbackSlot slot)
      : KeyedStoreIC(isolate, vector, slot) {
    DCHECK(IsStoreInArrayLiteralICKind(kind()));
  }

  void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);

 private:
  Handle<Code> slow_stub() const override {
    return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
  }
};

410 411
}  // namespace internal
}  // namespace v8
412

413
#endif  // V8_IC_IC_H_