LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-wasm-interpreter-entry.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 77 77 100.0 %
Date: 2019-04-18 Functions: 21 21 100.0 %

          Line data    Source code
       1             : // Copyright 2017 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 <cstdint>
       6             : 
       7             : #include "src/assembler-inl.h"
       8             : #include "src/base/overflowing-math.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/wasm/wasm-objects.h"
      11             : #include "test/cctest/cctest.h"
      12             : #include "test/cctest/compiler/value-helper.h"
      13             : #include "test/cctest/wasm/wasm-run-utils.h"
      14             : #include "test/common/wasm/wasm-macro-gen.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace wasm {
      19             : 
      20             : /**
      21             :  * We test the interface from Wasm compiled code to the Wasm interpreter by
      22             :  * building a module with two functions. The external function is called from
      23             :  * this test, and will be compiled code. It takes its arguments and passes them
      24             :  * on to the internal function, which will be redirected to the interpreter.
      25             :  * If the internal function has an i64 parameter, is has to be replaced by two
      26             :  * i32 parameters on the external function.
      27             :  * The internal function just converts all its arguments to f64, sums them up
      28             :  * and returns the sum.
      29             :  */
      30             : namespace {
      31             : 
      32             : template <typename T>
      33             : class ArgPassingHelper {
      34             :  public:
      35          24 :   ArgPassingHelper(WasmRunnerBase& runner, WasmFunctionCompiler& inner_compiler,
      36             :                    std::initializer_list<uint8_t> bytes_inner_function,
      37             :                    std::initializer_list<uint8_t> bytes_outer_function,
      38             :                    const T& expected_lambda)
      39             :       : isolate_(runner.main_isolate()),
      40             :         expected_lambda_(expected_lambda),
      41             :         debug_info_(WasmInstanceObject::GetOrCreateDebugInfo(
      42          24 :             runner.builder().instance_object())) {
      43             :     std::vector<uint8_t> inner_code{bytes_inner_function};
      44          24 :     inner_compiler.Build(inner_code.data(),
      45             :                          inner_code.data() + inner_code.size());
      46             : 
      47             :     std::vector<uint8_t> outer_code{bytes_outer_function};
      48          24 :     runner.Build(outer_code.data(), outer_code.data() + outer_code.size());
      49             : 
      50          24 :     int funcs_to_redict[] = {static_cast<int>(inner_compiler.function_index())};
      51             :     runner.builder().SetExecutable();
      52          24 :     WasmDebugInfo::RedirectToInterpreter(debug_info_,
      53             :                                          ArrayVector(funcs_to_redict));
      54          24 :     main_fun_wrapper_ = runner.builder().WrapCode(runner.function_index());
      55          24 :   }
      56             : 
      57             :   template <typename... Args>
      58       25644 :   void CheckCall(Args... args) {
      59       25644 :     Handle<Object> arg_objs[] = {isolate_->factory()->NewNumber(args)...};
      60             : 
      61       25644 :     uint64_t num_interpreted_before = debug_info_->NumInterpretedCalls();
      62       76932 :     Handle<Object> global(isolate_->context()->global_object(), isolate_);
      63       51288 :     MaybeHandle<Object> retval = Execution::Call(
      64       25644 :         isolate_, main_fun_wrapper_, global, arraysize(arg_objs), arg_objs);
      65       25644 :     uint64_t num_interpreted_after = debug_info_->NumInterpretedCalls();
      66             :     // Check that we really went through the interpreter.
      67       25644 :     CHECK_EQ(num_interpreted_before + 1, num_interpreted_after);
      68             :     // Check the result.
      69             :     double result = retval.ToHandleChecked()->Number();
      70         232 :     double expected = expected_lambda_(args...);
      71       25644 :     CHECK_DOUBLE_EQ(expected, result);
      72       25644 :   }
      73             : 
      74             :  private:
      75             :   Isolate* isolate_;
      76             :   T expected_lambda_;
      77             :   Handle<WasmDebugInfo> debug_info_;
      78             :   Handle<JSFunction> main_fun_wrapper_;
      79             : };
      80             : 
      81             : template <typename T>
      82             : static ArgPassingHelper<T> GetHelper(
      83             :     WasmRunnerBase& runner, WasmFunctionCompiler& inner_compiler,
      84             :     std::initializer_list<uint8_t> bytes_inner_function,
      85             :     std::initializer_list<uint8_t> bytes_outer_function,
      86             :     const T& expected_lambda) {
      87             :   return ArgPassingHelper<T>(runner, inner_compiler, bytes_inner_function,
      88          24 :                              bytes_outer_function, expected_lambda);
      89             : }
      90             : 
      91             : }  // namespace
      92             : 
      93             : // Pass int32_t, return int32_t.
      94       26660 : TEST(TestArgumentPassing_int32) {
      95           8 :   WasmRunner<int32_t, int32_t> runner(ExecutionTier::kTurbofan);
      96             :   WasmFunctionCompiler& f2 = runner.NewFunction<int32_t, int32_t>();
      97             : 
      98             :   auto helper = GetHelper(
      99             :       runner, f2,
     100             :       {// Return 2*<0> + 1.
     101             :        WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
     102             :       {// Call f2 with param <0>.
     103             :        WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
     104             :       [](int32_t a) {
     105             :         return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
     106          12 :       });
     107             : 
     108         236 :   FOR_INT32_INPUTS(v) { helper.CheckCall(v); }
     109           4 : }
     110             : 
     111             : // Pass int64_t, return double.
     112       26660 : TEST(TestArgumentPassing_double_int64) {
     113           8 :   WasmRunner<double, int32_t, int32_t> runner(ExecutionTier::kTurbofan);
     114             :   WasmFunctionCompiler& f2 = runner.NewFunction<double, int64_t>();
     115             : 
     116             :   auto helper = GetHelper(
     117             :       runner, f2,
     118             :       {// Return (double)<0>.
     119             :        WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))},
     120             :       {// Call f2 with param (<0> | (<1> << 32)).
     121             :        WASM_I64_IOR(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(0)),
     122             :                     WASM_I64_SHL(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(1)),
     123             :                                  WASM_I64V_1(32))),
     124             :        WASM_CALL_FUNCTION0(f2.function_index())},
     125             :       [](int32_t a, int32_t b) {
     126       14104 :         int64_t a64 = static_cast<int64_t>(a) & 0xFFFFFFFF;
     127       14104 :         int64_t b64 = static_cast<uint64_t>(static_cast<int64_t>(b)) << 32;
     128       14104 :         return static_cast<double>(a64 | b64);
     129          12 :       });
     130             : 
     131         468 :   FOR_INT32_INPUTS(v1) {
     132       13688 :     FOR_INT32_INPUTS(v2) { helper.CheckCall(v1, v2); }
     133             :   }
     134             : 
     135         652 :   FOR_INT64_INPUTS(v) {
     136         324 :     int32_t v1 = static_cast<int32_t>(v);
     137         324 :     int32_t v2 = static_cast<int32_t>(v >> 32);
     138         324 :     helper.CheckCall(v1, v2);
     139         324 :     helper.CheckCall(v2, v1);
     140             :   }
     141           4 : }
     142             : 
     143             : // Pass double, return int64_t.
     144       26660 : TEST(TestArgumentPassing_int64_double) {
     145             :   // Outer function still returns double.
     146           8 :   WasmRunner<double, double> runner(ExecutionTier::kTurbofan);
     147             :   WasmFunctionCompiler& f2 = runner.NewFunction<int64_t, double>();
     148             : 
     149             :   auto helper = GetHelper(
     150             :       runner, f2,
     151             :       {// Return (int64_t)<0>.
     152             :        WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))},
     153             :       {// Call f2 with param <0>, convert returned value back to double.
     154             :        WASM_F64_SCONVERT_I64(WASM_SEQ(
     155             :            WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())))},
     156          12 :       [](double d) { return d; });
     157             : 
     158         652 :   for (int64_t i : compiler::ValueHelper::int64_vector()) {
     159         324 :     helper.CheckCall(i);
     160             :   }
     161           4 : }
     162             : 
     163             : // Pass float, return double.
     164       26660 : TEST(TestArgumentPassing_float_double) {
     165           8 :   WasmRunner<double, float> runner(ExecutionTier::kTurbofan);
     166             :   WasmFunctionCompiler& f2 = runner.NewFunction<double, float>();
     167             : 
     168             :   auto helper = GetHelper(
     169             :       runner, f2,
     170             :       {// Return 2*(double)<0> + 1.
     171             :        WASM_F64_ADD(
     172             :            WASM_F64_MUL(WASM_F64(2), WASM_F64_CONVERT_F32(WASM_GET_LOCAL(0))),
     173             :            WASM_F64(1))},
     174             :       {// Call f2 with param <0>.
     175             :        WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
     176         472 :       [](float f) { return 2. * static_cast<double>(f) + 1.; });
     177             : 
     178         464 :   FOR_FLOAT32_INPUTS(f) { helper.CheckCall(f); }
     179           4 : }
     180             : 
     181             : // Pass two doubles, return double.
     182       26660 : TEST(TestArgumentPassing_double_double) {
     183           8 :   WasmRunner<double, double, double> runner(ExecutionTier::kTurbofan);
     184             :   WasmFunctionCompiler& f2 = runner.NewFunction<double, double, double>();
     185             : 
     186             :   auto helper = GetHelper(runner, f2,
     187             :                           {// Return <0> + <1>.
     188             :                            WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))},
     189             :                           {// Call f2 with params <0>, <1>.
     190             :                            WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
     191             :                            WASM_CALL_FUNCTION0(f2.function_index())},
     192        9616 :                           [](double a, double b) { return a + b; });
     193             : 
     194         396 :   FOR_FLOAT64_INPUTS(d1) {
     195        9800 :     FOR_FLOAT64_INPUTS(d2) { helper.CheckCall(d1, d2); }
     196             :   }
     197           4 : }
     198             : 
     199             : // Pass int32_t, int64_t, float and double, return double.
     200       26660 : TEST(TestArgumentPassing_AllTypes) {
     201             :   // The second and third argument will be combined to an i64.
     202             :   WasmRunner<double, int32_t, int32_t, int32_t, float, double> runner(
     203           8 :       ExecutionTier::kTurbofan);
     204             :   WasmFunctionCompiler& f2 =
     205             :       runner.NewFunction<double, int32_t, int64_t, float, double>();
     206             : 
     207             :   auto helper = GetHelper(
     208             :       runner, f2,
     209             :       {
     210             :           // Convert all arguments to double, add them and return the sum.
     211             :           WASM_F64_ADD(          // <0+1+2> + <3>
     212             :               WASM_F64_ADD(      // <0+1> + <2>
     213             :                   WASM_F64_ADD(  // <0> + <1>
     214             :                       WASM_F64_SCONVERT_I32(
     215             :                           WASM_GET_LOCAL(0)),  // <0> to double
     216             :                       WASM_F64_SCONVERT_I64(
     217             :                           WASM_GET_LOCAL(1))),               // <1> to double
     218             :                   WASM_F64_CONVERT_F32(WASM_GET_LOCAL(2))),  // <2> to double
     219             :               WASM_GET_LOCAL(3))                             // <3>
     220             :       },
     221             :       {WASM_GET_LOCAL(0),                                      // first arg
     222             :        WASM_I64_IOR(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(1)),  // second arg
     223             :                     WASM_I64_SHL(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(2)),
     224             :                                  WASM_I64V_1(32))),
     225             :        WASM_GET_LOCAL(3),  // third arg
     226             :        WASM_GET_LOCAL(4),  // fourth arg
     227             :        WASM_CALL_FUNCTION0(f2.function_index())},
     228             :       [](int32_t a, int32_t b, int32_t c, float d, double e) {
     229        1840 :         return 0. + a + (static_cast<int64_t>(b) & 0xFFFFFFFF) +
     230        1840 :                ((static_cast<int64_t>(c) & 0xFFFFFFFF) << 32) + d + e;
     231         932 :       });
     232             : 
     233         460 :   auto CheckCall = [&](int32_t a, int64_t b, float c, double d) {
     234         460 :     int32_t b0 = static_cast<int32_t>(b);
     235         460 :     int32_t b1 = static_cast<int32_t>(b >> 32);
     236         460 :     helper.CheckCall(a, b0, b1, c, d);
     237         460 :     helper.CheckCall(a, b1, b0, c, d);
     238         464 :   };
     239             : 
     240             :   Vector<const int32_t> test_values_i32 = compiler::ValueHelper::int32_vector();
     241             :   Vector<const int64_t> test_values_i64 = compiler::ValueHelper::int64_vector();
     242             :   Vector<const float> test_values_f32 = compiler::ValueHelper::float32_vector();
     243             :   Vector<const double> test_values_f64 =
     244             :       compiler::ValueHelper::float64_vector();
     245             :   size_t max_len =
     246           4 :       std::max(std::max(test_values_i32.size(), test_values_i64.size()),
     247           8 :                std::max(test_values_f32.size(), test_values_f64.size()));
     248         924 :   for (size_t i = 0; i < max_len; ++i) {
     249         920 :     int32_t i32 = test_values_i32[i % test_values_i32.size()];
     250         920 :     int64_t i64 = test_values_i64[i % test_values_i64.size()];
     251         920 :     float f32 = test_values_f32[i % test_values_f32.size()];
     252         920 :     double f64 = test_values_f64[i % test_values_f64.size()];
     253         460 :     CheckCall(i32, i64, f32, f64);
     254             :   }
     255           4 : }
     256             : 
     257             : }  // namespace wasm
     258             : }  // namespace internal
     259       79968 : }  // namespace v8

Generated by: LCOV version 1.10