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 #include "src/codegen/interface-descriptors.h"
6
7 #include "src/codegen/interface-descriptors-inl.h"
8 #include "src/codegen/macro-assembler.h"
9
10 namespace v8 {
11 namespace internal {
12
InitializeRegisters( Flags flags, int return_count, int parameter_count, StackArgumentOrder stack_order, int register_parameter_count, const Register* registers)13 void CallInterfaceDescriptorData::InitializeRegisters(
14 Flags flags, int return_count, int parameter_count,
15 StackArgumentOrder stack_order, int register_parameter_count,
16 const Register* registers) {
17 DCHECK(!IsInitializedTypes());
18
19 #ifdef DEBUG
20 {
21 // Make sure that the registers are all valid, and don't alias each other.
22 RegList reglist;
23 for (int i = 0; i < register_parameter_count; ++i) {
24 Register reg = registers[i];
25 DCHECK(reg.is_valid());
26 DCHECK(!reglist.has(reg));
27 DCHECK_NE(reg, kRootRegister);
28 #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
29 DCHECK_NE(reg, kPtrComprCageBaseRegister);
30 #endif
31 reglist.set(reg);
32 }
33 }
34 #endif
35
36 flags_ = flags;
37 stack_order_ = stack_order;
38 return_count_ = return_count;
39 param_count_ = parameter_count;
40 register_param_count_ = register_parameter_count;
41
42 // The caller owns the the registers array, so we just set the pointer.
43 register_params_ = registers;
44 }
45
InitializeTypes( const MachineType* machine_types, int machine_types_length)46 void CallInterfaceDescriptorData::InitializeTypes(
47 const MachineType* machine_types, int machine_types_length) {
48 DCHECK(IsInitializedRegisters());
49 const int types_length = return_count_ + param_count_;
50
51 // Machine types are either fully initialized or null.
52 if (machine_types == nullptr) {
53 machine_types_ =
54 NewArray<MachineType>(types_length, MachineType::AnyTagged());
55 } else {
56 DCHECK_EQ(machine_types_length, types_length);
57 machine_types_ = NewArray<MachineType>(types_length);
58 for (int i = 0; i < types_length; i++) machine_types_[i] = machine_types[i];
59 }
60
61 if (!(flags_ & kNoStackScan)) DCHECK(AllStackParametersAreTagged());
62 }
63
64 #ifdef DEBUG
AllStackParametersAreTagged() const65 bool CallInterfaceDescriptorData::AllStackParametersAreTagged() const {
66 DCHECK(IsInitialized());
67 const int types_length = return_count_ + param_count_;
68 const int first_stack_param = return_count_ + register_param_count_;
69 for (int i = first_stack_param; i < types_length; i++) {
70 if (!machine_types_[i].IsTagged()) return false;
71 }
72 return true;
73 }
74 #endif // DEBUG
75
Reset()76 void CallInterfaceDescriptorData::Reset() {
77 delete[] machine_types_;
78 machine_types_ = nullptr;
79 register_params_ = nullptr;
80 }
81
82 // static
83 CallInterfaceDescriptorData
84 CallDescriptors::call_descriptor_data_[NUMBER_OF_DESCRIPTORS];
85
InitializeOncePerProcess()86 void CallDescriptors::InitializeOncePerProcess() {
87 #define INTERFACE_DESCRIPTOR(name, ...) \
88 name##Descriptor().Initialize(&call_descriptor_data_[CallDescriptors::name]);
89 INTERFACE_DESCRIPTOR_LIST(INTERFACE_DESCRIPTOR)
90 #undef INTERFACE_DESCRIPTOR
91
92 DCHECK(ContextOnlyDescriptor{}.HasContextParameter());
93 DCHECK(!NoContextDescriptor{}.HasContextParameter());
94 DCHECK(!AllocateDescriptor{}.HasContextParameter());
95 DCHECK(!AbortDescriptor{}.HasContextParameter());
96 DCHECK(!WasmFloat32ToNumberDescriptor{}.HasContextParameter());
97 DCHECK(!WasmFloat64ToNumberDescriptor{}.HasContextParameter());
98 }
99
TearDown()100 void CallDescriptors::TearDown() {
101 for (CallInterfaceDescriptorData& data : call_descriptor_data_) {
102 data.Reset();
103 }
104 }
105
DebugName() const106 const char* CallInterfaceDescriptor::DebugName() const {
107 CallDescriptors::Key key = CallDescriptors::GetKey(data_);
108 switch (key) {
109 #define DEF_CASE(name, ...) \
110 case CallDescriptors::name: \
111 return #name " Descriptor";
112 INTERFACE_DESCRIPTOR_LIST(DEF_CASE)
113 #undef DEF_CASE
114 case CallDescriptors::NUMBER_OF_DESCRIPTORS:
115 break;
116 }
117 return "";
118 }
119
IsValidFloatParameterRegister(Register reg)120 bool CallInterfaceDescriptor::IsValidFloatParameterRegister(Register reg) {
121 #if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)
122 return reg.code() % 2 == 0;
123 #else
124 return true;
125 #endif
126 }
127
128 #if DEBUG
129 template <typename DerivedDescriptor>
Verify( CallInterfaceDescriptorData* data)130 void StaticCallInterfaceDescriptor<DerivedDescriptor>::Verify(
131 CallInterfaceDescriptorData* data) {}
132 // static
Verify(CallInterfaceDescriptorData* data)133 void WriteBarrierDescriptor::Verify(CallInterfaceDescriptorData* data) {
134 DCHECK(!AreAliased(ObjectRegister(), SlotAddressRegister(), ValueRegister()));
135 // The default parameters should not clobber vital registers in order to
136 // reduce code size:
137 DCHECK(!AreAliased(ObjectRegister(), kContextRegister,
138 kInterpreterAccumulatorRegister));
139 DCHECK(!AreAliased(SlotAddressRegister(), kContextRegister,
140 kInterpreterAccumulatorRegister));
141 DCHECK(!AreAliased(ValueRegister(), kContextRegister,
142 kInterpreterAccumulatorRegister));
143 DCHECK(!AreAliased(SlotAddressRegister(), kJavaScriptCallNewTargetRegister));
144 // Coincidental: to make calling from various builtins easier.
145 DCHECK_EQ(ObjectRegister(), kJSFunctionRegister);
146 // We need a certain set of registers by default:
147 RegList allocatable_regs = data->allocatable_registers();
148 DCHECK(allocatable_regs.has(kContextRegister));
149 DCHECK(allocatable_regs.has(kReturnRegister0));
150 VerifyArgumentRegisterCount(data, 4);
151 }
152 #endif // DEBUG
153
154 } // namespace internal
155 } // namespace v8
156