Home | History | Annotate | Download | only in wasm
      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 <stdint.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 
     10 #include "src/wasm/wasm-macro-gen.h"
     11 
     12 #include "test/cctest/cctest.h"
     13 #include "test/cctest/compiler/value-helper.h"
     14 #include "test/cctest/wasm/test-signatures.h"
     15 #include "test/cctest/wasm/wasm-run-utils.h"
     16 
     17 using namespace v8::base;
     18 using namespace v8::internal;
     19 using namespace v8::internal::compiler;
     20 using namespace v8::internal::wasm;
     21 
     22 #define BUILD(r, ...)                      \
     23   do {                                     \
     24     byte code[] = {__VA_ARGS__};           \
     25     r.Build(code, code + arraysize(code)); \
     26   } while (false)
     27 
     28 #define ADD_CODE(vec, ...)                                              \
     29   do {                                                                  \
     30     byte __buf[] = {__VA_ARGS__};                                       \
     31     for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \
     32   } while (false)
     33 
     34 namespace {
     35 // A helper for generating predictable but unique argument values that
     36 // are easy to debug (e.g. with misaligned stacks).
     37 class PredictableInputValues {
     38  public:
     39   int base_;
     40   explicit PredictableInputValues(int base) : base_(base) {}
     41   double arg_d(int which) { return base_ * which + ((which & 1) * 0.5); }
     42   float arg_f(int which) { return base_ * which + ((which & 1) * 0.25); }
     43   int32_t arg_i(int which) { return base_ * which + ((which & 1) * kMinInt); }
     44   int64_t arg_l(int which) {
     45     return base_ * which + ((which & 1) * (0x04030201LL << 32));
     46   }
     47 };
     48 
     49 uint32_t AddJSSelector(TestingModule* module, FunctionSig* sig, int which) {
     50   const int kMaxParams = 11;
     51   static const char* formals[kMaxParams] = {"",
     52                                             "a",
     53                                             "a,b",
     54                                             "a,b,c",
     55                                             "a,b,c,d",
     56                                             "a,b,c,d,e",
     57                                             "a,b,c,d,e,f",
     58                                             "a,b,c,d,e,f,g",
     59                                             "a,b,c,d,e,f,g,h",
     60                                             "a,b,c,d,e,f,g,h,i",
     61                                             "a,b,c,d,e,f,g,h,i,j"};
     62   CHECK_LT(which, static_cast<int>(sig->parameter_count()));
     63   CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams);
     64 
     65   i::EmbeddedVector<char, 256> source;
     66   char param = 'a' + which;
     67   SNPrintF(source, "(function(%s) { return %c; })",
     68            formals[sig->parameter_count()], param);
     69 
     70   return module->AddJsFunction(sig, source.start());
     71 }
     72 
     73 void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc,
     74                  Handle<Object>* buffer, int count) {
     75   Isolate* isolate = jsfunc->GetIsolate();
     76   Handle<Object> global(isolate->context()->global_object(), isolate);
     77   MaybeHandle<Object> retval =
     78       Execution::Call(isolate, jsfunc, global, count, buffer);
     79 
     80   CHECK(!retval.is_null());
     81   Handle<Object> result = retval.ToHandleChecked();
     82   if (result->IsSmi()) {
     83     CHECK_EQ(expected, Smi::cast(*result)->value());
     84   } else {
     85     CHECK(result->IsHeapNumber());
     86     CheckFloatEq(expected, HeapNumber::cast(*result)->value());
     87   }
     88 }
     89 
     90 void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a,
     91                  double b) {
     92   Isolate* isolate = jsfunc->GetIsolate();
     93   Handle<Object> buffer[] = {isolate->factory()->NewNumber(a),
     94                              isolate->factory()->NewNumber(b)};
     95   EXPECT_CALL(expected, jsfunc, buffer, 2);
     96 }
     97 }  // namespace
     98 
     99 TEST(Run_Int32Sub_jswrapped) {
    100   TestSignatures sigs;
    101   TestingModule module;
    102   WasmFunctionCompiler t(sigs.i_ii(), &module);
    103   BUILD(t, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
    104   Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    105 
    106   EXPECT_CALL(33, jsfunc, 44, 11);
    107   EXPECT_CALL(-8723487, jsfunc, -8000000, 723487);
    108 }
    109 
    110 TEST(Run_Float32Div_jswrapped) {
    111   TestSignatures sigs;
    112   TestingModule module;
    113   WasmFunctionCompiler t(sigs.f_ff(), &module);
    114   BUILD(t, WASM_F32_DIV(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
    115   Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    116 
    117   EXPECT_CALL(92, jsfunc, 46, 0.5);
    118   EXPECT_CALL(64, jsfunc, -16, -0.25);
    119 }
    120 
    121 TEST(Run_Float64Add_jswrapped) {
    122   TestSignatures sigs;
    123   TestingModule module;
    124   WasmFunctionCompiler t(sigs.d_dd(), &module);
    125   BUILD(t, WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
    126   Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    127 
    128   EXPECT_CALL(3, jsfunc, 2, 1);
    129   EXPECT_CALL(-5.5, jsfunc, -5.25, -0.25);
    130 }
    131 
    132 TEST(Run_I32Popcount_jswrapped) {
    133   TestSignatures sigs;
    134   TestingModule module;
    135   WasmFunctionCompiler t(sigs.i_i(), &module);
    136   BUILD(t, WASM_I32_POPCNT(WASM_GET_LOCAL(0)));
    137   Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    138 
    139   EXPECT_CALL(2, jsfunc, 9, 0);
    140   EXPECT_CALL(3, jsfunc, 11, 0);
    141   EXPECT_CALL(6, jsfunc, 0x3F, 0);
    142 }
    143 
    144 TEST(Run_CallJS_Add_jswrapped) {
    145   TestSignatures sigs;
    146   TestingModule module;
    147   WasmFunctionCompiler t(sigs.i_i(), &module);
    148   uint32_t js_index =
    149       module.AddJsFunction(sigs.i_i(), "(function(a) { return a + 99; })");
    150   BUILD(t, WASM_CALL_FUNCTION1(js_index, WASM_GET_LOCAL(0)));
    151 
    152   Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    153 
    154   EXPECT_CALL(101, jsfunc, 2, -8);
    155   EXPECT_CALL(199, jsfunc, 100, -1);
    156   EXPECT_CALL(-666666801, jsfunc, -666666900, -1);
    157 }
    158 
    159 void RunJSSelectTest(int which) {
    160   const int kMaxParams = 8;
    161   PredictableInputValues inputs(0x100);
    162   LocalType type = kAstF64;
    163   LocalType types[kMaxParams + 1] = {type, type, type, type, type,
    164                                      type, type, type, type};
    165   for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
    166     HandleScope scope(CcTest::InitIsolateOnce());
    167     FunctionSig sig(1, num_params, types);
    168 
    169     TestingModule module;
    170     uint32_t js_index = AddJSSelector(&module, &sig, which);
    171     WasmFunctionCompiler t(&sig, &module);
    172 
    173     {
    174       std::vector<byte> code;
    175 
    176       for (int i = 0; i < num_params; i++) {
    177         ADD_CODE(code, WASM_F64(inputs.arg_d(i)));
    178       }
    179 
    180       ADD_CODE(code, kExprCallFunction, static_cast<byte>(num_params),
    181                static_cast<byte>(js_index));
    182 
    183       size_t end = code.size();
    184       code.push_back(0);
    185       t.Build(&code[0], &code[end]);
    186     }
    187 
    188     Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    189     double expected = inputs.arg_d(which);
    190     EXPECT_CALL(expected, jsfunc, 0.0, 0.0);
    191   }
    192 }
    193 
    194 TEST(Run_JSSelect_0) { RunJSSelectTest(0); }
    195 
    196 TEST(Run_JSSelect_1) { RunJSSelectTest(1); }
    197 
    198 TEST(Run_JSSelect_2) { RunJSSelectTest(2); }
    199 
    200 TEST(Run_JSSelect_3) { RunJSSelectTest(3); }
    201 
    202 TEST(Run_JSSelect_4) { RunJSSelectTest(4); }
    203 
    204 TEST(Run_JSSelect_5) { RunJSSelectTest(5); }
    205 
    206 TEST(Run_JSSelect_6) { RunJSSelectTest(6); }
    207 
    208 TEST(Run_JSSelect_7) { RunJSSelectTest(7); }
    209 
    210 void RunWASMSelectTest(int which) {
    211   PredictableInputValues inputs(0x200);
    212   Isolate* isolate = CcTest::InitIsolateOnce();
    213   const int kMaxParams = 8;
    214   for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
    215     LocalType type = kAstF64;
    216     LocalType types[kMaxParams + 1] = {type, type, type, type, type,
    217                                        type, type, type, type};
    218     FunctionSig sig(1, num_params, types);
    219 
    220     TestingModule module;
    221     WasmFunctionCompiler t(&sig, &module);
    222     BUILD(t, WASM_GET_LOCAL(which));
    223     Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    224 
    225     Handle<Object> args[] = {
    226         isolate->factory()->NewNumber(inputs.arg_d(0)),
    227         isolate->factory()->NewNumber(inputs.arg_d(1)),
    228         isolate->factory()->NewNumber(inputs.arg_d(2)),
    229         isolate->factory()->NewNumber(inputs.arg_d(3)),
    230         isolate->factory()->NewNumber(inputs.arg_d(4)),
    231         isolate->factory()->NewNumber(inputs.arg_d(5)),
    232         isolate->factory()->NewNumber(inputs.arg_d(6)),
    233         isolate->factory()->NewNumber(inputs.arg_d(7)),
    234     };
    235 
    236     double expected = inputs.arg_d(which);
    237     EXPECT_CALL(expected, jsfunc, args, kMaxParams);
    238   }
    239 }
    240 
    241 TEST(Run_WASMSelect_0) { RunWASMSelectTest(0); }
    242 
    243 TEST(Run_WASMSelect_1) { RunWASMSelectTest(1); }
    244 
    245 TEST(Run_WASMSelect_2) { RunWASMSelectTest(2); }
    246 
    247 TEST(Run_WASMSelect_3) { RunWASMSelectTest(3); }
    248 
    249 TEST(Run_WASMSelect_4) { RunWASMSelectTest(4); }
    250 
    251 TEST(Run_WASMSelect_5) { RunWASMSelectTest(5); }
    252 
    253 TEST(Run_WASMSelect_6) { RunWASMSelectTest(6); }
    254 
    255 TEST(Run_WASMSelect_7) { RunWASMSelectTest(7); }
    256 
    257 void RunWASMSelectAlignTest(int num_args, int num_params) {
    258   PredictableInputValues inputs(0x300);
    259   Isolate* isolate = CcTest::InitIsolateOnce();
    260   const int kMaxParams = 10;
    261   DCHECK_LE(num_args, kMaxParams);
    262   LocalType type = kAstF64;
    263   LocalType types[kMaxParams + 1] = {type, type, type, type, type, type,
    264                                      type, type, type, type, type};
    265   FunctionSig sig(1, num_params, types);
    266 
    267   for (int which = 0; which < num_params; which++) {
    268     TestingModule module;
    269     WasmFunctionCompiler t(&sig, &module);
    270     BUILD(t, WASM_GET_LOCAL(which));
    271     Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    272 
    273     Handle<Object> args[] = {isolate->factory()->NewNumber(inputs.arg_d(0)),
    274                              isolate->factory()->NewNumber(inputs.arg_d(1)),
    275                              isolate->factory()->NewNumber(inputs.arg_d(2)),
    276                              isolate->factory()->NewNumber(inputs.arg_d(3)),
    277                              isolate->factory()->NewNumber(inputs.arg_d(4)),
    278                              isolate->factory()->NewNumber(inputs.arg_d(5)),
    279                              isolate->factory()->NewNumber(inputs.arg_d(6)),
    280                              isolate->factory()->NewNumber(inputs.arg_d(7)),
    281                              isolate->factory()->NewNumber(inputs.arg_d(8)),
    282                              isolate->factory()->NewNumber(inputs.arg_d(9))};
    283 
    284     double nan = std::numeric_limits<double>::quiet_NaN();
    285     double expected = which < num_args ? inputs.arg_d(which) : nan;
    286     EXPECT_CALL(expected, jsfunc, args, num_args);
    287   }
    288 }
    289 
    290 TEST(Run_WASMSelectAlign_0) {
    291   RunWASMSelectAlignTest(0, 1);
    292   RunWASMSelectAlignTest(0, 2);
    293 }
    294 
    295 TEST(Run_WASMSelectAlign_1) {
    296   RunWASMSelectAlignTest(1, 2);
    297   RunWASMSelectAlignTest(1, 3);
    298 }
    299 
    300 TEST(Run_WASMSelectAlign_2) {
    301   RunWASMSelectAlignTest(2, 3);
    302   RunWASMSelectAlignTest(2, 4);
    303 }
    304 
    305 TEST(Run_WASMSelectAlign_3) {
    306   RunWASMSelectAlignTest(3, 3);
    307   RunWASMSelectAlignTest(3, 4);
    308 }
    309 
    310 TEST(Run_WASMSelectAlign_4) {
    311   RunWASMSelectAlignTest(4, 3);
    312   RunWASMSelectAlignTest(4, 4);
    313 }
    314 
    315 TEST(Run_WASMSelectAlign_7) {
    316   RunWASMSelectAlignTest(7, 5);
    317   RunWASMSelectAlignTest(7, 6);
    318   RunWASMSelectAlignTest(7, 7);
    319 }
    320 
    321 TEST(Run_WASMSelectAlign_8) {
    322   RunWASMSelectAlignTest(8, 5);
    323   RunWASMSelectAlignTest(8, 6);
    324   RunWASMSelectAlignTest(8, 7);
    325   RunWASMSelectAlignTest(8, 8);
    326 }
    327 
    328 TEST(Run_WASMSelectAlign_9) {
    329   RunWASMSelectAlignTest(9, 6);
    330   RunWASMSelectAlignTest(9, 7);
    331   RunWASMSelectAlignTest(9, 8);
    332   RunWASMSelectAlignTest(9, 9);
    333 }
    334 
    335 TEST(Run_WASMSelectAlign_10) {
    336   RunWASMSelectAlignTest(10, 7);
    337   RunWASMSelectAlignTest(10, 8);
    338   RunWASMSelectAlignTest(10, 9);
    339   RunWASMSelectAlignTest(10, 10);
    340 }
    341 
    342 void RunJSSelectAlignTest(int num_args, int num_params) {
    343   PredictableInputValues inputs(0x400);
    344   Isolate* isolate = CcTest::InitIsolateOnce();
    345   Factory* factory = isolate->factory();
    346   const int kMaxParams = 10;
    347   CHECK_LE(num_args, kMaxParams);
    348   CHECK_LE(num_params, kMaxParams);
    349   LocalType type = kAstF64;
    350   LocalType types[kMaxParams + 1] = {type, type, type, type, type, type,
    351                                      type, type, type, type, type};
    352   FunctionSig sig(1, num_params, types);
    353 
    354   // Build the calling code.
    355   std::vector<byte> code;
    356 
    357   for (int i = 0; i < num_params; i++) {
    358     ADD_CODE(code, WASM_GET_LOCAL(i));
    359   }
    360 
    361   ADD_CODE(code, kExprCallFunction, static_cast<byte>(num_params), 0);
    362 
    363   size_t end = code.size();
    364   code.push_back(0);
    365 
    366   // Call different select JS functions.
    367   for (int which = 0; which < num_params; which++) {
    368     HandleScope scope(isolate);
    369     TestingModule module;
    370     uint32_t js_index = AddJSSelector(&module, &sig, which);
    371     CHECK_EQ(0, js_index);
    372     WasmFunctionCompiler t(&sig, &module);
    373     t.Build(&code[0], &code[end]);
    374 
    375     Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
    376 
    377     Handle<Object> args[] = {
    378         factory->NewNumber(inputs.arg_d(0)),
    379         factory->NewNumber(inputs.arg_d(1)),
    380         factory->NewNumber(inputs.arg_d(2)),
    381         factory->NewNumber(inputs.arg_d(3)),
    382         factory->NewNumber(inputs.arg_d(4)),
    383         factory->NewNumber(inputs.arg_d(5)),
    384         factory->NewNumber(inputs.arg_d(6)),
    385         factory->NewNumber(inputs.arg_d(7)),
    386         factory->NewNumber(inputs.arg_d(8)),
    387         factory->NewNumber(inputs.arg_d(9)),
    388     };
    389 
    390     double nan = std::numeric_limits<double>::quiet_NaN();
    391     double expected = which < num_args ? inputs.arg_d(which) : nan;
    392     EXPECT_CALL(expected, jsfunc, args, num_args);
    393   }
    394 }
    395 
    396 TEST(Run_JSSelectAlign_0) {
    397   RunJSSelectAlignTest(0, 1);
    398   RunJSSelectAlignTest(0, 2);
    399 }
    400 
    401 TEST(Run_JSSelectAlign_1) {
    402   RunJSSelectAlignTest(1, 2);
    403   RunJSSelectAlignTest(1, 3);
    404 }
    405 
    406 TEST(Run_JSSelectAlign_2) {
    407   RunJSSelectAlignTest(2, 3);
    408   RunJSSelectAlignTest(2, 4);
    409 }
    410 
    411 TEST(Run_JSSelectAlign_3) {
    412   RunJSSelectAlignTest(3, 3);
    413   RunJSSelectAlignTest(3, 4);
    414 }
    415 
    416 TEST(Run_JSSelectAlign_4) {
    417   RunJSSelectAlignTest(4, 3);
    418   RunJSSelectAlignTest(4, 4);
    419 }
    420 
    421 TEST(Run_JSSelectAlign_7) {
    422   RunJSSelectAlignTest(7, 3);
    423   RunJSSelectAlignTest(7, 4);
    424   RunJSSelectAlignTest(7, 4);
    425   RunJSSelectAlignTest(7, 4);
    426 }
    427 
    428 TEST(Run_JSSelectAlign_8) {
    429   RunJSSelectAlignTest(8, 5);
    430   RunJSSelectAlignTest(8, 6);
    431   RunJSSelectAlignTest(8, 7);
    432   RunJSSelectAlignTest(8, 8);
    433 }
    434 
    435 TEST(Run_JSSelectAlign_9) {
    436   RunJSSelectAlignTest(9, 6);
    437   RunJSSelectAlignTest(9, 7);
    438   RunJSSelectAlignTest(9, 8);
    439   RunJSSelectAlignTest(9, 9);
    440 }
    441 
    442 TEST(Run_JSSelectAlign_10) {
    443   RunJSSelectAlignTest(10, 7);
    444   RunJSSelectAlignTest(10, 8);
    445   RunJSSelectAlignTest(10, 9);
    446   RunJSSelectAlignTest(10, 10);
    447 }
    448