1 // Copyright 2014 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.
5 #ifndef V8_COMPILER_LINKAGE_IMPL_H_
6 #define V8_COMPILER_LINKAGE_IMPL_H_
8 #include "src/code-stubs.h"
9 #include "src/compiler/osr.h"
15 // TODO(titzer): replace uses of int with size_t in LinkageHelper.
16 template <typename LinkageTraits>
19 static const RegList kNoCalleeSaved = 0;
21 static void AddReturnLocations(LocationSignature::Builder* locations) {
22 DCHECK(locations->return_count_ <= 2);
23 if (locations->return_count_ > 0) {
24 locations->AddReturn(regloc(LinkageTraits::ReturnValueReg()));
26 if (locations->return_count_ > 1) {
27 locations->AddReturn(regloc(LinkageTraits::ReturnValue2Reg()));
31 // TODO(turbofan): cache call descriptors for JSFunction calls.
32 static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
33 int js_parameter_count,
34 CallDescriptor::Flags flags) {
35 const size_t return_count = 1;
36 const size_t context_count = 1;
37 const size_t parameter_count = js_parameter_count + context_count;
39 LocationSignature::Builder locations(zone, return_count, parameter_count);
40 MachineSignature::Builder types(zone, return_count, parameter_count);
43 AddReturnLocations(&locations);
44 for (size_t i = 0; i < return_count; i++) {
45 types.AddReturn(kMachAnyTagged);
48 // All parameters to JS calls go on the stack.
49 for (int i = 0; i < js_parameter_count; i++) {
50 int spill_slot_index = i - js_parameter_count;
51 locations.AddParam(stackloc(spill_slot_index));
52 types.AddParam(kMachAnyTagged);
55 locations.AddParam(regloc(LinkageTraits::ContextReg()));
56 types.AddParam(kMachAnyTagged);
58 // The target for JS function calls is the JSFunction object.
59 MachineType target_type = kMachAnyTagged;
60 // TODO(titzer): When entering into an OSR function from unoptimized code,
61 // the JSFunction is not in a register, but it is on the stack in an
62 // unaddressable spill slot. We hack this in the OSR prologue. Fix.
63 LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
64 return new (zone) CallDescriptor( // --
65 CallDescriptor::kCallJSFunction, // kind
66 target_type, // target MachineType
67 target_loc, // target location
68 types.Build(), // machine_sig
69 locations.Build(), // location_sig
70 js_parameter_count, // js_parameter_count
71 Operator::kNoProperties, // properties
72 kNoCalleeSaved, // callee-saved
78 // TODO(turbofan): cache call descriptors for runtime calls.
79 static CallDescriptor* GetRuntimeCallDescriptor(
80 Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
81 Operator::Properties properties) {
82 const size_t function_count = 1;
83 const size_t num_args_count = 1;
84 const size_t context_count = 1;
85 const size_t parameter_count = function_count +
86 static_cast<size_t>(js_parameter_count) +
87 num_args_count + context_count;
89 const Runtime::Function* function = Runtime::FunctionForId(function_id);
90 const size_t return_count = static_cast<size_t>(function->result_size);
92 LocationSignature::Builder locations(zone, return_count, parameter_count);
93 MachineSignature::Builder types(zone, return_count, parameter_count);
96 AddReturnLocations(&locations);
97 for (size_t i = 0; i < return_count; i++) {
98 types.AddReturn(kMachAnyTagged);
101 // All parameters to the runtime call go on the stack.
102 for (int i = 0; i < js_parameter_count; i++) {
103 locations.AddParam(stackloc(i - js_parameter_count));
104 types.AddParam(kMachAnyTagged);
106 // Add runtime function itself.
107 locations.AddParam(regloc(LinkageTraits::RuntimeCallFunctionReg()));
108 types.AddParam(kMachAnyTagged);
110 // Add runtime call argument count.
111 locations.AddParam(regloc(LinkageTraits::RuntimeCallArgCountReg()));
112 types.AddParam(kMachPtr);
115 locations.AddParam(regloc(LinkageTraits::ContextReg()));
116 types.AddParam(kMachAnyTagged);
118 CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
119 ? CallDescriptor::kNeedsFrameState
120 : CallDescriptor::kNoFlags;
122 // The target for runtime calls is a code object.
123 MachineType target_type = kMachAnyTagged;
124 LinkageLocation target_loc = LinkageLocation::AnyRegister();
125 return new (zone) CallDescriptor( // --
126 CallDescriptor::kCallCodeObject, // kind
127 target_type, // target MachineType
128 target_loc, // target location
129 types.Build(), // machine_sig
130 locations.Build(), // location_sig
131 js_parameter_count, // js_parameter_count
132 properties, // properties
133 kNoCalleeSaved, // callee-saved
135 function->name); // debug name
139 // TODO(all): Add support for return representations/locations to
140 // CallInterfaceDescriptor.
141 // TODO(turbofan): cache call descriptors for code stub calls.
142 static CallDescriptor* GetStubCallDescriptor(
143 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
144 int stack_parameter_count, CallDescriptor::Flags flags,
145 Operator::Properties properties, MachineType return_type) {
146 const int register_parameter_count =
147 descriptor.GetEnvironmentParameterCount();
148 const int js_parameter_count =
149 register_parameter_count + stack_parameter_count;
150 const int context_count = 1;
151 const size_t return_count = 1;
152 const size_t parameter_count =
153 static_cast<size_t>(js_parameter_count + context_count);
155 LocationSignature::Builder locations(zone, return_count, parameter_count);
156 MachineSignature::Builder types(zone, return_count, parameter_count);
158 // Add return location.
159 AddReturnLocations(&locations);
160 types.AddReturn(return_type);
162 // Add parameters in registers and on the stack.
163 for (int i = 0; i < js_parameter_count; i++) {
164 if (i < register_parameter_count) {
165 // The first parameters go in registers.
166 Register reg = descriptor.GetEnvironmentParameterRegister(i);
168 descriptor.GetEnvironmentParameterRepresentation(i);
169 locations.AddParam(regloc(reg));
170 types.AddParam(reptyp(rep));
172 // The rest of the parameters go on the stack.
173 int stack_slot = i - register_parameter_count - stack_parameter_count;
174 locations.AddParam(stackloc(stack_slot));
175 types.AddParam(kMachAnyTagged);
179 locations.AddParam(regloc(LinkageTraits::ContextReg()));
180 types.AddParam(kMachAnyTagged);
182 // The target for stub calls is a code object.
183 MachineType target_type = kMachAnyTagged;
184 LinkageLocation target_loc = LinkageLocation::AnyRegister();
185 return new (zone) CallDescriptor( // --
186 CallDescriptor::kCallCodeObject, // kind
187 target_type, // target MachineType
188 target_loc, // target location
189 types.Build(), // machine_sig
190 locations.Build(), // location_sig
191 js_parameter_count, // js_parameter_count
192 properties, // properties
193 kNoCalleeSaved, // callee-saved registers
195 descriptor.DebugName(isolate));
198 static CallDescriptor* GetSimplifiedCDescriptor(
199 Zone* zone, const MachineSignature* msig) {
200 LocationSignature::Builder locations(zone, msig->return_count(),
201 msig->parameter_count());
202 // Add return location(s).
203 AddReturnLocations(&locations);
205 // Add register and/or stack parameter(s).
206 const int parameter_count = static_cast<int>(msig->parameter_count());
207 for (int i = 0; i < parameter_count; i++) {
208 if (i < LinkageTraits::CRegisterParametersLength()) {
209 locations.AddParam(regloc(LinkageTraits::CRegisterParameter(i)));
211 locations.AddParam(stackloc(-1 - i));
215 // The target for C calls is always an address (i.e. machine pointer).
216 MachineType target_type = kMachPtr;
217 LinkageLocation target_loc = LinkageLocation::AnyRegister();
218 return new (zone) CallDescriptor( // --
219 CallDescriptor::kCallAddress, // kind
220 target_type, // target MachineType
221 target_loc, // target location
223 locations.Build(), // location_sig
224 0, // js_parameter_count
225 Operator::kNoProperties, // properties
226 LinkageTraits::CCalleeSaveRegisters(), CallDescriptor::kNoFlags,
230 static LinkageLocation regloc(Register reg) {
231 return LinkageLocation(Register::ToAllocationIndex(reg));
234 static LinkageLocation stackloc(int i) {
236 return LinkageLocation(i);
239 static MachineType reptyp(Representation representation) {
240 switch (representation.kind()) {
241 case Representation::kInteger8:
243 case Representation::kUInteger8:
245 case Representation::kInteger16:
247 case Representation::kUInteger16:
249 case Representation::kInteger32:
251 case Representation::kSmi:
252 case Representation::kTagged:
253 case Representation::kHeapObject:
254 return kMachAnyTagged;
255 case Representation::kDouble:
257 case Representation::kExternal:
259 case Representation::kNone:
260 case Representation::kNumRepresentations:
269 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
270 CHECK(incoming_->IsJSFunctionCall());
271 int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
272 int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
274 if (index >= first_stack_slot) {
275 // Local variable stored in this (callee) stack.
277 LinkageLocation::ANY_REGISTER + 1 + index - first_stack_slot;
278 // TODO(titzer): bailout instead of crashing here.
279 CHECK(spill_index <= LinkageLocation::MAX_STACK_SLOT);
280 return LinkageLocation(spill_index);
282 // Parameter. Use the assigned location from the incoming call descriptor.
283 int parameter_index = 1 + index; // skip index 0, which is the target.
284 return incoming_->GetInputLocation(parameter_index);
288 } // namespace compiler
289 } // namespace internal
292 #endif // V8_COMPILER_LINKAGE_IMPL_H_