v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
interface-descriptors-inl.h
Go to the documentation of this file.
1// Copyright 2021 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_CODEGEN_INTERFACE_DESCRIPTORS_INL_H_
6#define V8_CODEGEN_INTERFACE_DESCRIPTORS_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include <utility>
12
13#include "src/base/logging.h"
15#if V8_ENABLE_WEBASSEMBLY
17#endif
18
19#if V8_TARGET_ARCH_X64
21#elif V8_TARGET_ARCH_ARM64
23#elif V8_TARGET_ARCH_IA32
25#elif V8_TARGET_ARCH_ARM
27#elif V8_TARGET_ARCH_PPC64
29#elif V8_TARGET_ARCH_S390X
31#elif V8_TARGET_ARCH_MIPS64
33#elif V8_TARGET_ARCH_LOONG64
35#elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64
37#else
38#error Unsupported target architecture.
39#endif
40
41namespace v8 {
42namespace internal {
43
44// static
45constexpr std::array<Register, kJSBuiltinRegisterParams>
51
52// static
53template <typename DerivedDescriptor>
57
58// static
59template <typename DerivedDescriptor>
60constexpr auto
64
65// static
66template <typename DerivedDescriptor>
67constexpr auto
71
72// static
73template <typename DerivedDescriptor>
74constexpr auto
78
79// static
80template <typename DerivedDescriptor>
84
85// static
91
92// static
96
97template <typename DerivedDescriptor>
100 // Static local copy of the Registers array, for platform-specific
101 // initialization
102 static constexpr auto registers = DerivedDescriptor::registers();
103 static constexpr auto double_registers =
104 DerivedDescriptor::double_registers();
105 static constexpr auto return_registers =
106 DerivedDescriptor::return_registers();
107 static constexpr auto return_double_registers =
108 DerivedDescriptor::return_double_registers();
109
110 // The passed pointer should be a modifiable pointer to our own data.
111 DCHECK_EQ(data, this->data());
112 DCHECK(!data->IsInitialized());
113
114 if (DerivedDescriptor::kRestrictAllocatableRegisters) {
115 data->RestrictAllocatableRegisters(registers.data(), registers.size());
116 } else {
117 DCHECK(!DerivedDescriptor::kCalleeSaveRegisters);
118 }
119
120 // Make sure the defined arrays are big enough. The arrays can be filled up
121 // with `no_reg` and `no_dreg` to pass this DCHECK.
122 DCHECK_GE(registers.size(), GetRegisterParameterCount());
123 DCHECK_GE(double_registers.size(), GetRegisterParameterCount());
124 DCHECK_GE(return_registers.size(), DerivedDescriptor::kReturnCount);
125 DCHECK_GE(return_double_registers.size(), DerivedDescriptor::kReturnCount);
126 data->InitializeRegisters(
127 DerivedDescriptor::flags(), DerivedDescriptor::kEntrypointTag,
128 DerivedDescriptor::kReturnCount, DerivedDescriptor::GetParameterCount(),
129 DerivedDescriptor::kStackArgumentOrder,
130 DerivedDescriptor::GetRegisterParameterCount(), registers.data(),
131 double_registers.data(), return_registers.data(),
132 return_double_registers.data());
133
134 // InitializeTypes is customizable by the DerivedDescriptor subclass.
135 DerivedDescriptor::InitializeTypes(data);
136
137 DCHECK(data->IsInitialized());
138 DCHECK(this->CheckFloatingPointParameters(data));
139#if DEBUG
140 DerivedDescriptor::Verify(data);
141#endif
142}
143// static
144template <typename DerivedDescriptor>
145constexpr int
147 static_assert(
148 DerivedDescriptor::kReturnCount >= 0,
149 "DerivedDescriptor subclass should override return count with a value "
150 "that is greater than or equal to 0");
151
152 return DerivedDescriptor::kReturnCount;
153}
154
155// static
156template <typename DerivedDescriptor>
157constexpr int
159 static_assert(
160 DerivedDescriptor::kParameterCount >= 0,
161 "DerivedDescriptor subclass should override parameter count with a "
162 "value that is greater than or equal to 0");
163
164 return DerivedDescriptor::kParameterCount;
165}
166
167namespace detail {
168
169// Helper trait for statically checking if a type is a std::array<Register,N>.
170template <typename T>
171struct IsRegisterArray : public std::false_type {};
172template <size_t N>
173struct IsRegisterArray<std::array<Register, N>> : public std::true_type {};
174template <>
175struct IsRegisterArray<EmptyRegisterArray> : public std::true_type {};
176
177// Helper for finding the index of the first invalid register in a register
178// array.
179template <size_t N, size_t Index>
181 static constexpr int Call(std::array<Register, N> regs) {
182 if (!std::get<Index>(regs).is_valid()) {
183 // All registers after the first invalid one have to also be invalid (this
184 // DCHECK will be checked recursively).
186 Index + 1);
187 return Index;
188 }
190 }
191};
192template <size_t N>
194 static constexpr int Call(std::array<Register, N> regs) { return N; }
195};
196template <size_t N, size_t Index = 0>
197constexpr size_t FirstInvalidRegister(std::array<Register, N> regs) {
199}
200constexpr size_t FirstInvalidRegister(EmptyRegisterArray regs) { return 0; }
201
202} // namespace detail
203
204// static
205template <typename DerivedDescriptor>
206constexpr int
208 static_assert(
209 detail::IsRegisterArray<decltype(DerivedDescriptor::registers())>::value,
210 "DerivedDescriptor subclass should define a registers() function "
211 "returning a std::array<Register>");
212
213 // The register parameter count is the minimum of:
214 // 1. The number of named parameters in the descriptor, and
215 // 2. The number of valid registers the descriptor provides with its
216 // registers() function, e.g. for {rax, rbx, no_reg} this number is 2.
217 // 3. The maximum number of register parameters allowed (
218 // kMaxBuiltinRegisterParams for most builtins,
219 // kMaxTFSBuiltinRegisterParams for TFS builtins, customizable by the
220 // subclass otherwise).
221 return std::min<int>({DerivedDescriptor::GetParameterCount(),
222 static_cast<int>(detail::FirstInvalidRegister(
223 DerivedDescriptor::registers())),
224 DerivedDescriptor::kMaxRegisterParams});
225}
226
227// static
228template <typename DerivedDescriptor>
229constexpr int
231 return DerivedDescriptor::GetParameterCount() -
232 DerivedDescriptor::GetRegisterParameterCount();
233}
234
235// static
236template <typename DerivedDescriptor>
237constexpr Register
239 DCHECK(!IsFloatingPoint(GetParameterType(i).representation()));
240 return DerivedDescriptor::registers()[i];
241}
242
243// static
244template <typename DerivedDescriptor>
245constexpr int
247 int i) {
248 return i - DerivedDescriptor::GetRegisterParameterCount();
249}
250
251// static
252template <typename DerivedDescriptor>
253constexpr MachineType
255 if constexpr (!DerivedDescriptor::kCustomMachineTypes) {
256 // If there are no custom machine types, all results and parameters are
257 // tagged.
258 return MachineType::AnyTagged();
259 } else {
260 // All varags are tagged.
261 if (DerivedDescriptor::AllowVarArgs() &&
262 i >= DerivedDescriptor::GetParameterCount()) {
263 return MachineType::AnyTagged();
264 }
265 DCHECK_LT(i, DerivedDescriptor::GetParameterCount());
266 return DerivedDescriptor::kMachineTypes
267 [DerivedDescriptor::GetReturnCount() + i];
268 }
269}
270
271// static
272template <typename DerivedDescriptor>
273constexpr DoubleRegister
275 int i) {
276 DCHECK(IsFloatingPoint(GetParameterType(i).representation()));
278 DerivedDescriptor::double_registers()[i].code());
279}
280
281// static
282constexpr Register FastNewObjectDescriptor::TargetRegister() {
283 return kJSFunctionRegister;
284}
285
286// static
290
291// static
293 return std::get<kObject>(registers());
294}
295// static
297 return std::get<kSlotAddress>(registers());
298}
299
300// static
302 return std::get<kSlotAddress + 1>(registers());
303}
304
305// static
307 Register object, Register slot_address) {
308 DCHECK(!AreAliased(object, slot_address));
309 RegList saved_registers;
310#if V8_TARGET_ARCH_X64
311 // Only push clobbered registers.
312 if (object != ObjectRegister()) saved_registers.set(ObjectRegister());
313 if (slot_address != no_reg && slot_address != SlotAddressRegister()) {
314 saved_registers.set(SlotAddressRegister());
315 }
316#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_LOONG64 || \
317 V8_TARGET_ARCH_MIPS64
318 if (object != ObjectRegister()) saved_registers.set(ObjectRegister());
319 // The slot address is always clobbered.
320 saved_registers.set(SlotAddressRegister());
321#else
322 // TODO(cbruni): Enable callee-saved registers for other platforms.
323 // This is a temporary workaround to prepare code for callee-saved registers.
324 constexpr auto allocated_registers = registers();
325 for (size_t i = 0; i < allocated_registers.size(); ++i) {
326 saved_registers.set(allocated_registers[i]);
327 }
328#endif
329 return saved_registers;
330}
331
332// static
335}
336// static
338 return std::get<kObject>(registers());
339}
340// static
341constexpr Register
343 return std::get<kSlotAddress>(registers());
344}
345// static
346constexpr Register
348 return std::get<kIndirectPointerTag>(registers());
349}
350
351// static
353 Register object, Register slot_address) {
354 DCHECK(!AreAliased(object, slot_address));
355 // This write barrier behaves identical to the generic one, except that it
356 // passes one additional parameter.
357 RegList saved_registers =
359 saved_registers.set(IndirectPointerTagRegister());
360 return saved_registers;
361}
362// static
363constexpr Register ApiGetterDescriptor::ReceiverRegister() {
364 return LoadDescriptor::ReceiverRegister();
365}
366
367// static
368constexpr Register LoadGlobalNoFeedbackDescriptor::ICKindRegister() {
370}
371
372// static
373constexpr Register LoadNoFeedbackDescriptor::ICKindRegister() {
374 return LoadGlobalNoFeedbackDescriptor::ICKindRegister();
375}
376
377#if V8_TARGET_ARCH_IA32
378// On ia32, LoadWithVectorDescriptor passes vector on the stack and thus we
379// need to choose a new register here.
380// static
381constexpr Register LoadGlobalWithVectorDescriptor::VectorRegister() {
382 static_assert(!LoadWithVectorDescriptor::VectorRegister().is_valid());
383 return LoadDescriptor::ReceiverRegister();
384}
385#else
386// static
387constexpr Register LoadGlobalWithVectorDescriptor::VectorRegister() {
388 return LoadWithVectorDescriptor::VectorRegister();
389}
390#endif
391
392// static
394 return RegisterArray(ReceiverRegister(), NameRegister(), SlotRegister());
395}
396
397// static
398constexpr auto LoadBaselineDescriptor::registers() {
400}
401
402// static
403constexpr auto LoadGlobalDescriptor::registers() {
406}
407
408// static
411}
412
413// static
415 return RegisterArray(ReceiverRegister(), NameRegister(), ValueRegister(),
416 SlotRegister());
417}
418
419// static
421 return RegisterArray(StoreDescriptor::ReceiverRegister(),
424}
425
426// static
427constexpr auto StoreBaselineDescriptor::registers() {
429}
430
431// static
432constexpr auto StoreGlobalDescriptor::registers() {
436}
437
438// static
441}
442
443// static
445 return RegisterArray(StoreDescriptor::ReceiverRegister(),
448 DefineKeyedOwnDescriptor::FlagsRegister(),
450}
451
452// static
455}
456
457// static
459 return RegisterArray(
460 LoadDescriptor::ReceiverRegister(),
461 LoadWithReceiverAndVectorDescriptor::LookupStartObjectRegister(),
463}
464
465// static
467 // TODO(v8:11421): Implement on other platforms.
468#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM || \
469 V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X || V8_TARGET_ARCH_RISCV64 || \
470 V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_LOONG64 || V8_TARGET_ARCH_RISCV32
471 return RegisterArray(
475#elif V8_TARGET_ARCH_IA32
477 return RegisterArray(
480#else
481 return DefaultRegisterArray();
482#endif
483}
484
485// static
487 // TODO(v8:11421): Implement on other platforms.
488#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 || \
489 V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X || \
490 V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_MIPS64 || \
491 V8_TARGET_ARCH_LOONG64 || V8_TARGET_ARCH_RISCV32
492 return RegisterArray(ParamsSizeRegister(), WeightRegister());
493#else
494 return DefaultRegisterArray();
495#endif
498// static
509
510// static
511constexpr auto
513#ifdef V8_ENABLE_MAGLEV
514 return RegisterArray(FlagsRegister(), FeedbackVectorRegister(),
516#else
517 return DefaultRegisterArray();
518#endif
519}
520
521// static
522constexpr Register OnStackReplacementDescriptor::MaybeTargetCodeRegister() {
523 // Picking the first register on purpose because it's convenient that this
524 // register is the same as the platform's return-value register.
525 return registers()[0];
526}
527
528// static
529constexpr Register
533
534// static
535constexpr auto VoidDescriptor::registers() { return RegisterArray(); }
536
537// static
538constexpr auto AllocateDescriptor::registers() {
540}
541
542// static
546}
548// static
552}
554// static
558}
559
560// static
562 return RegisterArray(TargetRegister(), NewTargetRegister());
563}
564
565// static
567 return RegisterArray(LoadDescriptor::ReceiverRegister(),
568 LoadDescriptor::NameRegister(), ICKindRegister());
569}
570
571// static
573 return RegisterArray(LoadDescriptor::NameRegister(), ICKindRegister());
574}
575
576// static
581
582// static
584 return RegisterArray(
585 LoadDescriptor::ReceiverRegister(), LookupStartObjectRegister(),
587 LoadWithVectorDescriptor::VectorRegister());
588}
589
590// static
595 StoreWithVectorDescriptor::VectorRegister());
596}
597
598// static
600 return RegisterArray(StoreDescriptor::ReceiverRegister(),
601 StoreDescriptor::NameRegister(), MapRegister(),
604 StoreWithVectorDescriptor::VectorRegister());
605}
606
607// static
611
612// static
616
617// static
619 return RegisterArray();
620}
621
622// static
624 return RegisterArray();
625}
626
627// static
629 return RegisterArray();
630}
631
632// static
634 return RegisterArray(LoadDescriptor::ReceiverRegister(),
636 LoadDescriptor::SlotRegister(), VectorRegister());
637}
638
639// static
641 return RegisterArray(ReceiverRegister(), NameRegister(), SlotRegister());
642}
643
644// static
646 return RegisterArray(KeyedLoadBaselineDescriptor::ReceiverRegister(),
648 EnumIndexRegister(), CacheTypeRegister(),
649 SlotRegister());
650}
651
652// static
654 return RegisterArray(
655 KeyedLoadBaselineDescriptor::ReceiverRegister(),
657 EnumeratedKeyedLoadBaselineDescriptor::EnumIndexRegister(),
660 KeyedLoadWithVectorDescriptor::VectorRegister());
661}
662
663// static
664constexpr auto KeyedLoadDescriptor::registers() {
666}
667
668// static
670 return RegisterArray(KeyedLoadBaselineDescriptor::ReceiverRegister(),
673 VectorRegister());
674}
675
676// static
678 return RegisterArray(ReceiverRegister(), NameRegister(), SlotRegister());
679}
680
681// static
683 return RegisterArray(KeyedHasICBaselineDescriptor::ReceiverRegister(),
686 VectorRegister());
687}
688
689// static
691 return RegisterArray(StoreDescriptor::ReceiverRegister(),
694 StoreDescriptor::SlotRegister(), VectorRegister());
695}
696
697// static
699 return RegisterArray(StoreDescriptor::ReceiverRegister(),
702 DefineKeyedOwnDescriptor::FlagsRegister(),
704}
705
706// static
708 return RegisterArray(ApiFunctionAddressRegister(),
711}
712
713// static
715 return RegisterArray(ActualArgumentsCountRegister(),
718}
719
720// static
722 return RegisterArray(ReceiverRegister(), HolderRegister(),
724}
725
726// static
728
729// static
730constexpr auto NoContextDescriptor::registers() { return RegisterArray(); }
731
732// static
734 return RegisterArray(ObjectRegister(), KeyRegister());
735}
736
737// static
739 // Keep the arguments on the same registers as they were in
740 // ArrayConstructorDescriptor to avoid unnecessary register moves.
741 // kFunction, kAllocationSite, kActualArgumentsCount
745}
746
747// static
749 // This descriptor must use the same set of registers as the
750 // ArrayNArgumentsConstructorDescriptor.
752}
753
754// static
756 // This descriptor must use the same set of registers as the
757 // ArrayNArgumentsConstructorDescriptor.
759}
760
761// static
765
766// static
767constexpr inline Register
769 return std::get<kWrapperBuffer>(registers());
770}
771
772// static
773constexpr inline Register
774WasmHandleStackOverflowDescriptor::FrameBaseRegister() {
775 return std::get<kFrameBase>(registers());
776}
777
779 return std::get<kGap>(registers());
780}
781
783#if V8_ENABLE_WEBASSEMBLY
785#else
786 return EmptyRegisterArray();
787#endif
788}
789
791#if V8_ENABLE_WEBASSEMBLY
793 no_reg, no_reg);
794#else
795 // An arbitrary register array so that the code compiles.
797#endif
798}
799
801#if V8_ENABLE_WEBASSEMBLY
804#else
805 // An arbitrary register array so that the code compiles.
807#endif
808}
809
810#define DEFINE_STATIC_BUILTIN_DESCRIPTOR_GETTER(Name, DescriptorName) \
811 template <> \
812 struct CallInterfaceDescriptorFor<Builtin::k##Name> { \
813 using type = DescriptorName##Descriptor; \
814 };
820#undef DEFINE_STATIC_BUILTIN_DESCRIPTOR_GETTER
821#define DEFINE_STATIC_BUILTIN_DESCRIPTOR_GETTER(Name, ...) \
822 template <> \
823 struct CallInterfaceDescriptorFor<Builtin::k##Name> { \
824 using type = Name##Descriptor; \
825 };
827#undef DEFINE_STATIC_BUILTIN_DESCRIPTOR_GETTER
828
829} // namespace internal
830} // namespace v8
831
832#endif // V8_CODEGEN_INTERFACE_DESCRIPTORS_INL_H_
#define BUILTIN_LIST_TFS(V)
#define IGNORE_BUILTIN(...)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static DEFINE_PARAMETERS_VARARGS(kActualArgumentsCount, kTopmostScriptHavingContext, kFunctionTemplateInfo) DEFINE_PARAMETER_TYPES(MachineType constexpr Register TopmostScriptHavingContextRegister()
static DEFINE_PARAMETERS_VARARGS(kApiFunctionAddress, kActualArgumentsCount, kFunctionTemplateInfo) DEFINE_PARAMETER_TYPES(MachineType constexpr Register ActualArgumentsCountRegister()
static constexpr std::array< Register, kJSBuiltinRegisterParams > DefaultJSRegisterArray()
static constexpr RegList ComputeSavedRegisters(Register object, Register slot_address=no_reg)
static constexpr MachineType AnyTagged()
constexpr void set(RegisterT reg)
static constexpr DwVfpRegister from_code(int8_t code)
static constexpr MachineType GetParameterType(int i)
static constexpr DoubleRegister GetDoubleRegisterParameter(int i)
static constexpr Register GetRegisterParameter(int i)
void Initialize(CallInterfaceDescriptorData *data)
static constexpr RegList ComputeSavedRegisters(Register object, Register slot_address=no_reg)
Handle< Code > code
#define DEFINE_STATIC_BUILTIN_DESCRIPTOR_GETTER(Name, DescriptorName)
RegListBase< RegisterT > registers
STL namespace.
constexpr size_t FirstInvalidRegister(std::array< Register, N > regs)
constexpr DoubleRegister kFpReturnRegisters[]
constexpr Register kGpParamRegisters[]
constexpr Register kGpReturnRegisters[]
constexpr Register no_reg
constexpr Register kRuntimeCallFunctionRegister
constexpr EmptyDoubleRegisterArray DoubleRegisterArray()
constexpr Register kRuntimeCallArgvRegister
constexpr Register kJavaScriptCallTargetRegister
constexpr DwVfpRegister no_dreg
constexpr int N
constexpr EmptyRegisterArray RegisterArray()
constexpr Register kJavaScriptCallArgCountRegister
constexpr bool IsFloatingPoint(MachineRepresentation rep)
constexpr Register kReturnRegister0
constexpr Register kContextRegister
V8_EXPORT_PRIVATE bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
constexpr Register kRuntimeCallArgCountRegister
constexpr Register kAllocateSizeRegister
constexpr Register kJavaScriptCallExtraArg1Register
constexpr Register kJavaScriptCallCodeStartRegister
return value
Definition map-inl.h:893
constexpr Register kJavaScriptCallDispatchHandleRegister
constexpr Register kJavaScriptCallNewTargetRegister
constexpr Register kJSFunctionRegister
constexpr Register kInterpreterBytecodeArrayRegister
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
static constexpr int Call(std::array< Register, N > regs)
static constexpr int Call(std::array< Register, N > regs)