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 namespace v8 {
9 namespace internal {
10 namespace compiler {
11 
12 // TODO(titzer): replace uses of int with size_t in LinkageHelper.
13 template <typename LinkageTraits>
14 class LinkageHelper {
15  public:
16   static const RegList kNoCalleeSaved = 0;
17 
AddReturnLocations(LocationSignature::Builder * locations)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.
GetJSCallDescriptor(Zone * zone,int js_parameter_count)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.
GetRuntimeCallDescriptor(Zone * zone,Runtime::FunctionId function_id,int js_parameter_count,Operator::Properties properties)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.
GetStubCallDescriptor(Zone * zone,CallInterfaceDescriptor descriptor,int stack_parameter_count,CallDescriptor::Flags flags)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 
GetSimplifiedCDescriptor(Zone * zone,MachineSignature * msig)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 
regloc(Register reg)213   static LinkageLocation regloc(Register reg) {
214     return LinkageLocation(Register::ToAllocationIndex(reg));
215   }
216 
stackloc(int i)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