accessor-assembler.h 18.6 KB
Newer Older
1 2 3 4
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_IC_ACCESSOR_ASSEMBLER_H_
#define V8_IC_ACCESSOR_ASSEMBLER_H_
7

8
#include "src/codegen/code-stub-assembler.h"
9 10 11 12 13 14 15 16

namespace v8 {
namespace internal {

namespace compiler {
class CodeAssemblerState;
}

17 18
class ExitPoint;

19
class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
20
 public:
21 22 23 24 25
  using Node = compiler::Node;
  template <class T>
  using TNode = compiler::TNode<T>;
  template <class T>
  using SloppyTNode = compiler::SloppyTNode<T>;
26 27 28 29 30

  explicit AccessorAssembler(compiler::CodeAssemblerState* state)
      : CodeStubAssembler(state) {}

  void GenerateLoadIC();
31
  void GenerateLoadIC_Megamorphic();
32
  void GenerateLoadIC_Noninlined();
33
  void GenerateLoadIC_Uninitialized();
34
  void GenerateLoadICTrampoline();
35
  void GenerateLoadICTrampoline_Megamorphic();
36 37
  void GenerateKeyedLoadIC();
  void GenerateKeyedLoadIC_Megamorphic();
38
  void GenerateKeyedLoadIC_PolymorphicName();
39 40
  void GenerateKeyedLoadICTrampoline();
  void GenerateKeyedLoadICTrampoline_Megamorphic();
41 42
  void GenerateStoreIC();
  void GenerateStoreICTrampoline();
43 44
  void GenerateStoreGlobalIC();
  void GenerateStoreGlobalICTrampoline();
45
  void GenerateCloneObjectIC();
46
  void GenerateCloneObjectIC_Slow();
47 48 49
  void GenerateKeyedHasIC();
  void GenerateKeyedHasIC_Megamorphic();
  void GenerateKeyedHasIC_PolymorphicName();
50 51 52 53

  void GenerateLoadGlobalIC(TypeofMode typeof_mode);
  void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);

54 55
  void GenerateKeyedStoreIC();
  void GenerateKeyedStoreICTrampoline();
56

57 58
  void GenerateStoreInArrayLiteralIC();

59
  void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
60
                         Label* if_handler, TVariable<MaybeObject>* var_handler,
61 62 63 64 65 66 67 68 69 70
                         Label* if_miss);

  Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
    return StubCachePrimaryOffset(name, map);
  }
  Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
    return StubCacheSecondaryOffset(name, map);
  }

  struct LoadICParameters {
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    LoadICParameters(TNode<Context> context, Node* receiver, Node* name,
                     Node* slot, Node* vector, Node* holder = nullptr)
        : context_(context),
          receiver_(receiver),
          name_(name),
          slot_(slot),
          vector_(vector),
          holder_(holder ? holder : receiver) {}

    LoadICParameters(const LoadICParameters* p, Node* unique_name)
        : context_(p->context_),
          receiver_(p->receiver_),
          name_(unique_name),
          slot_(p->slot_),
          vector_(p->vector_),
          holder_(p->holder_) {}

    TNode<Context> context() const { return context_; }
    Node* receiver() const { return receiver_; }
    Node* name() const { return name_; }
    Node* slot() const { return slot_; }
    Node* vector() const { return vector_; }
    Node* holder() const { return holder_; }

   private:
    TNode<Context> context_;
    Node* receiver_;
    Node* name_;
    Node* slot_;
    Node* vector_;
    Node* holder_;
  };

  struct LazyLoadICParameters {
    LazyLoadICParameters(LazyNode<Context> context, Node* receiver,
                         LazyNode<Object> name, Node* slot, Node* vector,
                         Node* holder = nullptr)
        : context_(context),
          receiver_(receiver),
          name_(name),
          slot_(slot),
          vector_(vector),
          holder_(holder ? holder : receiver) {}

    explicit LazyLoadICParameters(const LoadICParameters* p)
        : receiver_(p->receiver()),
          slot_(p->slot()),
          vector_(p->vector()),
          holder_(p->holder()) {
      TNode<Context> p_context = p->context();
      context_ = [=] { return p_context; };
      TNode<Object> p_name = TNode<Object>::UncheckedCast(p->name());
      name_ = [=] { return p_name; };
    }

    TNode<Context> context() const { return context_(); }
    Node* receiver() const { return receiver_; }
    Node* name() const { return name_(); }
    Node* slot() const { return slot_; }
    Node* vector() const { return vector_; }
    Node* holder() const { return holder_; }

   private:
    LazyNode<Context> context_;
    Node* receiver_;
    LazyNode<Object> name_;
    Node* slot_;
    Node* vector_;
    Node* holder_;
140 141
  };

