LCOV - code coverage report
Current view: top level - src/compiler - wasm-linkage.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 56 59 94.9 %
Date: 2017-04-26 Functions: 5 6 83.3 %

          Line data    Source code
       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-inl.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             : 
      28      436644 : MachineType MachineTypeFor(ValueType type) {
      29      436644 :   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           0 :       UNREACHABLE();
      42             :       return MachineType::AnyTagged();
      43             :   }
      44             : }
      45             : 
      46             : LinkageLocation regloc(Register reg, MachineType type) {
      47             :   return LinkageLocation::ForRegister(reg.code(), type);
      48             : }
      49             : 
      50             : LinkageLocation regloc(DoubleRegister reg, MachineType type) {
      51             :   return LinkageLocation::ForRegister(reg.code(), type);
      52             : }
      53             : 
      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 {
     158             :   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        9552 :         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             : 
     177      436648 :   LinkageLocation Next(ValueType type) {
     178      436648 :     if (IsFloatingPoint(type)) {
     179             :       // Allocate a floating point register/stack location.
     180      115073 :       if (fp_offset < fp_count) {
     181       88603 :         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       88603 :         return regloc(reg, MachineTypeFor(type));
     194             :       } else {
     195       26470 :         int offset = -1 - stack_offset;
     196       26470 :         stack_offset += Words(type);
     197       26470 :         return stackloc(offset, MachineTypeFor(type));
     198             :       }
     199             :     } else {
     200             :       // Allocate a general purpose register/stack location.
     201      321575 :       if (gp_offset < gp_count) {
     202      300368 :         return regloc(gp_regs[gp_offset++], MachineTypeFor(type));
     203             :       } else {
     204       21207 :         int offset = -1 - stack_offset;
     205       21207 :         stack_offset += Words(type);
     206       21207 :         return stackloc(offset, MachineTypeFor(type));
     207             :       }
     208             :     }
     209             :   }
     210             :   bool IsFloatingPoint(ValueType type) {
     211      436648 :     return type == kWasmF32 || type == kWasmF64;
     212             :   }
     213             :   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 {
     223             :   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        4776 :                                   kFPParamRegisters, kFPParamRegistersCount);
     244             :   }
     245             : };
     246             : 
     247             : static base::LazyInstance<Allocator, ParameterRegistersCreateTrait>::type
     248             :     parameter_registers = LAZY_INSTANCE_INITIALIZER;
     249             : 
     250             : struct ReturnRegistersCreateTrait {
     251             :   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        4776 :                                   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.
     279      177187 : CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
     280      791023 :                                                  FunctionSig* fsig) {
     281             :   LocationSignature::Builder locations(zone, fsig->return_count(),
     282             :                                        fsig->parameter_count());
     283             : 
     284      177193 :   Allocator rets = return_registers.Get();
     285             : 
     286             :   // Add return location(s).
     287      177193 :   const int return_count = static_cast<int>(locations.return_count_);
     288      312465 :   for (int i = 0; i < return_count; i++) {
     289      135274 :     ValueType ret = fsig->GetReturn(i);
     290      135274 :     locations.AddReturn(rets.Next(ret));
     291             :   }
     292             : 
     293      177195 :   Allocator params = parameter_registers.Get();
     294             : 
     295             :   // Add register and/or stack parameter(s).
     296      177195 :   const int parameter_count = static_cast<int>(fsig->parameter_count());
     297      478561 :   for (int i = 0; i < parameter_count; i++) {
     298      301367 :     ValueType param = fsig->GetParam(i);
     299      301367 :     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      531584 :       "wasm-call");
     320             : }
     321             : 
     322           4 : CallDescriptor* ReplaceTypeInCallDescriptorWith(
     323          30 :     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          10 :   for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
     328           6 :     if (descriptor->GetParameterType(i) == input_type) {
     329           4 :       parameter_count += num_replacements - 1;
     330             :     }
     331             :   }
     332           4 :   for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
     333           4 :     if (descriptor->GetReturnType(i) == input_type) {
     334           2 :       return_count += num_replacements - 1;
     335             :     }
     336             :   }
     337           4 :   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           4 :   Allocator rets = return_registers.Get();
     345             : 
     346          16 :   for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
     347           4 :     if (descriptor->GetReturnType(i) == input_type) {
     348           4 :       for (size_t j = 0; j < num_replacements; j++) {
     349           4 :         locations.AddReturn(rets.Next(output_type));
     350             :       }
     351             :     } else {
     352             :       locations.AddReturn(
     353           2 :           rets.Next(descriptor->GetReturnType(i).representation()));
     354             :     }
     355             :   }
     356             : 
     357           4 :   Allocator params = parameter_registers.Get();
     358             : 
     359          20 :   for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
     360           6 :     if (descriptor->GetParameterType(i) == input_type) {
     361           8 :       for (size_t j = 0; j < num_replacements; j++) {
     362           8 :         locations.AddParam(params.Next(output_type));
     363             :       }
     364             :     } else {
     365             :       locations.AddParam(
     366           2 :           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          12 :       descriptor->debug_name());
     381             : }
     382             : 
     383           4 : CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
     384             :     Zone* zone, CallDescriptor* descriptor) {
     385             :   return ReplaceTypeInCallDescriptorWith(zone, descriptor, 2,
     386             :                                          MachineType::Int64(),
     387           4 :                                          MachineRepresentation::kWord32);
     388             : }
     389             : 
     390           0 : CallDescriptor* ModuleEnv::GetI32WasmCallDescriptorForSimd(
     391             :     Zone* zone, CallDescriptor* descriptor) {
     392             :   return ReplaceTypeInCallDescriptorWith(zone, descriptor, 4,
     393             :                                          MachineType::Simd128(),
     394           0 :                                          MachineRepresentation::kWord32);
     395             : }
     396             : 
     397             : }  // namespace wasm
     398             : }  // namespace internal
     399             : }  // namespace v8

Generated by: LCOV version 1.10