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
10namespace v8 {
11namespace internal {
12
13void 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
46void 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
65bool 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
76void CallInterfaceDescriptorData::Reset() {
77  delete[] machine_types_;
78  machine_types_ = nullptr;
79  register_params_ = nullptr;
80}
81
82// static
83CallInterfaceDescriptorData
84    CallDescriptors::call_descriptor_data_[NUMBER_OF_DESCRIPTORS];
85
86void 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
100void CallDescriptors::TearDown() {
101  for (CallInterfaceDescriptorData& data : call_descriptor_data_) {
102    data.Reset();
103  }
104}
105
106const 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
120bool 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
129template <typename DerivedDescriptor>
130void StaticCallInterfaceDescriptor<DerivedDescriptor>::Verify(
131    CallInterfaceDescriptorData* data) {}
132// static
133void 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