LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-c-wasm-entry.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 65 65 100.0 %
Date: 2019-04-17 Functions: 30 30 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 C to compiled wasm code by generating a wasm
      22             :  * function, creating a corresponding signature, compiling the c wasm entry for
      23             :  * that signature, and then calling that entry using different test values.
      24             :  * The result is compared against the expected result, computed from a lambda
      25             :  * passed to the CWasmEntryArgTester.
      26             :  */
      27             : namespace {
      28             : 
      29             : template <typename ReturnType, typename... Args>
      30          48 : class CWasmEntryArgTester {
      31             :  public:
      32          24 :   CWasmEntryArgTester(std::initializer_list<uint8_t> wasm_function_bytes,
      33             :                       std::function<ReturnType(Args...)> expected_fn)
      34             :       : runner_(ExecutionTier::kTurbofan),
      35             :         isolate_(runner_.main_isolate()),
      36             :         expected_fn_(expected_fn),
      37          48 :         sig_(runner_.template CreateSig<ReturnType, Args...>()) {
      38             :     std::vector<uint8_t> code{wasm_function_bytes};
      39          24 :     runner_.Build(code.data(), code.data() + code.size());
      40          24 :     wasm_code_ = runner_.builder().GetFunctionCode(0);
      41          24 :     Handle<WasmInstanceObject> instance(runner_.builder().instance_object());
      42             :     Handle<WasmDebugInfo> debug_info =
      43          24 :         WasmInstanceObject::GetOrCreateDebugInfo(instance);
      44          24 :     c_wasm_entry_fn_ = WasmDebugInfo::GetCWasmEntry(debug_info, sig_);
      45          24 :   }
      46             : 
      47             :   template <typename... Rest>
      48             :   void WriteToBuffer(Address buf, Rest... rest) {
      49             :     static_assert(sizeof...(rest) == 0, "this is the base case");
      50             :   }
      51             : 
      52             :   template <typename First, typename... Rest>
      53       10984 :   void WriteToBuffer(Address buf, First first, Rest... rest) {
      54             :     WriteUnalignedValue(buf, first);
      55       10984 :     WriteToBuffer(buf + sizeof(first), rest...);
      56       10984 :   }
      57             : 
      58       11404 :   void CheckCall(Args... args) {
      59       11404 :     std::vector<uint8_t> arg_buffer(sizeof...(args) * 8);
      60       10064 :     WriteToBuffer(reinterpret_cast<Address>(arg_buffer.data()), args...);
      61             : 
      62       11404 :     Handle<Object> receiver = isolate_->factory()->undefined_value();
      63             :     Handle<Object> buffer_obj(
      64       11404 :         Object(reinterpret_cast<Address>(arg_buffer.data())), isolate_);
      65       11404 :     CHECK(!buffer_obj->IsHeapObject());
      66       11404 :     Handle<Object> code_entry_obj(Object(wasm_code_->instruction_start()),
      67       11404 :                                   isolate_);
      68       11404 :     CHECK(!code_entry_obj->IsHeapObject());
      69             :     Handle<Object> call_args[]{code_entry_obj,
      70       22808 :                                runner_.builder().instance_object(), buffer_obj};
      71             :     static_assert(
      72             :         arraysize(call_args) == compiler::CWasmEntryParameters::kNumParameters,
      73             :         "adapt this test");
      74       11404 :     wasm_code_->native_module()->SetExecutable(true);
      75       22808 :     MaybeHandle<Object> return_obj = Execution::Call(
      76       11404 :         isolate_, c_wasm_entry_fn_, receiver, arraysize(call_args), call_args);
      77       11404 :     CHECK(!return_obj.is_null());
      78       11404 :     CHECK(return_obj.ToHandleChecked()->IsSmi());
      79       11404 :     CHECK_EQ(0, Smi::ToInt(*return_obj.ToHandleChecked()));
      80             : 
      81             :     // Check the result.
      82             :     ReturnType result = ReadUnalignedValue<ReturnType>(
      83             :         reinterpret_cast<Address>(arg_buffer.data()));
      84             :     ReturnType expected = expected_fn_(args...);
      85             :     if (std::is_floating_point<ReturnType>::value) {
      86       10848 :       CHECK_DOUBLE_EQ(expected, result);
      87             :     } else {
      88         556 :       CHECK_EQ(expected, result);
      89             :     }
      90       11404 :   }
      91             : 
      92             :  private:
      93             :   WasmRunner<ReturnType, Args...> runner_;
      94             :   Isolate* isolate_;
      95             :   std::function<ReturnType(Args...)> expected_fn_;
      96             :   FunctionSig* sig_;
      97             :   Handle<JSFunction> c_wasm_entry_fn_;
      98             :   WasmCode* wasm_code_;
      99             : };
     100             : 
     101             : }  // namespace
     102             : 
     103             : // Pass int32_t, return int32_t.
     104       26643 : TEST(TestCWasmEntryArgPassing_int32) {
     105             :   CWasmEntryArgTester<int32_t, int32_t> tester(
     106             :       {// Return 2*<0> + 1.
     107             :        WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
     108             :       [](int32_t a) {
     109             :         return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
     110          12 :       });
     111             : 
     112         236 :   FOR_INT32_INPUTS(v) { tester.CheckCall(v); }
     113           4 : }
     114             : 
     115             : // Pass int64_t, return double.
     116       26643 : TEST(TestCWasmEntryArgPassing_double_int64) {
     117             :   CWasmEntryArgTester<double, int64_t> tester(
     118             :       {// Return (double)<0>.
     119             :        WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))},
     120         336 :       [](int64_t a) { return static_cast<double>(a); });
     121             : 
     122         328 :   FOR_INT64_INPUTS(v) { tester.CheckCall(v); }
     123           4 : }
     124             : 
     125             : // Pass double, return int64_t.
     126       26643 : TEST(TestCWasmEntryArgPassing_int64_double) {
     127             :   CWasmEntryArgTester<int64_t, double> tester(
     128             :       {// Return (int64_t)<0>.
     129             :        WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))},
     130         336 :       [](double d) { return static_cast<int64_t>(d); });
     131             : 
     132         328 :   FOR_INT64_INPUTS(i) { tester.CheckCall(i); }
     133           4 : }
     134             : 
     135             : // Pass float, return double.
     136       26643 : TEST(TestCWasmEntryArgPassing_float_double) {
     137             :   CWasmEntryArgTester<double, float> tester(
     138             :       {// Return 2*(double)<0> + 1.
     139             :        WASM_F64_ADD(
     140             :            WASM_F64_MUL(WASM_F64(2), WASM_F64_CONVERT_F32(WASM_GET_LOCAL(0))),
     141             :            WASM_F64(1))},
     142         472 :       [](float f) { return 2. * static_cast<double>(f) + 1.; });
     143             : 
     144         464 :   FOR_FLOAT32_INPUTS(f) { tester.CheckCall(f); }
     145           4 : }
     146             : 
     147             : // Pass two doubles, return double.
     148       26643 : TEST(TestCWasmEntryArgPassing_double_double) {
     149             :   CWasmEntryArgTester<double, double, double> tester(
     150             :       {// Return <0> + <1>.
     151             :        WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))},
     152        9616 :       [](double a, double b) { return a + b; });
     153             : 
     154         396 :   FOR_FLOAT64_INPUTS(d1) {
     155        9800 :     FOR_FLOAT64_INPUTS(d2) { tester.CheckCall(d1, d2); }
     156             :   }
     157           4 : }
     158             : 
     159             : // Pass int32_t, int64_t, float and double, return double.
     160       26643 : TEST(TestCWasmEntryArgPassing_AllTypes) {
     161             :   CWasmEntryArgTester<double, int32_t, int64_t, float, double> tester(
     162             :       {
     163             :           // Convert all arguments to double, add them and return the sum.
     164             :           WASM_F64_ADD(          // <0+1+2> + <3>
     165             :               WASM_F64_ADD(      // <0+1> + <2>
     166             :                   WASM_F64_ADD(  // <0> + <1>
     167             :                       WASM_F64_SCONVERT_I32(
     168             :                           WASM_GET_LOCAL(0)),  // <0> to double
     169             :                       WASM_F64_SCONVERT_I64(
     170             :                           WASM_GET_LOCAL(1))),               // <1> to double
     171             :                   WASM_F64_CONVERT_F32(WASM_GET_LOCAL(2))),  // <2> to double
     172             :               WASM_GET_LOCAL(3))                             // <3>
     173             :       },
     174             :       [](int32_t a, int64_t b, float c, double d) {
     175         460 :         return 0. + a + b + c + d;
     176         472 :       });
     177             : 
     178             :   Vector<const int32_t> test_values_i32 = compiler::ValueHelper::int32_vector();
     179             :   Vector<const int64_t> test_values_i64 = compiler::ValueHelper::int64_vector();
     180             :   Vector<const float> test_values_f32 = compiler::ValueHelper::float32_vector();
     181             :   Vector<const double> test_values_f64 =
     182             :       compiler::ValueHelper::float64_vector();
     183             :   size_t max_len =
     184           4 :       std::max(std::max(test_values_i32.size(), test_values_i64.size()),
     185           8 :                std::max(test_values_f32.size(), test_values_f64.size()));
     186         924 :   for (size_t i = 0; i < max_len; ++i) {
     187         920 :     int32_t i32 = test_values_i32[i % test_values_i32.size()];
     188         920 :     int64_t i64 = test_values_i64[i % test_values_i64.size()];
     189         920 :     float f32 = test_values_f32[i % test_values_f32.size()];
     190         920 :     double f64 = test_values_f64[i % test_values_f64.size()];
     191         460 :     tester.CheckCall(i32, i64, f32, f64);
     192             :   }
     193           4 : }
     194             : 
     195             : }  // namespace wasm
     196             : }  // namespace internal
     197       79917 : }  // namespace v8

Generated by: LCOV version 1.10