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: 58 58 100.0 %
Date: 2017-10-20 Functions: 26 26 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/objects-inl.h"
       9             : #include "src/wasm/wasm-objects.h"
      10             : #include "test/cctest/cctest.h"
      11             : #include "test/cctest/compiler/value-helper.h"
      12             : #include "test/cctest/wasm/wasm-run-utils.h"
      13             : #include "test/common/wasm/wasm-macro-gen.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace wasm {
      18             : 
      19             : /**
      20             :  * We test the interface from C to compiled wasm code by generating a wasm
      21             :  * function, creating a corresponding signature, compiling the c wasm entry for
      22             :  * that signature, and then calling that entry using different test values.
      23             :  * The result is compared against the expected result, computed from a lambda
      24             :  * passed to the CWasmEntryArgTester.
      25             :  */
      26             : namespace {
      27             : 
      28             : template <typename ReturnType, typename... Args>
      29          72 : class CWasmEntryArgTester {
      30             :  public:
      31          36 :   CWasmEntryArgTester(std::initializer_list<uint8_t> wasm_function_bytes,
      32             :                       std::function<ReturnType(Args...)> expected_fn)
      33             :       : runner_(kExecuteCompiled),
      34             :         isolate_(runner_.main_isolate()),
      35             :         expected_fn_(expected_fn),
      36          72 :         sig_(runner_.template CreateSig<ReturnType, Args...>()) {
      37             :     std::vector<uint8_t> code{wasm_function_bytes};
      38          72 :     runner_.Build(code.data(), code.data() + code.size());
      39          36 :     wasm_code_ = runner_.builder().GetFunctionCode(0);
      40          36 :     Handle<WasmInstanceObject> instance(runner_.builder().instance_object());
      41             :     Handle<WasmDebugInfo> debug_info =
      42          36 :         WasmInstanceObject::GetOrCreateDebugInfo(instance);
      43          36 :     c_wasm_entry_fn_ = WasmDebugInfo::GetCWasmEntry(debug_info, sig_);
      44          36 :   }
      45             : 
      46             :   template <typename... Rest>
      47             :   void WriteToBuffer(uint8_t* buf, Rest... rest) {
      48             :     static_assert(sizeof...(rest) == 0, "this is the base case");
      49             :   }
      50             : 
      51             :   template <typename First, typename... Rest>
      52             :   void WriteToBuffer(uint8_t* buf, First first, Rest... rest) {
      53             :     WriteUnalignedValue(buf, first);
      54             :     WriteToBuffer(buf + sizeof(first), rest...);
      55             :   }
      56             : 
      57       17106 :   void CheckCall(Args... args) {
      58       17106 :     std::vector<uint8_t> arg_buffer(sizeof...(args) * 8);
      59             :     WriteToBuffer(arg_buffer.data(), args...);
      60             : 
      61       17106 :     Handle<Object> receiver = isolate_->factory()->undefined_value();
      62             :     Handle<Object> buffer_obj(reinterpret_cast<Object*>(arg_buffer.data()),
      63             :                               isolate_);
      64       17106 :     CHECK(!buffer_obj->IsHeapObject());
      65       17106 :     Handle<Object> call_args[]{wasm_code_, buffer_obj};
      66             :     static_assert(
      67             :         arraysize(call_args) == compiler::CWasmEntryParameters::kNumParameters,
      68             :         "adapt this test");
      69             :     MaybeHandle<Object> return_obj = Execution::Call(
      70       17106 :         isolate_, c_wasm_entry_fn_, receiver, arraysize(call_args), call_args);
      71       17106 :     CHECK(!return_obj.is_null());
      72       17106 :     CHECK(return_obj.ToHandleChecked()->IsSmi());
      73       17106 :     CHECK_EQ(0, Smi::ToInt(*return_obj.ToHandleChecked()));
      74             : 
      75             :     // Check the result.
      76             :     ReturnType result = ReadUnalignedValue<ReturnType>(arg_buffer.data());
      77       17106 :     ReturnType expected = expected_fn_(args...);
      78             :     if (std::is_floating_point<ReturnType>::value) {
      79       16272 :       CHECK_DOUBLE_EQ(expected, result);
      80             :     } else {
      81         834 :       CHECK_EQ(expected, result);
      82             :     }
      83       17106 :   }
      84             : 
      85             :  private:
      86             :   WasmRunner<ReturnType, Args...> runner_;
      87             :   Isolate* isolate_;
      88             :   std::function<ReturnType(Args...)> expected_fn_;
      89             :   FunctionSig* sig_;
      90             :   Handle<JSFunction> c_wasm_entry_fn_;
      91             :   Handle<Code> wasm_code_;
      92             : };
      93             : 
      94             : }  // namespace
      95             : 
      96             : // Pass int32_t, return int32_t.
      97       23724 : TEST(TestCWasmEntryArgPassing_int32) {
      98             :   CWasmEntryArgTester<int32_t, int32_t> tester(
      99             :       {// Return 2*<0> + 1.
     100             :        WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
     101         360 :       [](int32_t a) { return 2 * a + 1; });
     102             : 
     103           6 :   FOR_INT32_INPUTS(v) { tester.CheckCall(*v); }
     104           6 : }
     105             : 
     106             : // Pass int64_t, return double.
     107       23724 : TEST(TestCWasmEntryArgPassing_double_int64) {
     108             :   CWasmEntryArgTester<double, int64_t> tester(
     109             :       {// Return (double)<0>.
     110             :        WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))},
     111         498 :       [](int64_t a) { return static_cast<double>(a); });
     112             : 
     113           6 :   FOR_INT64_INPUTS(v) { tester.CheckCall(*v); }
     114           6 : }
     115             : 
     116             : // Pass double, return int64_t.
     117       23724 : TEST(TestCWasmEntryArgPassing_int64_double) {
     118             :   CWasmEntryArgTester<int64_t, double> tester(
     119             :       {// Return (int64_t)<0>.
     120             :        WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))},
     121         498 :       [](double d) { return static_cast<int64_t>(d); });
     122             : 
     123           6 :   FOR_INT64_INPUTS(i) { tester.CheckCall(*i); }
     124           6 : }
     125             : 
     126             : // Pass float, return double.
     127       23724 : TEST(TestCWasmEntryArgPassing_float_double) {
     128             :   CWasmEntryArgTester<double, float> tester(
     129             :       {// Return 2*(double)<0> + 1.
     130             :        WASM_F64_ADD(
     131             :            WASM_F64_MUL(WASM_F64(2), WASM_F64_CONVERT_F32(WASM_GET_LOCAL(0))),
     132             :            WASM_F64(1))},
     133         702 :       [](float f) { return 2. * static_cast<double>(f) + 1.; });
     134             : 
     135           6 :   FOR_FLOAT32_INPUTS(f) { tester.CheckCall(*f); }
     136           6 : }
     137             : 
     138             : // Pass two doubles, return double.
     139       23724 : TEST(TestCWasmEntryArgPassing_double_double) {
     140             :   CWasmEntryArgTester<double, double, double> tester(
     141             :       {// Return <0> + <1>.
     142             :        WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))},
     143       14418 :       [](double a, double b) { return a + b; });
     144             : 
     145         300 :   FOR_FLOAT64_INPUTS(d1) {
     146       14406 :     FOR_FLOAT64_INPUTS(d2) { tester.CheckCall(*d1, *d2); }
     147           6 :   }
     148           6 : }
     149             : 
     150             : // Pass int32_t, int64_t, float and double, return double.
     151       23724 : TEST(TestCWasmEntryArgPassing_AllTypes) {
     152             :   CWasmEntryArgTester<double, int32_t, int64_t, float, double> tester(
     153             :       {
     154             :           // Convert all arguments to double, add them and return the sum.
     155             :           WASM_F64_ADD(          // <0+1+2> + <3>
     156             :               WASM_F64_ADD(      // <0+1> + <2>
     157             :                   WASM_F64_ADD(  // <0> + <1>
     158             :                       WASM_F64_SCONVERT_I32(
     159             :                           WASM_GET_LOCAL(0)),  // <0> to double
     160             :                       WASM_F64_SCONVERT_I64(
     161             :                           WASM_GET_LOCAL(1))),               // <1> to double
     162             :                   WASM_F64_CONVERT_F32(WASM_GET_LOCAL(2))),  // <2> to double
     163             :               WASM_GET_LOCAL(3))                             // <3>
     164             :       },
     165             :       [](int32_t a, int64_t b, float c, double d) {
     166         690 :         return 0. + a + b + c + d;
     167         702 :       });
     168             : 
     169             :   Vector<const int32_t> test_values_i32 = compiler::ValueHelper::int32_vector();
     170             :   Vector<const int64_t> test_values_i64 = compiler::ValueHelper::int64_vector();
     171             :   Vector<const float> test_values_f32 = compiler::ValueHelper::float32_vector();
     172             :   Vector<const double> test_values_f64 =
     173             :       compiler::ValueHelper::float64_vector();
     174             :   size_t max_len =
     175          12 :       std::max(std::max(test_values_i32.size(), test_values_i64.size()),
     176          18 :                std::max(test_values_f32.size(), test_values_f64.size()));
     177         696 :   for (size_t i = 0; i < max_len; ++i) {
     178        1380 :     int32_t i32 = test_values_i32[i % test_values_i32.size()];
     179        1380 :     int64_t i64 = test_values_i64[i % test_values_i64.size()];
     180        1380 :     float f32 = test_values_f32[i % test_values_f32.size()];
     181        1380 :     double f64 = test_values_f64[i % test_values_f64.size()];
     182         690 :     tester.CheckCall(i32, i64, f32, f64);
     183           6 :   }
     184           6 : }
     185             : 
     186             : }  // namespace wasm
     187             : }  // namespace internal
     188       71154 : }  // namespace v8

Generated by: LCOV version 1.10