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.
4
5#ifndef V8_COMPILER_LINKAGE_IMPL_H_
6#define V8_COMPILER_LINKAGE_IMPL_H_
7
8namespace v8 {
9namespace internal {
10namespace compiler {
11
12// TODO(titzer): replace uses of int with size_t in LinkageHelper.
13template <typename LinkageTraits>
14class LinkageHelper {
15 public:
16  static const RegList kNoCalleeSaved = 0;
17
18  static void AddReturnLocations(LocationSignature::Builder* locations) {
19    DCHECK(locations->return_count_ <= 2);
20    if (locations->return_count_ > 0) {
21      locations->AddReturn(regloc(LinkageTraits::ReturnValueReg()));
22    }
23    if (locations->return_count_ > 1) {
24      locations->AddReturn(regloc(LinkageTraits::ReturnValue2Reg()));
25    }
26  }
27
28  // TODO(turbofan): cache call descriptors for JSFunction calls.
29  static CallDescriptor* GetJSCallDescriptor(Zone* zone,
30                                             int js_parameter_count) {
31    const size_t return_count = 1;
32    const size_t context_count = 1;
33    const size_t parameter_count = js_parameter_count + context_count;
34
35    LocationSignature::Builder locations(zone, return_count, parameter_count);
36    MachineSignature::Builder types(zone, return_count, parameter_count);
37
38    // Add returns.
39    AddReturnLocations(&locations);
40    for (size_t i = 0; i < return_count; i++) {
41      types.AddReturn(kMachAnyTagged);
42    }
43
44    // All parameters to JS calls go on the stack.
45    for (int i = 0; i < js_parameter_count; i++) {
46      int spill_slot_index = i - js_parameter_count;
47      locations.AddParam(stackloc(spill_slot_index));
48      types.AddParam(kMachAnyTagged);
49    }
50    // Add context.
51    locations.AddParam(regloc(LinkageTraits::ContextReg()));
52    types.AddParam(kMachAnyTagged);
53
54    // The target for JS function calls is the JSFunction object.
55    MachineType target_type = kMachAnyTagged;
56    LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
57    return new (zone) CallDescriptor(CallDescriptor::kCallJSFunction,  // kind
58                                     target_type,         // target MachineType
59                                     target_loc,          // target location
60                                     types.Build(),       // machine_sig
61                                     locations.Build(),   // location_sig
62                                     js_parameter_count,  // js_parameter_count
63                                     Operator::kNoProperties,  // properties
64                                     kNoCalleeSaved,           // callee-saved
65                                     CallDescriptor::kNeedsFrameState,  // flags
66                                     "js-call");
67  }
68
69
70  // TODO(turbofan): cache call descriptors for runtime calls.
71  static CallDescriptor* GetRuntimeCallDescriptor(
72      Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
73      Operator::Properties properties) {
74    const size_t function_count = 1;
75    const size_t num_args_count = 1;
76    const size_t context_count = 1;
77    const size_t parameter_count = function_count +
78                                   static_cast<size_t>(js_parameter_count) +
79                                   num_args_count + context_count;
80
81    const Runtime::Function* function = Runtime::FunctionForId(function_id);
82    const size_t return_count = static_cast<size_t>(function->result_size);
83
84    LocationSignature::Builder locations(zone, return_count, parameter_count);
85    MachineSignature::Builder types(zone, return_count, parameter_count);
86
87    // Add returns.
88    AddReturnLocations(&locations);
89    for (size_t i = 0; i < return_count; i++) {
90      types.AddReturn(kMachAnyTagged);
91    }
92
93    // All parameters to the runtime call go on the stack.
94    for (int i = 0; i < js_parameter_count; i++) {
95      locations.AddParam(stackloc(i - js_parameter_count));
96      types.AddParam(kMachAnyTagged);
97    }
98    // Add runtime function itself.
99    locations.AddParam(regloc(LinkageTraits::RuntimeCallFunctionReg()));
100    types.AddParam(kMachAnyTagged);
101
102    // Add runtime call argument count.
103    locations.AddParam(regloc(LinkageTraits::RuntimeCallArgCountReg()));
104    types.AddParam(kMachPtr);
105
106    // Add context.
107    locations.AddParam(regloc(LinkageTraits::ContextReg()));
108    types.AddParam(kMachAnyTagged);
109
110    CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
111                                      ? CallDescriptor::kNeedsFrameState
112                                      : CallDescriptor::kNoFlags;
113
114    // The target for runtime calls is a code object.
115    MachineType target_type = kMachAnyTagged;
116    LinkageLocation target_loc = LinkageLocation::AnyRegister();
117    return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
118                                     target_type,         // target MachineType
119                                     target_loc,          // target location
120                                     types.Build(),       // machine_sig
121                                     locations.Build(),   // location_sig
122                                     js_parameter_count,  // js_parameter_count
123                                     properties,          // properties
124                                     kNoCalleeSaved,      // callee-saved
125                                     flags,               // flags
126                                     function->name);     // debug name
127  }
128
129
130  // TODO(turbofan): cache call descriptors for code stub calls.
131  static CallDescriptor* GetStubCallDescriptor(
132      Zone* zone, CallInterfaceDescriptor descriptor, int stack_parameter_count,
133      CallDescriptor::Flags flags) {
134    const int register_parameter_count =
135        descriptor.GetEnvironmentParameterCount();
136    const int js_parameter_count =
137        register_parameter_count + stack_parameter_count;
138    const int context_count = 1;
139    const size_t return_count = 1;
140    const size_t parameter_count =
141        static_cast<size_t>(js_parameter_count + context_count);
142
143    LocationSignature::Builder locations(zone, return_count, parameter_count);
144    MachineSignature::Builder types(zone, return_count, parameter_count);
145
146    // Add return location.
147    AddReturnLocations(&locations);
148    types.AddReturn(kMachAnyTagged);
149
150    // Add parameters in registers and on the stack.
151    for (int i = 0; i < js_parameter_count; i++) {
152      if (i < register_parameter_count) {
153        // The first parameters go in registers.
154        Register reg = descriptor.GetEnvironmentParameterRegister(i);
155        locations.AddParam(regloc(reg));
156      } else {
157        // The rest of the parameters go on the stack.
158        int stack_slot = i - register_parameter_count - stack_parameter_count;
159        locations.AddParam(stackloc(stack_slot));
160      }
161      types.AddParam(kMachAnyTagged);
162    }
163    // Add context.
164    locations.AddParam(regloc(LinkageTraits::ContextReg()));
165    types.AddParam(kMachAnyTagged);
166
167    // The target for stub calls is a code object.
168    MachineType target_type = kMachAnyTagged;
169    LinkageLocation target_loc = LinkageLocation::AnyRegister();
170    return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
171                                     target_type,         // target MachineType
172                                     target_loc,          // target location
173                                     types.Build(),       // machine_sig
174                                     locations.Build(),   // location_sig
175                                     js_parameter_count,  // js_parameter_count
176                                     Operator::kNoProperties,  // properties
177                                     kNoCalleeSaved,  // callee-saved registers
178                                     flags,           // flags
179                                     descriptor.DebugName(zone->isolate()));
180  }
181
182  static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
183                                                  MachineSignature* msig) {
184    LocationSignature::Builder locations(zone, msig->return_count(),
185                                         msig->parameter_count());
186    // Add return location(s).
187    AddReturnLocations(&locations);
188
189    // Add register and/or stack parameter(s).
190    const int parameter_count = static_cast<int>(msig->parameter_count());
191    for (int i = 0; i < parameter_count; i++) {
192      if (i < LinkageTraits::CRegisterParametersLength()) {
193        locations.AddParam(regloc(LinkageTraits::CRegisterParameter(i)));
194      } else {
195        locations.AddParam(stackloc(-1 - i));
196      }
197    }
198
199    // The target for C calls is always an address (i.e. machine pointer).
200    MachineType target_type = kMachPtr;
201    LinkageLocation target_loc = LinkageLocation::AnyRegister();
202    return new (zone) CallDescriptor(CallDescriptor::kCallAddress,  // kind
203                                     target_type,        // target MachineType
204                                     target_loc,         // target location
205                                     msig,               // machine_sig
206                                     locations.Build(),  // location_sig
207                                     0,                  // js_parameter_count
208                                     Operator::kNoProperties,  // properties
209                                     LinkageTraits::CCalleeSaveRegisters(),
210                                     CallDescriptor::kNoFlags, "c-call");
211  }
212
213  static LinkageLocation regloc(Register reg) {
214    return LinkageLocation(Register::ToAllocationIndex(reg));
215  }
216
217  static LinkageLocation stackloc(int i) {
218    DCHECK_LT(i, 0);
219    return LinkageLocation(i);
220  }
221};
222}  // namespace compiler
223}  // namespace internal
224}  // namespace v8
225
226#endif  // V8_COMPILER_LINKAGE_IMPL_H_
227