• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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/assembler.h"
6 #include "src/base/lazy-instance.h"
7 #include "src/macro-assembler.h"
8 #include "src/objects-inl.h"
9 #include "src/register-configuration.h"
10 
11 #include "src/wasm/wasm-module.h"
12 
13 #include "src/compiler/linkage.h"
14 
15 #include "src/zone/zone.h"
16 
17 namespace v8 {
18 namespace internal {
19 // TODO(titzer): this should not be in the WASM namespace.
20 namespace wasm {
21 
22 using compiler::LocationSignature;
23 using compiler::CallDescriptor;
24 using compiler::LinkageLocation;
25 
26 namespace {
27 
MachineTypeFor(ValueType type)28 MachineType MachineTypeFor(ValueType type) {
29   switch (type) {
30     case kWasmI32:
31       return MachineType::Int32();
32     case kWasmI64:
33       return MachineType::Int64();
34     case kWasmF64:
35       return MachineType::Float64();
36     case kWasmF32:
37       return MachineType::Float32();
38     case kWasmS128:
39       return MachineType::Simd128();
40     default:
41       UNREACHABLE();
42       return MachineType::AnyTagged();
43   }
44 }
45 
regloc(Register reg,MachineType type)46 LinkageLocation regloc(Register reg, MachineType type) {
47   return LinkageLocation::ForRegister(reg.code(), type);
48 }
49 
regloc(DoubleRegister reg,MachineType type)50 LinkageLocation regloc(DoubleRegister reg, MachineType type) {
51   return LinkageLocation::ForRegister(reg.code(), type);
52 }
53 
stackloc(int i,MachineType type)54 LinkageLocation stackloc(int i, MachineType type) {
55   return LinkageLocation::ForCallerFrameSlot(i, type);
56 }
57 
58 
59 #if V8_TARGET_ARCH_IA32
60 // ===========================================================================
61 // == ia32 ===================================================================
62 // ===========================================================================
63 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
64 #define GP_RETURN_REGISTERS eax, edx
65 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
66 #define FP_RETURN_REGISTERS xmm1, xmm2
67 
68 #elif V8_TARGET_ARCH_X64
69 // ===========================================================================
70 // == x64 ====================================================================
71 // ===========================================================================
72 #define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi
73 #define GP_RETURN_REGISTERS rax, rdx
74 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
75 #define FP_RETURN_REGISTERS xmm1, xmm2
76 
77 #elif V8_TARGET_ARCH_X87
78 // ===========================================================================
79 // == x87 ====================================================================
80 // ===========================================================================
81 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
82 #define GP_RETURN_REGISTERS eax, edx
83 #define FP_RETURN_REGISTERS stX_0
84 
85 #elif V8_TARGET_ARCH_ARM
86 // ===========================================================================
87 // == arm ====================================================================
88 // ===========================================================================
89 #define GP_PARAM_REGISTERS r0, r1, r2, r3
90 #define GP_RETURN_REGISTERS r0, r1
91 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
92 #define FP_RETURN_REGISTERS d0, d1
93 
94 #elif V8_TARGET_ARCH_ARM64
95 // ===========================================================================
96 // == arm64 ====================================================================
97 // ===========================================================================
98 #define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
99 #define GP_RETURN_REGISTERS x0, x1
100 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
101 #define FP_RETURN_REGISTERS d0, d1
102 
103 #elif V8_TARGET_ARCH_MIPS
104 // ===========================================================================
105 // == mips ===================================================================
106 // ===========================================================================
107 #define GP_PARAM_REGISTERS a0, a1, a2, a3
108 #define GP_RETURN_REGISTERS v0, v1
109 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
110 #define FP_RETURN_REGISTERS f2, f4
111 
112 #elif V8_TARGET_ARCH_MIPS64
113 // ===========================================================================
114 // == mips64 =================================================================
115 // ===========================================================================
116 #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
117 #define GP_RETURN_REGISTERS v0, v1
118 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
119 #define FP_RETURN_REGISTERS f2, f4
120 
121 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
122 // ===========================================================================
123 // == ppc & ppc64 ============================================================
124 // ===========================================================================
125 #define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
126 #define GP_RETURN_REGISTERS r3, r4
127 #define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
128 #define FP_RETURN_REGISTERS d1, d2
129 
130 #elif V8_TARGET_ARCH_S390X
131 // ===========================================================================
132 // == s390x ==================================================================
133 // ===========================================================================
134 #define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
135 #define GP_RETURN_REGISTERS r2, r3
136 #define FP_PARAM_REGISTERS d0, d2, d4, d6
137 #define FP_RETURN_REGISTERS d0, d2, d4, d6
138 
139 #elif V8_TARGET_ARCH_S390
140 // ===========================================================================
141 // == s390 ===================================================================
142 // ===========================================================================
143 #define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
144 #define GP_RETURN_REGISTERS r2, r3
145 #define FP_PARAM_REGISTERS d0, d2
146 #define FP_RETURN_REGISTERS d0, d2
147 
148 #else
149 // ===========================================================================
150 // == unknown ================================================================
151 // ===========================================================================
152 // Don't define anything. We'll just always use the stack.
153 #endif
154 
155 
156 // Helper for allocating either an GP or FP reg, or the next stack slot.
157 struct Allocator {
Allocatorv8::internal::wasm::__anon762a1cc20111::Allocator158   Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc)
159       : gp_count(gpc),
160         gp_offset(0),
161         gp_regs(gp),
162         fp_count(fpc),
163         fp_offset(0),
164         fp_regs(fp),
165         stack_offset(0) {}
166 
167   int gp_count;
168   int gp_offset;
169   const Register* gp_regs;
170 
171   int fp_count;
172   int fp_offset;
173   const DoubleRegister* fp_regs;
174 
175   int stack_offset;
176 
Nextv8::internal::wasm::__anon762a1cc20111::Allocator177   LinkageLocation Next(ValueType type) {
178     if (IsFloatingPoint(type)) {
179       // Allocate a floating point register/stack location.
180       if (fp_offset < fp_count) {
181         DoubleRegister reg = fp_regs[fp_offset++];
182 #if V8_TARGET_ARCH_ARM
183         // Allocate floats using a double register, but modify the code to
184         // reflect how ARM FP registers alias.
185         // TODO(bbudge) Modify wasm linkage to allow use of all float regs.
186         if (type == kWasmF32) {
187           int float_reg_code = reg.code() * 2;
188           DCHECK(float_reg_code < RegisterConfiguration::kMaxFPRegisters);
189           return regloc(DoubleRegister::from_code(float_reg_code),
190                         MachineTypeFor(type));
191         }
192 #endif
193         return regloc(reg, MachineTypeFor(type));
194       } else {
195         int offset = -1 - stack_offset;
196         stack_offset += Words(type);
197         return stackloc(offset, MachineTypeFor(type));
198       }
199     } else {
200       // Allocate a general purpose register/stack location.
201       if (gp_offset < gp_count) {
202         return regloc(gp_regs[gp_offset++], MachineTypeFor(type));
203       } else {
204         int offset = -1 - stack_offset;
205         stack_offset += Words(type);
206         return stackloc(offset, MachineTypeFor(type));
207       }
208     }
209   }
IsFloatingPointv8::internal::wasm::__anon762a1cc20111::Allocator210   bool IsFloatingPoint(ValueType type) {
211     return type == kWasmF32 || type == kWasmF64;
212   }
Wordsv8::internal::wasm::__anon762a1cc20111::Allocator213   int Words(ValueType type) {
214     if (kPointerSize < 8 && (type == kWasmI64 || type == kWasmF64)) {
215       return 2;
216     }
217     return 1;
218   }
219 };
220 }  // namespace
221 
222 struct ParameterRegistersCreateTrait {
Constructv8::internal::wasm::ParameterRegistersCreateTrait223   static void Construct(Allocator* allocated_ptr) {
224 #ifdef GP_PARAM_REGISTERS
225     static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
226     static const int kGPParamRegistersCount =
227         static_cast<int>(arraysize(kGPParamRegisters));
228 #else
229     static const Register* kGPParamRegisters = nullptr;
230     static const int kGPParamRegistersCount = 0;
231 #endif
232 
233 #ifdef FP_PARAM_REGISTERS
234     static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
235     static const int kFPParamRegistersCount =
236         static_cast<int>(arraysize(kFPParamRegisters));
237 #else
238     static const DoubleRegister* kFPParamRegisters = nullptr;
239     static const int kFPParamRegistersCount = 0;
240 #endif
241 
242     new (allocated_ptr) Allocator(kGPParamRegisters, kGPParamRegistersCount,
243                                   kFPParamRegisters, kFPParamRegistersCount);
244   }
245 };
246 
247 static base::LazyInstance<Allocator, ParameterRegistersCreateTrait>::type
248     parameter_registers = LAZY_INSTANCE_INITIALIZER;
249 
250 struct ReturnRegistersCreateTrait {
Constructv8::internal::wasm::ReturnRegistersCreateTrait251   static void Construct(Allocator* allocated_ptr) {
252 #ifdef GP_RETURN_REGISTERS
253     static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
254     static const int kGPReturnRegistersCount =
255         static_cast<int>(arraysize(kGPReturnRegisters));
256 #else
257     static const Register* kGPReturnRegisters = nullptr;
258     static const int kGPReturnRegistersCount = 0;
259 #endif
260 
261 #ifdef FP_RETURN_REGISTERS
262     static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
263     static const int kFPReturnRegistersCount =
264         static_cast<int>(arraysize(kFPReturnRegisters));
265 #else
266     static const DoubleRegister* kFPReturnRegisters = nullptr;
267     static const int kFPReturnRegistersCount = 0;
268 #endif
269 
270     new (allocated_ptr) Allocator(kGPReturnRegisters, kGPReturnRegistersCount,
271                                   kFPReturnRegisters, kFPReturnRegistersCount);
272   }
273 };
274 
275 static base::LazyInstance<Allocator, ReturnRegistersCreateTrait>::type
276     return_registers = LAZY_INSTANCE_INITIALIZER;
277 
278 // General code uses the above configuration data.
GetWasmCallDescriptor(Zone * zone,FunctionSig * fsig)279 CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
280                                                  FunctionSig* fsig) {
281   LocationSignature::Builder locations(zone, fsig->return_count(),
282                                        fsig->parameter_count());
283 
284   Allocator rets = return_registers.Get();
285 
286   // Add return location(s).
287   const int return_count = static_cast<int>(locations.return_count_);
288   for (int i = 0; i < return_count; i++) {
289     ValueType ret = fsig->GetReturn(i);
290     locations.AddReturn(rets.Next(ret));
291   }
292 
293   Allocator params = parameter_registers.Get();
294 
295   // Add register and/or stack parameter(s).
296   const int parameter_count = static_cast<int>(fsig->parameter_count());
297   for (int i = 0; i < parameter_count; i++) {
298     ValueType param = fsig->GetParam(i);
299     locations.AddParam(params.Next(param));
300   }
301 
302   const RegList kCalleeSaveRegisters = 0;
303   const RegList kCalleeSaveFPRegisters = 0;
304 
305   // The target for WASM calls is always a code object.
306   MachineType target_type = MachineType::AnyTagged();
307   LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
308 
309   return new (zone) CallDescriptor(       // --
310       CallDescriptor::kCallCodeObject,    // kind
311       target_type,                        // target MachineType
312       target_loc,                         // target location
313       locations.Build(),                  // location_sig
314       params.stack_offset,                // stack_parameter_count
315       compiler::Operator::kNoProperties,  // properties
316       kCalleeSaveRegisters,               // callee-saved registers
317       kCalleeSaveFPRegisters,             // callee-saved fp regs
318       CallDescriptor::kUseNativeStack,    // flags
319       "wasm-call");
320 }
321 
ReplaceTypeInCallDescriptorWith(Zone * zone,CallDescriptor * descriptor,size_t num_replacements,MachineType input_type,MachineRepresentation output_type)322 CallDescriptor* ReplaceTypeInCallDescriptorWith(
323     Zone* zone, CallDescriptor* descriptor, size_t num_replacements,
324     MachineType input_type, MachineRepresentation output_type) {
325   size_t parameter_count = descriptor->ParameterCount();
326   size_t return_count = descriptor->ReturnCount();
327   for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
328     if (descriptor->GetParameterType(i) == input_type) {
329       parameter_count += num_replacements - 1;
330     }
331   }
332   for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
333     if (descriptor->GetReturnType(i) == input_type) {
334       return_count += num_replacements - 1;
335     }
336   }
337   if (parameter_count == descriptor->ParameterCount() &&
338       return_count == descriptor->ReturnCount()) {
339     return descriptor;
340   }
341 
342   LocationSignature::Builder locations(zone, return_count, parameter_count);
343 
344   Allocator rets = return_registers.Get();
345 
346   for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
347     if (descriptor->GetReturnType(i) == input_type) {
348       for (size_t j = 0; j < num_replacements; j++) {
349         locations.AddReturn(rets.Next(output_type));
350       }
351     } else {
352       locations.AddReturn(
353           rets.Next(descriptor->GetReturnType(i).representation()));
354     }
355   }
356 
357   Allocator params = parameter_registers.Get();
358 
359   for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
360     if (descriptor->GetParameterType(i) == input_type) {
361       for (size_t j = 0; j < num_replacements; j++) {
362         locations.AddParam(params.Next(output_type));
363       }
364     } else {
365       locations.AddParam(
366           params.Next(descriptor->GetParameterType(i).representation()));
367     }
368   }
369 
370   return new (zone) CallDescriptor(          // --
371       descriptor->kind(),                    // kind
372       descriptor->GetInputType(0),           // target MachineType
373       descriptor->GetInputLocation(0),       // target location
374       locations.Build(),                     // location_sig
375       params.stack_offset,                   // stack_parameter_count
376       descriptor->properties(),              // properties
377       descriptor->CalleeSavedRegisters(),    // callee-saved registers
378       descriptor->CalleeSavedFPRegisters(),  // callee-saved fp regs
379       descriptor->flags(),                   // flags
380       descriptor->debug_name());
381 }
382 
GetI32WasmCallDescriptor(Zone * zone,CallDescriptor * descriptor)383 CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
384     Zone* zone, CallDescriptor* descriptor) {
385   return ReplaceTypeInCallDescriptorWith(zone, descriptor, 2,
386                                          MachineType::Int64(),
387                                          MachineRepresentation::kWord32);
388 }
389 
GetI32WasmCallDescriptorForSimd(Zone * zone,CallDescriptor * descriptor)390 CallDescriptor* ModuleEnv::GetI32WasmCallDescriptorForSimd(
391     Zone* zone, CallDescriptor* descriptor) {
392   return ReplaceTypeInCallDescriptorWith(zone, descriptor, 4,
393                                          MachineType::Simd128(),
394                                          MachineRepresentation::kWord32);
395 }
396 
397 }  // namespace wasm
398 }  // namespace internal
399 }  // namespace v8
400