V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
code-stubs.h
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_CODE_STUBS_H_
6 #define V8_CODE_STUBS_H_
7 
8 #include "src/frames.h"
9 #include "src/interface-descriptors.h"
10 #include "src/type-hints.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // Forward declarations.
16 class CodeStubDescriptor;
17 class Isolate;
18 class MacroAssembler;
19 class TurboAssembler;
20 namespace compiler {
21 class CodeAssemblerState;
22 }
23 
24 // List of code stubs used on all platforms.
25 #define CODE_STUB_LIST_ALL_PLATFORMS(V) \
26  /* --- PlatformCodeStubs --- */ \
27  V(CallApiCallback) \
28  V(CallApiGetter) \
29  V(JSEntry)
30 
31 // List of code stubs only used on ARM 32 bits platforms.
32 #if V8_TARGET_ARCH_ARM
33 #define CODE_STUB_LIST_ARM(V) V(DirectCEntry)
34 
35 #else
36 #define CODE_STUB_LIST_ARM(V)
37 #endif
38 
39 // List of code stubs only used on ARM 64 bits platforms.
40 #if V8_TARGET_ARCH_ARM64
41 #define CODE_STUB_LIST_ARM64(V) V(DirectCEntry)
42 
43 #else
44 #define CODE_STUB_LIST_ARM64(V)
45 #endif
46 
47 // List of code stubs only used on PPC platforms.
48 #ifdef V8_TARGET_ARCH_PPC
49 #define CODE_STUB_LIST_PPC(V) V(DirectCEntry)
50 #else
51 #define CODE_STUB_LIST_PPC(V)
52 #endif
53 
54 // List of code stubs only used on MIPS platforms.
55 #if V8_TARGET_ARCH_MIPS
56 #define CODE_STUB_LIST_MIPS(V) V(DirectCEntry)
57 #elif V8_TARGET_ARCH_MIPS64
58 #define CODE_STUB_LIST_MIPS(V) V(DirectCEntry)
59 #else
60 #define CODE_STUB_LIST_MIPS(V)
61 #endif
62 
63 // List of code stubs only used on S390 platforms.
64 #ifdef V8_TARGET_ARCH_S390
65 #define CODE_STUB_LIST_S390(V) V(DirectCEntry)
66 #else
67 #define CODE_STUB_LIST_S390(V)
68 #endif
69 
70 // Combined list of code stubs.
71 #define CODE_STUB_LIST(V) \
72  CODE_STUB_LIST_ALL_PLATFORMS(V) \
73  CODE_STUB_LIST_ARM(V) \
74  CODE_STUB_LIST_ARM64(V) \
75  CODE_STUB_LIST_PPC(V) \
76  CODE_STUB_LIST_MIPS(V) \
77  CODE_STUB_LIST_S390(V)
78 
79 static const int kHasReturnedMinusZeroSentinel = 1;
80 
81 class CodeStub : public ZoneObject {
82  public:
83  enum Major {
84  // TODO(mvstanton): eliminate the NoCache key by getting rid
85  // of the non-monomorphic-cache.
86  NoCache = 0, // marker for stubs that do custom caching]
87 #define DEF_ENUM(name) name,
88  CODE_STUB_LIST(DEF_ENUM)
89 #undef DEF_ENUM
90  NUMBER_OF_IDS
91  };
92 
93  // Retrieve the code for the stub. Generate the code if needed.
94  Handle<Code> GetCode();
95 
96  static Major MajorKeyFromKey(uint32_t key) {
97  return static_cast<Major>(MajorKeyBits::decode(key));
98  }
99  static uint32_t MinorKeyFromKey(uint32_t key) {
100  return MinorKeyBits::decode(key);
101  }
102 
103  // Gets the major key from a code object that is a code stub or binary op IC.
104  static Major GetMajorKey(const Code code_stub);
105 
106  static uint32_t NoCacheKey() { return MajorKeyBits::encode(NoCache); }
107 
108  static const char* MajorName(Major major_key);
109 
110  explicit CodeStub(Isolate* isolate) : minor_key_(0), isolate_(isolate) {}
111  virtual ~CodeStub() = default;
112 
113  // Some stubs put untagged junk on the stack that cannot be scanned by the
114  // GC. This means that we must be statically sure that no GC can occur while
115  // they are running. If that is the case they should override this to return
116  // true, which will cause an assertion if we try to call something that can
117  // GC or if we try to put a stack frame on top of the junk, which would not
118  // result in a traversable stack.
119  virtual bool SometimesSetsUpAFrame() { return true; }
120 
121  // Lookup the code in the (possibly custom) cache.
122  bool FindCodeInCache(Code* code_out);
123 
124  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() const = 0;
125 
126  virtual int GetStackParameterCount() const {
127  return GetCallInterfaceDescriptor().GetStackParameterCount();
128  }
129 
130  static void InitializeDescriptor(Isolate* isolate, uint32_t key,
131  CodeStubDescriptor* desc);
132 
133  static MaybeHandle<Code> GetCode(Isolate* isolate, uint32_t key);
134 
135  // Returns information for computing the number key.
136  virtual Major MajorKey() const = 0;
137  uint32_t MinorKey() const { return minor_key_; }
138 
139  friend std::ostream& operator<<(std::ostream& os, const CodeStub& s) {
140  s.PrintName(os);
141  return os;
142  }
143 
144  Isolate* isolate() const { return isolate_; }
145  void set_isolate(Isolate* isolate) {
146  DCHECK_NOT_NULL(isolate);
147  DCHECK(isolate_ == nullptr || isolate_ == isolate);
148  isolate_ = isolate;
149  }
150 
151  void DeleteStubFromCacheForTesting();
152 
153  protected:
154  CodeStub(uint32_t key, Isolate* isolate)
155  : minor_key_(MinorKeyFromKey(key)), isolate_(isolate) {}
156 
157  // Generates the assembler code for the stub.
158  virtual Handle<Code> GenerateCode() = 0;
159 
160  // Returns whether the code generated for this stub needs to be allocated as
161  // a fixed (non-moveable) code object.
162  // TODO(jgruber): Only required by DirectCEntryStub. Can be removed when/if
163  // that is ported to a builtin.
164  virtual Movability NeedsImmovableCode() { return kMovable; }
165 
166  virtual void PrintName(std::ostream& os) const; // NOLINT
167  virtual void PrintBaseName(std::ostream& os) const; // NOLINT
168  virtual void PrintState(std::ostream& os) const { ; } // NOLINT
169 
170  // Computes the key based on major and minor.
171  uint32_t GetKey() {
172  DCHECK(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
173  return MinorKeyBits::encode(MinorKey()) | MajorKeyBits::encode(MajorKey());
174  }
175 
176  uint32_t minor_key_;
177 
178  private:
179  // Perform bookkeeping required after code generation when stub code is
180  // initially generated.
181  void RecordCodeGeneration(Handle<Code> code);
182 
183  // We use this dispatch to statically instantiate the correct code stub for
184  // the given stub key and call the passed function with that code stub.
185  typedef void (*DispatchedCall)(CodeStub* stub, void** value_out);
186  static void Dispatch(Isolate* isolate, uint32_t key, void** value_out,
187  DispatchedCall call);
188 
189  static void GetCodeDispatchCall(CodeStub* stub, void** value_out);
190 
191  STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits));
192  class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {};
193  class MinorKeyBits: public BitField<uint32_t,
194  kStubMajorKeyBits, kStubMinorKeyBits> {}; // NOLINT
195 
196  friend class BreakPointIterator;
197 
198  Isolate* isolate_;
199 };
200 
201 
202 #define DEFINE_CODE_STUB_BASE(NAME, SUPER) \
203  public: \
204  NAME(uint32_t key, Isolate* isolate) : SUPER(key, isolate) {} \
205  \
206  private: \
207  DISALLOW_COPY_AND_ASSIGN(NAME)
208 
209 
210 #define DEFINE_CODE_STUB(NAME, SUPER) \
211  public: \
212  inline Major MajorKey() const override { return NAME; }; \
213  \
214  DEFINE_CODE_STUB_BASE(NAME##Stub, SUPER)
215 
216 
217 #define DEFINE_PLATFORM_CODE_STUB(NAME, SUPER) \
218  private: \
219  void Generate(MacroAssembler* masm) override; \
220  DEFINE_CODE_STUB(NAME, SUPER)
221 
222 
223 #define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER) \
224  public: \
225  void GenerateAssembly(compiler::CodeAssemblerState* state) const override; \
226  DEFINE_CODE_STUB(NAME, SUPER)
227 
228 #define DEFINE_CALL_INTERFACE_DESCRIPTOR(NAME) \
229  public: \
230  typedef NAME##Descriptor Descriptor; \
231  CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
232  return Descriptor(); \
233  }
234 
235 // There are some code stubs we just can't describe right now with a
236 // CallInterfaceDescriptor. Isolate behavior for those cases with this macro.
237 // An attempt to retrieve a descriptor will fail.
238 #define DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR() \
239  public: \
240  CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
241  UNREACHABLE(); \
242  return CallInterfaceDescriptor(); \
243  }
244 
245 
246 class PlatformCodeStub : public CodeStub {
247  public:
248  // Retrieve the code for the stub. Generate the code if needed.
249  Handle<Code> GenerateCode() override;
250 
251  protected:
252  explicit PlatformCodeStub(Isolate* isolate) : CodeStub(isolate) {}
253 
254  // Generates the assembler code for the stub.
255  virtual void Generate(MacroAssembler* masm) = 0;
256 
257  // Generates the exception handler table for the stub.
258  virtual int GenerateHandlerTable(MacroAssembler* masm);
259 
260  DEFINE_CODE_STUB_BASE(PlatformCodeStub, CodeStub);
261 };
262 
263 
264 enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };
265 
266 
268  public:
269  explicit CodeStubDescriptor(CodeStub* stub);
270 
271  CodeStubDescriptor(Isolate* isolate, uint32_t stub_key);
272 
273  void Initialize(Address deoptimization_handler = kNullAddress,
274  int hint_stack_parameter_count = -1,
275  StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE);
276  void Initialize(Register stack_parameter_count,
277  Address deoptimization_handler = kNullAddress,
278  int hint_stack_parameter_count = -1,
279  StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE);
280 
281  void SetMissHandler(Runtime::FunctionId id) {
282  miss_handler_id_ = id;
283  miss_handler_ = ExternalReference::Create(Runtime::FunctionForId(id));
284  has_miss_handler_ = true;
285  // Our miss handler infrastructure doesn't currently support
286  // variable stack parameter counts.
287  DCHECK(!stack_parameter_count_.is_valid());
288  }
289 
290  void set_call_descriptor(CallInterfaceDescriptor d) {
291  call_descriptor_ = std::move(d);
292  }
293  CallInterfaceDescriptor call_descriptor() const { return call_descriptor_; }
294 
295  int GetRegisterParameterCount() const {
296  return call_descriptor().GetRegisterParameterCount();
297  }
298 
299  int GetStackParameterCount() const {
300  return call_descriptor().GetStackParameterCount();
301  }
302 
303  int GetParameterCount() const {
304  return call_descriptor().GetParameterCount();
305  }
306 
307  Register GetRegisterParameter(int index) const {
308  return call_descriptor().GetRegisterParameter(index);
309  }
310 
311  MachineType GetParameterType(int index) const {
312  return call_descriptor().GetParameterType(index);
313  }
314 
315  ExternalReference miss_handler() const {
316  DCHECK(has_miss_handler_);
317  return miss_handler_;
318  }
319 
320  Runtime::FunctionId miss_handler_id() const {
321  DCHECK(has_miss_handler_);
322  return miss_handler_id_;
323  }
324 
325  bool has_miss_handler() const {
326  return has_miss_handler_;
327  }
328 
329  int GetHandlerParameterCount() const {
330  int params = GetParameterCount();
331  if (PassesArgumentsToDeoptimizationHandler()) {
332  params += 1;
333  }
334  return params;
335  }
336 
337  int hint_stack_parameter_count() const { return hint_stack_parameter_count_; }
338  Register stack_parameter_count() const { return stack_parameter_count_; }
339  StubFunctionMode function_mode() const { return function_mode_; }
340  Address deoptimization_handler() const { return deoptimization_handler_; }
341 
342  private:
343  bool PassesArgumentsToDeoptimizationHandler() const {
344  return stack_parameter_count_.is_valid();
345  }
346 
347  Isolate* isolate_;
348  CallInterfaceDescriptor call_descriptor_;
349  Register stack_parameter_count_;
350  // If hint_stack_parameter_count_ > 0, the code stub can optimize the
351  // return sequence. Default value is -1, which means it is ignored.
352  int hint_stack_parameter_count_;
353  StubFunctionMode function_mode_;
354 
355  Address deoptimization_handler_;
356 
357  ExternalReference miss_handler_;
358  Runtime::FunctionId miss_handler_id_;
359  bool has_miss_handler_;
360 };
361 
362 } // namespace internal
363 } // namespace v8
364 
365 #if V8_TARGET_ARCH_IA32
366 #elif V8_TARGET_ARCH_X64
367 #elif V8_TARGET_ARCH_ARM64
368 #include "src/arm64/code-stubs-arm64.h"
369 #elif V8_TARGET_ARCH_ARM
370 #include "src/arm/code-stubs-arm.h"
371 #elif V8_TARGET_ARCH_PPC
372 #include "src/ppc/code-stubs-ppc.h"
373 #elif V8_TARGET_ARCH_MIPS
374 #include "src/mips/code-stubs-mips.h"
375 #elif V8_TARGET_ARCH_MIPS64
376 #include "src/mips64/code-stubs-mips64.h"
377 #elif V8_TARGET_ARCH_S390
378 #include "src/s390/code-stubs-s390.h"
379 #else
380 #error Unsupported target architecture.
381 #endif
382 
383 namespace v8 {
384 namespace internal {
385 
386 class CommonStoreModeBits : public BitField<KeyedAccessStoreMode, 0, 3> {};
387 
389  public:
390  static const int kArgBits = 7;
391  static const int kArgMax = (1 << kArgBits) - 1;
392 
393  CallApiCallbackStub(Isolate* isolate, int argc)
394  : PlatformCodeStub(isolate) {
395  CHECK_LE(0, argc); // The argc in {0, 1} cases are covered by builtins.
396  CHECK_LE(argc, kArgMax);
397  minor_key_ = ArgumentBits::encode(argc);
398  }
399 
400  private:
401  int argc() const { return ArgumentBits::decode(minor_key_); }
402 
403  class ArgumentBits : public BitField<int, 0, kArgBits> {};
404 
405  friend class Builtins; // For generating the related builtin.
406 
407  DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiCallback);
408  DEFINE_PLATFORM_CODE_STUB(CallApiCallback, PlatformCodeStub);
409 };
410 
411 // TODO(jgruber): This stub only exists to avoid code duplication between
412 // code-stubs-<arch>.cc and builtins-<arch>.cc. If CallApiCallbackStub is ever
413 // completely removed, CallApiGetterStub can also be deleted.
415  private:
416  // For generating the related builtin.
417  explicit CallApiGetterStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
418  friend class Builtins;
419 
420  DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiGetter);
421  DEFINE_PLATFORM_CODE_STUB(CallApiGetter, PlatformCodeStub);
422 };
423 
425  public:
426  enum class SpecialTarget { kNone, kRunMicrotasks };
427  JSEntryStub(Isolate* isolate, StackFrame::Type type)
428  : PlatformCodeStub(isolate) {
429  DCHECK(type == StackFrame::ENTRY || type == StackFrame::CONSTRUCT_ENTRY);
430  minor_key_ = StackFrameTypeBits::encode(type) |
431  SpecialTargetBits::encode(SpecialTarget::kNone);
432  }
433 
434  JSEntryStub(Isolate* isolate, SpecialTarget target)
435  : PlatformCodeStub(isolate) {
436  minor_key_ = StackFrameTypeBits::encode(StackFrame::ENTRY) |
437  SpecialTargetBits::encode(target);
438  }
439 
440  private:
441  int GenerateHandlerTable(MacroAssembler* masm) override;
442 
443  void PrintName(std::ostream& os) const override { // NOLINT
444  os << (type() == StackFrame::ENTRY ? "JSEntryStub"
445  : "JSConstructEntryStub");
446  }
447 
448  StackFrame::Type type() const {
449  return StackFrameTypeBits::decode(minor_key_);
450  }
451 
452  SpecialTarget special_target() const {
453  return SpecialTargetBits::decode(minor_key_);
454  }
455 
456  Handle<Code> EntryTrampoline() {
457  switch (special_target()) {
458  case SpecialTarget::kNone:
459  return (type() == StackFrame::CONSTRUCT_ENTRY)
460  ? BUILTIN_CODE(isolate(), JSConstructEntryTrampoline)
461  : BUILTIN_CODE(isolate(), JSEntryTrampoline);
462  case SpecialTarget::kRunMicrotasks:
463  return BUILTIN_CODE(isolate(), RunMicrotasks);
464  }
465  UNREACHABLE();
466  return Handle<Code>();
467  }
468 
469  class StackFrameTypeBits : public BitField<StackFrame::Type, 0, 5> {};
470  class SpecialTargetBits
471  : public BitField<SpecialTarget, StackFrameTypeBits::kNext, 1> {};
472 
473  int handler_offset_;
474 
475  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
476  DEFINE_PLATFORM_CODE_STUB(JSEntry, PlatformCodeStub);
477 };
478 
479 #undef DEFINE_CALL_INTERFACE_DESCRIPTOR
480 #undef DEFINE_PLATFORM_CODE_STUB
481 #undef DEFINE_CODE_STUB
482 #undef DEFINE_CODE_STUB_BASE
483 
484 } // namespace internal
485 } // namespace v8
486 
487 #endif // V8_CODE_STUBS_H_
Definition: libplatform.h:13