142
  void LoadGlobalIC(Node* vector, Node* slot,
143 144 145 146
                    const LazyNode<Context>& lazy_context,
                    const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
                    ExitPoint* exit_point,
                    ParameterMode slot_mode = SMI_PARAMETERS);
147

148 149
  // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
  // construction on common paths.
150 151
  void LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
                              ExitPoint* exit_point);
152

153
  // Loads dataX field from the DataHandler object.
154 155
  TNode<MaybeObject> LoadHandlerDataField(SloppyTNode<DataHandler> handler,
                                          int data_index);
156

157
 protected:
158
  struct StoreICParameters : public LoadICParameters {
159
    StoreICParameters(TNode<Context> context, Node* receiver, Node* name,
160
                      SloppyTNode<Object> value, Node* slot, Node* vector)
161
        : LoadICParameters(context, receiver, name, slot, vector),
162 163 164 165 166 167
          value_(value) {}

    SloppyTNode<Object> value() const { return value_; }

   private:
    SloppyTNode<Object> value_;
168 169
  };

170
  enum class LoadAccessMode { kLoad, kHas };
171
  enum class ICMode { kNonGlobalIC, kGlobalIC };
172 173
  enum ElementSupport { kOnlyProperties, kSupportElements };
  void HandleStoreICHandlerCase(
174 175
      const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
      ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
176 177 178 179 180 181
  enum StoreTransitionMapFlags {
    kCheckPrototypeValidity = 1 << 0,
    kValidateTransitionHandler = 1 << 1,
    kStoreTransitionMapFlagsMask =
        kCheckPrototypeValidity | kValidateTransitionHandler,
  };
182
  void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p,
183 184
                                             TNode<Map> transition_map,
                                             Label* miss,
185
                                             StoreTransitionMapFlags flags);
186

187
  void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
188

189
  void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield3 = nullptr);
190

191 192 193 194 195 196 197
  void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
                                         Node* descriptors,
                                         Node* descriptor_name_index,
                                         Node* details, Node* value,
                                         Label* slow,
                                         bool do_transitioning_store);

198 199
  void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
                      Node* representation, Node* value, Label* bailout);
200

201 202 203
 private:
  // Stub generation entry points.

204 205
  // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
  // logic not inlined into Ignition bytecode handlers.
206
  void LoadIC(const LoadICParameters* p);
207
  void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
208 209 210
                         TNode<HeapObject> feedback,
                         TVariable<MaybeObject>* var_handler, Label* if_handler,
                         Label* miss, ExitPoint* exit_point);
211

212 213
  TNode<Object> LoadDescriptorValue(TNode<Map> map,
                                    TNode<IntPtrT> descriptor_entry);
214
  TNode<MaybeObject> LoadDescriptorValueOrFieldType(
215
      TNode<Map> map, TNode<IntPtrT> descriptor_entry);
216

217
  void LoadIC_Uninitialized(const LoadICParameters* p);
218

219
  void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
220
  void KeyedLoadICGeneric(const LoadICParameters* p);
221 222
  void KeyedLoadICPolymorphicName(const LoadICParameters* p,
                                  LoadAccessMode access_mode);
223
  void StoreIC(const StoreICParameters* p);
224
  void StoreGlobalIC(const StoreICParameters* p);
225 226
  void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
                                      ExitPoint* exit_point, Label* miss);
227
  void KeyedStoreIC(const StoreICParameters* p);
228
  void StoreInArrayLiteralIC(const StoreICParameters* p);
229 230 231 232

  // IC dispatcher behavior.

  // Checks monomorphic case. Returns {feedback} entry of the vector.
233 234 235 236
  TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector,
                                        Node* receiver_map, Label* if_handler,
                                        TVariable<MaybeObject>* var_handler,
                                        Label* if_miss);
237 238 239
  void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
                             Label* if_handler,
                             TVariable<MaybeObject>* var_handler,
240
                             Label* if_miss);
241 242 243

  // LoadIC implementation.
  void HandleLoadICHandlerCase(
244
      const LazyLoadICParameters* p, TNode<Object> handler, Label* miss,
245
      ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
246
      OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
247 248
      ElementSupport support_elements = kOnlyProperties,
      LoadAccessMode access_mode = LoadAccessMode::kLoad);
