| // Copyright 2012 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. |
| |
| #include "src/codegen/interface-descriptors.h" |
| |
| #include "src/codegen/interface-descriptors-inl.h" |
| #include "src/codegen/macro-assembler.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| void CallInterfaceDescriptorData::InitializeRegisters( |
| Flags flags, int return_count, int parameter_count, |
| StackArgumentOrder stack_order, int register_parameter_count, |
| const Register* registers) { |
| DCHECK(!IsInitializedTypes()); |
| |
| #ifdef DEBUG |
| { |
| // Make sure that the registers are all valid, and don't alias each other. |
| RegList reglist; |
| for (int i = 0; i < register_parameter_count; ++i) { |
| Register reg = registers[i]; |
| DCHECK(reg.is_valid()); |
| DCHECK(!reglist.has(reg)); |
| DCHECK_NE(reg, kRootRegister); |
| #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE |
| DCHECK_NE(reg, kPtrComprCageBaseRegister); |
| #endif |
| reglist.set(reg); |
| } |
| } |
| #endif |
| |
| flags_ = flags; |
| stack_order_ = stack_order; |
| return_count_ = return_count; |
| param_count_ = parameter_count; |
| register_param_count_ = register_parameter_count; |
| |
| // The caller owns the the registers array, so we just set the pointer. |
| register_params_ = registers; |
| } |
| |
| void CallInterfaceDescriptorData::InitializeTypes( |
| const MachineType* machine_types, int machine_types_length) { |
| DCHECK(IsInitializedRegisters()); |
| const int types_length = return_count_ + param_count_; |
| |
| // Machine types are either fully initialized or null. |
| if (machine_types == nullptr) { |
| machine_types_ = |
| NewArray<MachineType>(types_length, MachineType::AnyTagged()); |
| } else { |
| DCHECK_EQ(machine_types_length, types_length); |
| machine_types_ = NewArray<MachineType>(types_length); |
| for (int i = 0; i < types_length; i++) machine_types_[i] = machine_types[i]; |
| } |
| |
| if (!(flags_ & kNoStackScan)) DCHECK(AllStackParametersAreTagged()); |
| } |
| |
| #ifdef DEBUG |
| bool CallInterfaceDescriptorData::AllStackParametersAreTagged() const { |
| DCHECK(IsInitialized()); |
| const int types_length = return_count_ + param_count_; |
| const int first_stack_param = return_count_ + register_param_count_; |
| for (int i = first_stack_param; i < types_length; i++) { |
| if (!machine_types_[i].IsTagged()) return false; |
| } |
| return true; |
| } |
| #endif // DEBUG |
| |
| void CallInterfaceDescriptorData::Reset() { |
| delete[] machine_types_; |
| machine_types_ = nullptr; |
| register_params_ = nullptr; |
| } |
| |
| // static |
| CallInterfaceDescriptorData |
| CallDescriptors::call_descriptor_data_[NUMBER_OF_DESCRIPTORS]; |
| |
| void CallDescriptors::InitializeOncePerProcess() { |
| #define INTERFACE_DESCRIPTOR(name, ...) \ |
| name##Descriptor().Initialize(&call_descriptor_data_[CallDescriptors::name]); |
| INTERFACE_DESCRIPTOR_LIST(INTERFACE_DESCRIPTOR) |
| #undef INTERFACE_DESCRIPTOR |
| |
| DCHECK(ContextOnlyDescriptor{}.HasContextParameter()); |
| DCHECK(!NoContextDescriptor{}.HasContextParameter()); |
| DCHECK(!AllocateDescriptor{}.HasContextParameter()); |
| DCHECK(!AbortDescriptor{}.HasContextParameter()); |
| DCHECK(!WasmFloat32ToNumberDescriptor{}.HasContextParameter()); |
| DCHECK(!WasmFloat64ToNumberDescriptor{}.HasContextParameter()); |
| } |
| |
| void CallDescriptors::TearDown() { |
| for (CallInterfaceDescriptorData& data : call_descriptor_data_) { |
| data.Reset(); |
| } |
| } |
| |
| const char* CallInterfaceDescriptor::DebugName() const { |
| CallDescriptors::Key key = CallDescriptors::GetKey(data_); |
| switch (key) { |
| #define DEF_CASE(name, ...) \ |
| case CallDescriptors::name: \ |
| return #name " Descriptor"; |
| INTERFACE_DESCRIPTOR_LIST(DEF_CASE) |
| #undef DEF_CASE |
| case CallDescriptors::NUMBER_OF_DESCRIPTORS: |
| break; |
| } |
| return ""; |
| } |
| |
| bool CallInterfaceDescriptor::IsValidFloatParameterRegister(Register reg) { |
| #if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) |
| return reg.code() % 2 == 0; |
| #else |
| return true; |
| #endif |
| } |
| |
| #if DEBUG |
| template <typename DerivedDescriptor> |
| void StaticCallInterfaceDescriptor<DerivedDescriptor>::Verify( |
| CallInterfaceDescriptorData* data) {} |
| // static |
| void WriteBarrierDescriptor::Verify(CallInterfaceDescriptorData* data) { |
| DCHECK(!AreAliased(ObjectRegister(), SlotAddressRegister(), ValueRegister())); |
| // The default parameters should not clobber vital registers in order to |
| // reduce code size: |
| DCHECK(!AreAliased(ObjectRegister(), kContextRegister, |
| kInterpreterAccumulatorRegister)); |
| DCHECK(!AreAliased(SlotAddressRegister(), kContextRegister, |
| kInterpreterAccumulatorRegister)); |
| DCHECK(!AreAliased(ValueRegister(), kContextRegister, |
| kInterpreterAccumulatorRegister)); |
| DCHECK(!AreAliased(SlotAddressRegister(), kJavaScriptCallNewTargetRegister)); |
| // Coincidental: to make calling from various builtins easier. |
| DCHECK_EQ(ObjectRegister(), kJSFunctionRegister); |
| // We need a certain set of registers by default: |
| RegList allocatable_regs = data->allocatable_registers(); |
| DCHECK(allocatable_regs.has(kContextRegister)); |
| DCHECK(allocatable_regs.has(kReturnRegister0)); |
| VerifyArgumentRegisterCount(data, 4); |
| } |
| #endif // DEBUG |
| |
| } // namespace internal |
| } // namespace v8 |