blob: 5f7d09fb2ab07096baa4ffaed307aea272e91b4a [file] [log] [blame]
// 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