abd0696837d17a49c4f58e1d9ca8084968658069
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / linkage-impl.h
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
8 #include "src/code-stubs.h"
9 #include "src/compiler/osr.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 // TODO(titzer): replace uses of int with size_t in LinkageHelper.
16 template <typename LinkageTraits>
17 class LinkageHelper {
18  public:
19   static const RegList kNoCalleeSaved = 0;
20
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()));
25     }
26     if (locations->return_count_ > 1) {
27       locations->AddReturn(regloc(LinkageTraits::ReturnValue2Reg()));
28     }
29   }
30
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;
38
39     LocationSignature::Builder locations(zone, return_count, parameter_count);
40     MachineSignature::Builder types(zone, return_count, parameter_count);
41
42     // Add returns.
43     AddReturnLocations(&locations);
44     for (size_t i = 0; i < return_count; i++) {
45       types.AddReturn(kMachAnyTagged);
46     }
47
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);
53     }
54     // Add context.
55     locations.AddParam(regloc(LinkageTraits::ContextReg()));
56     types.AddParam(kMachAnyTagged);
57
58     // The target for JS function calls is the JSFunction object.
59     MachineType target_type = kMachAnyTagged;
60     // Unoptimized code doesn't preserve the JSCallFunctionReg, so expect the
61     // closure on the stack.
62     LinkageLocation target_loc =
63         is_osr ? stackloc(Linkage::kJSFunctionCallClosureParamIndex -
64                           js_parameter_count)
65                : regloc(LinkageTraits::JSCallFunctionReg());
66     return new (zone) CallDescriptor(     // --
67         CallDescriptor::kCallJSFunction,  // kind
68         target_type,                      // target MachineType
69         target_loc,                       // target location
70         types.Build(),                    // machine_sig
71         locations.Build(),                // location_sig
72         js_parameter_count,               // js_parameter_count
73         Operator::kNoProperties,          // properties
74         kNoCalleeSaved,                   // callee-saved
75         flags,                            // flags
76         "js-call");
77   }
78
79
80   // TODO(turbofan): cache call descriptors for runtime calls.
81   static CallDescriptor* GetRuntimeCallDescriptor(
82       Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
83       Operator::Properties properties) {
84     const size_t function_count = 1;
85     const size_t num_args_count = 1;
86     const size_t context_count = 1;
87     const size_t parameter_count = function_count +
88                                    static_cast<size_t>(js_parameter_count) +
89                                    num_args_count + context_count;
90
91     const Runtime::Function* function = Runtime::FunctionForId(function_id);
92     const size_t return_count = static_cast<size_t>(function->result_size);
93
94     LocationSignature::Builder locations(zone, return_count, parameter_count);
95     MachineSignature::Builder types(zone, return_count, parameter_count);
96
97     // Add returns.
98     AddReturnLocations(&locations);
99     for (size_t i = 0; i < return_count; i++) {
100       types.AddReturn(kMachAnyTagged);
101     }
102
103     // All parameters to the runtime call go on the stack.
104     for (int i = 0; i < js_parameter_count; i++) {
105       locations.AddParam(stackloc(i - js_parameter_count));
106       types.AddParam(kMachAnyTagged);
107     }
108     // Add runtime function itself.
109     locations.AddParam(regloc(LinkageTraits::RuntimeCallFunctionReg()));
110     types.AddParam(kMachAnyTagged);
111
112     // Add runtime call argument count.
113     locations.AddParam(regloc(LinkageTraits::RuntimeCallArgCountReg()));
114     types.AddParam(kMachPtr);
115
116     // Add context.
117     locations.AddParam(regloc(LinkageTraits::ContextReg()));
118     types.AddParam(kMachAnyTagged);
119
120     CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
121                                       ? CallDescriptor::kNeedsFrameState
122                                       : CallDescriptor::kNoFlags;
123
124     // The target for runtime calls is a code object.
125     MachineType target_type = kMachAnyTagged;
126     LinkageLocation target_loc = LinkageLocation::AnyRegister();
127     return new (zone) CallDescriptor(     // --
128         CallDescriptor::kCallCodeObject,  // kind
129         target_type,                      // target MachineType
130         target_loc,                       // target location
131         types.Build(),                    // machine_sig
132         locations.Build(),                // location_sig
133         js_parameter_count,               // js_parameter_count
134         properties,                       // properties
135         kNoCalleeSaved,                   // callee-saved
136         flags,                            // flags
137         function->name);                  // debug name
138   }
139
140
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) {
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);
154
155     LocationSignature::Builder locations(zone, return_count, parameter_count);
156     MachineSignature::Builder types(zone, return_count, parameter_count);
157
158     // Add return location.
159     AddReturnLocations(&locations);
160     types.AddReturn(kMachAnyTagged);
161
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);
167         locations.AddParam(regloc(reg));
168       } else {
169         // The rest of the parameters go on the stack.
170         int stack_slot = i - register_parameter_count - stack_parameter_count;
171         locations.AddParam(stackloc(stack_slot));
172       }
173       types.AddParam(kMachAnyTagged);
174     }
175     // Add context.
176     locations.AddParam(regloc(LinkageTraits::ContextReg()));
177     types.AddParam(kMachAnyTagged);
178
179     // The target for stub calls is a code object.
180     MachineType target_type = kMachAnyTagged;
181     LinkageLocation target_loc = LinkageLocation::AnyRegister();
182     return new (zone) CallDescriptor(     // --
183         CallDescriptor::kCallCodeObject,  // kind
184         target_type,                      // target MachineType
185         target_loc,                       // target location
186         types.Build(),                    // machine_sig
187         locations.Build(),                // location_sig
188         js_parameter_count,               // js_parameter_count
189         properties,                       // properties
190         kNoCalleeSaved,                   // callee-saved registers
191         flags,                            // flags
192         descriptor.DebugName(isolate));
193   }
194
195   static CallDescriptor* GetSimplifiedCDescriptor(
196       Zone* zone, const MachineSignature* msig) {
197     LocationSignature::Builder locations(zone, msig->return_count(),
198                                          msig->parameter_count());
199     // Add return location(s).
200     AddReturnLocations(&locations);
201
202     // Add register and/or stack parameter(s).
203     const int parameter_count = static_cast<int>(msig->parameter_count());
204     for (int i = 0; i < parameter_count; i++) {
205       if (i < LinkageTraits::CRegisterParametersLength()) {
206         locations.AddParam(regloc(LinkageTraits::CRegisterParameter(i)));
207       } else {
208         locations.AddParam(stackloc(-1 - i));
209       }
210     }
211
212     // The target for C calls is always an address (i.e. machine pointer).
213     MachineType target_type = kMachPtr;
214     LinkageLocation target_loc = LinkageLocation::AnyRegister();
215     return new (zone) CallDescriptor(  // --
216         CallDescriptor::kCallAddress,  // kind
217         target_type,                   // target MachineType
218         target_loc,                    // target location
219         msig,                          // machine_sig
220         locations.Build(),             // location_sig
221         0,                             // js_parameter_count
222         Operator::kNoProperties,       // properties
223         LinkageTraits::CCalleeSaveRegisters(), CallDescriptor::kNoFlags,
224         "c-call");
225   }
226
227   static LinkageLocation regloc(Register reg) {
228     return LinkageLocation(Register::ToAllocationIndex(reg));
229   }
230
231   static LinkageLocation stackloc(int i) {
232     DCHECK_LT(i, 0);
233     return LinkageLocation(i);
234   }
235 };
236
237
238 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
239   CHECK(incoming_->IsJSFunctionCall());
240   int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
241   int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
242
243   if (index >= first_stack_slot) {
244     // Local variable stored in this (callee) stack.
245     int spill_index =
246         LinkageLocation::ANY_REGISTER + 1 + index - first_stack_slot;
247     // TODO(titzer): bailout instead of crashing here.
248     CHECK(spill_index <= LinkageLocation::MAX_STACK_SLOT);
249     return LinkageLocation(spill_index);
250   } else {
251     // Parameter. Use the assigned location from the incoming call descriptor.
252     int parameter_index = 1 + index;  // skip index 0, which is the target.
253     return incoming_->GetInputLocation(parameter_index);
254   }
255 }
256
257
258 }  // namespace compiler
259 }  // namespace internal
260 }  // namespace v8
261
262 #endif  // V8_COMPILER_LINKAGE_IMPL_H_