249

250
  void HandleLoadICSmiHandlerCase(const LazyLoadICParameters* p, Node* holder,
251 252
                                  SloppyTNode<Smi> smi_handler,
                                  SloppyTNode<Object> handler, Label* miss,
253
                                  ExitPoint* exit_point,
254
                                  OnNonExistent on_nonexistent,
255 256
                                  ElementSupport support_elements,
                                  LoadAccessMode access_mode);
257

258
  void HandleLoadICProtoHandler(const LazyLoadICParameters* p, Node* handler,
259 260
                                Variable* var_holder, Variable* var_smi_handler,
                                Label* if_smi_handler, Label* miss,
261 262
                                ExitPoint* exit_point, ICMode ic_mode,
                                LoadAccessMode access_mode);
263

264
  void HandleLoadCallbackProperty(const LazyLoadICParameters* p,
265 266 267 268
                                  TNode<JSObject> holder,
                                  TNode<WordT> handler_word,
                                  ExitPoint* exit_point);

269
  void HandleLoadAccessor(const LazyLoadICParameters* p,
270 271 272 273
                          TNode<CallHandlerInfo> call_handler_info,
                          TNode<WordT> handler_word, TNode<DataHandler> handler,
                          TNode<IntPtrT> handler_kind, ExitPoint* exit_point);

274 275 276 277
  void HandleLoadField(Node* holder, Node* handler_word,
                       Variable* var_double_value, Label* rebox_double,
                       ExitPoint* exit_point);

278 279 280
  void EmitAccessCheck(Node* expected_native_context, Node* context,
                       Node* receiver, Label* can_access, Label* miss);

281
  void HandleLoadICSmiHandlerLoadNamedCase(
282
      const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
283 284 285 286 287
      TNode<WordT> handler_word, Label* rebox_double,
      Variable* var_double_value, SloppyTNode<Object> handler, Label* miss,
      ExitPoint* exit_point, OnNonExistent on_nonexistent,
      ElementSupport support_elements);

288
  void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p,
289 290 291 292
                                          Node* holder,
                                          TNode<IntPtrT> handler_kind,
                                          Label* miss, ExitPoint* exit_point);

293 294
  // LoadGlobalIC implementation.

295 296 297 298 299 300 301 302 303 304 305 306
  void LoadGlobalIC_TryPropertyCellCase(
      TNode<FeedbackVector> vector, Node* slot,
      const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
      Label* try_handler, Label* miss,
      ParameterMode slot_mode = SMI_PARAMETERS);

  void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot,
                                   const LazyNode<Context>& lazy_context,
                                   const LazyNode<Name>& lazy_name,
                                   TypeofMode typeof_mode,
                                   ExitPoint* exit_point, Label* miss,
                                   ParameterMode slot_mode);
307 308 309

  // StoreIC implementation.

310 311 312
  void HandleStoreICProtoHandler(const StoreICParameters* p,
                                 TNode<StoreHandler> handler, Label* miss,
                                 ICMode ic_mode,
313
                                 ElementSupport support_elements);
314
  void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
315
                                   Node* value, Label* miss);
316 317
  void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
                                 Representation representation, Node* value,
318
                                 Label* miss);
319

320
  void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss);
321 322 323
  void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
                                       Node* handler_word);

324
  void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
325
                          ElementSupport support_elements);
326

327 328 329
  void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
                           Node* handler_word);

330 331 332
  // KeyedLoadIC_Generic implementation.

  void GenericElementLoad(Node* receiver, Node* receiver_map,
333 334
                          SloppyTNode<Int32T> instance_type, Node* index,
                          Label* slow);
335

336
  enum UseStubCache { kUseStubCache, kDontUseStubCache };
337
  void GenericPropertyLoad(Node* receiver, Node* receiver_map,
338 339
                           SloppyTNode<Int32T> instance_type,
                           const LoadICParameters* p, Label* slow,
340
                           UseStubCache use_stub_cache = kUseStubCache);
341

342 343
  // Low-level helpers.

344 345 346
  using OnCodeHandler = std::function<void(Node* code_handler)>;
  using OnFoundOnReceiver =
      std::function<void(Node* properties, Node* name_index)>;
347 348 349 350 351 352 353

  template <typename ICHandler, typename ICParameters>
  Node* HandleProtoHandler(const ICParameters* p, Node* handler,
                           const OnCodeHandler& on_code_handler,
                           const OnFoundOnReceiver& on_found_on_receiver,
                           Label* miss, ICMode ic_mode);

