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