354
  Node* PrepareValueForStore(Node* handler_word, Node* holder,
355 356
                             Representation representation, Node* value,
                             Label* bailout);
357

358 359 360
  // Extends properties backing store by JSObject::kFieldsAdded elements,
  // returns updated properties backing store.
  Node* ExtendPropertiesBackingStore(Node* object, Node* index);
361 362 363

  void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
                       Representation representation, Node* value,
364
                       Label* bailout);
365 366 367 368

  void EmitFastElementsBoundsCheck(Node* object, Node* elements,
                                   Node* intptr_index,
                                   Node* is_jsarray_condition, Label* miss);
369
  void EmitElementLoad(Node* object, Node* elements_kind,
370 371 372
                       SloppyTNode<IntPtrT> key, Node* is_jsarray_condition,
                       Label* if_hole, Label* rebox_double,
                       Variable* var_double_value,
373
                       Label* unimplemented_elements_kind, Label* out_of_bounds,
374 375
                       Label* miss, ExitPoint* exit_point,
                       LoadAccessMode access_mode = LoadAccessMode::kLoad);
376 377
  void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
                                    Label* miss);
378
  TNode<BoolT> IsPropertyDetailsConst(Node* details);
379 380 381 382 383 384 385 386 387 388 389 390

  // Stub cache access helpers.

  // This enum is used here as a replacement for StubCache::Table to avoid
  // including stub cache header.
  enum StubCacheTable : int;

  Node* StubCachePrimaryOffset(Node* name, Node* map);
  Node* StubCacheSecondaryOffset(Node* name, Node* seed);

  void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
                              Node* entry_offset, Node* name, Node* map,
391 392
                              Label* if_handler,
                              TVariable<MaybeObject>* var_handler,
393
                              Label* if_miss);
394 395
};

396 397 398 399 400
// Abstraction over direct and indirect exit points. Direct exits correspond to
// tailcalls and Return, while indirect exits store the result in a variable
// and then jump to an exit label.
class ExitPoint {
 private:
401 402 403
  using Node = compiler::Node;
  using CodeAssemblerLabel = compiler::CodeAssemblerLabel;
  using CodeAssemblerVariable = compiler::CodeAssemblerVariable;
404 405

 public:
406
  using IndirectReturnHandler = std::function<void(Node* result)>;
407

408
  explicit ExitPoint(CodeStubAssembler* assembler)
409 410 411 412 413 414
      : ExitPoint(assembler, nullptr) {}

  ExitPoint(CodeStubAssembler* assembler,
            const IndirectReturnHandler& indirect_return_handler)
      : asm_(assembler), indirect_return_handler_(indirect_return_handler) {}

415 416
  ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
            CodeAssemblerVariable* var_result)
417 418 419 420
      : ExitPoint(assembler, [=](Node* result) {
          var_result->Bind(result);
          assembler->Goto(out);
        }) {
421 422 423 424 425 426 427 428 429
    DCHECK_EQ(out != nullptr, var_result != nullptr);
  }

  template <class... TArgs>
  void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
                         TArgs... args) {
    if (IsDirect()) {
      asm_->TailCallRuntime(function, context, args...);
    } else {
430
      indirect_return_handler_(asm_->CallRuntime(function, context, args...));
431 432 433 434 435 436 437 438
    }
  }

  template <class... TArgs>
  void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
    if (IsDirect()) {
      asm_->TailCallStub(callable, context, args...);
    } else {
439
      indirect_return_handler_(asm_->CallStub(callable, context, args...));
440 441 442 443 444 445 446 447 448
    }
  }

  template <class... TArgs>
  void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
                      Node* context, TArgs... args) {
    if (IsDirect()) {
      asm_->TailCallStub(descriptor, target, context, args...);
    } else {
449 450
      indirect_return_handler_(
          asm_->CallStub(descriptor, target, context, args...));
451 452 453 454 455 456 457
    }
  }

  void Return(Node* const result) {
    if (IsDirect()) {
      asm_->Return(result);
    } else {
458
      indirect_return_handler_(result);
459 460 461
    }
  }

462
  bool IsDirect() const { return !indirect_return_handler_; }
463 464 465

 private:
  CodeStubAssembler* const asm_;
466
  IndirectReturnHandler indirect_return_handler_;
467 468
};

469 470 471
}  // namespace internal
}  // namespace v8

472
#endif  // V8_IC_ACCESSOR_ASSEMBLER_H_