v8/test/cctest/wasm/test-run-wasm-js.cc
Clemens Backes 61c2a0f4ba [wasm] Remove interpreter entry code
This removes the interpreter entry stubs, which are used to redirect
specific wasm functions to the interpreter. It is only needed when
mixing JS code with interpreted Wasm code, otherwise the test functions
just call the interpreter directly.
Thus a lot of tests that contain such interaction between JS and Wasm
need to be restricted to execute in Liftoff and TurboFan only.

After this CL, the WASM_INTERPRETER_ENTRY frame type and the
corresponding WasmInterpreterEntryFrame are dead, and will be removed in
a follow-up CL.

R=thibaudm@chromium.org

Bug: v8:10389
Change-Id: I8e50d350dbc2afcc1cddaeb98baf23711117af2d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2172962
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67559}
2020-05-05 11:18:05 +00:00

576 lines
19 KiB
C++

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "src/api/api-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/objects/heap-number-inl.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
#include "test/cctest/wasm/wasm-run-utils.h"
#include "test/common/wasm/test-signatures.h"
#include "test/common/wasm/wasm-macro-gen.h"
namespace v8 {
namespace internal {
namespace wasm {
#define ADD_CODE(vec, ...) \
do { \
byte __buf[] = {__VA_ARGS__}; \
for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \
} while (false)
namespace {
// A helper for generating predictable but unique argument values that
// are easy to debug (e.g. with misaligned stacks).
class PredictableInputValues {
public:
int base_;
explicit PredictableInputValues(int base) : base_(base) {}
double arg_d(int which) { return base_ * which + ((which & 1) * 0.5); }
float arg_f(int which) { return base_ * which + ((which & 1) * 0.25); }
int32_t arg_i(int which) { return base_ * which + ((which & 1) * kMinInt); }
int64_t arg_l(int which) {
return base_ * which + ((which & 1) * (0x04030201LL << 32));
}
};
ManuallyImportedJSFunction CreateJSSelector(FunctionSig* sig, int which) {
const int kMaxParams = 11;
static const char* formals[kMaxParams] = {"",
"a",
"a,b",
"a,b,c",
"a,b,c,d",
"a,b,c,d,e",
"a,b,c,d,e,f",
"a,b,c,d,e,f,g",
"a,b,c,d,e,f,g,h",
"a,b,c,d,e,f,g,h,i",
"a,b,c,d,e,f,g,h,i,j"};
CHECK_LT(which, static_cast<int>(sig->parameter_count()));
CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams);
i::EmbeddedVector<char, 256> source;
char param = 'a' + which;
SNPrintF(source, "(function(%s) { return %c; })",
formals[sig->parameter_count()], param);
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source.begin()))));
ManuallyImportedJSFunction import = {sig, js_function};
return import;
}
} // namespace
WASM_COMPILED_EXEC_TEST(Run_Int32Sub_jswrapped) {
WasmRunner<int, int, int> r(execution_tier);
BUILD(r, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
r.CheckCallViaJS(33, 44, 11);
r.CheckCallViaJS(-8723487, -8000000, 723487);
}
WASM_COMPILED_EXEC_TEST(Run_Float32Div_jswrapped) {
WasmRunner<float, float, float> r(execution_tier);
BUILD(r, WASM_F32_DIV(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
r.CheckCallViaJS(92, 46, 0.5);
r.CheckCallViaJS(64, -16, -0.25);
}
WASM_COMPILED_EXEC_TEST(Run_Float64Add_jswrapped) {
WasmRunner<double, double, double> r(execution_tier);
BUILD(r, WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
r.CheckCallViaJS(3, 2, 1);
r.CheckCallViaJS(-5.5, -5.25, -0.25);
}
WASM_COMPILED_EXEC_TEST(Run_I32Popcount_jswrapped) {
WasmRunner<int, int> r(execution_tier);
BUILD(r, WASM_I32_POPCNT(WASM_GET_LOCAL(0)));
r.CheckCallViaJS(2, 9);
r.CheckCallViaJS(3, 11);
r.CheckCallViaJS(6, 0x3F);
}
WASM_COMPILED_EXEC_TEST(Run_CallJS_Add_jswrapped) {
TestSignatures sigs;
HandleScope scope(CcTest::InitIsolateOnce());
const char* source = "(function(a) { return a + 99; })";
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
ManuallyImportedJSFunction import = {sigs.i_i(), js_function};
WasmRunner<int, int> r(execution_tier, &import);
uint32_t js_index = 0;
BUILD(r, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0)));
r.CheckCallViaJS(101, 2);
r.CheckCallViaJS(199, 100);
r.CheckCallViaJS(-666666801, -666666900);
}
WASM_COMPILED_EXEC_TEST(Run_IndirectCallJSFunction) {
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
TestSignatures sigs;
const char* source = "(function(a, b, c) { if(c) return a; return b; })";
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
ManuallyImportedJSFunction import = {sigs.i_iii(), js_function};
WasmRunner<int32_t, int32_t> r(execution_tier, &import);
const uint32_t js_index = 0;
const int32_t left = -2;
const int32_t right = 3;
WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc");
byte sig_index = r.builder().AddSignature(sigs.i_iii());
uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)};
r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table));
BUILD(rc_fn, WASM_CALL_INDIRECT(sig_index, WASM_I32V(left), WASM_I32V(right),
WASM_GET_LOCAL(0), WASM_I32V(js_index)));
Handle<Object> args_left[] = {isolate->factory()->NewNumber(1)};
r.CheckCallApplyViaJS(left, rc_fn.function_index(), args_left, 1);
Handle<Object> args_right[] = {isolate->factory()->NewNumber(0)};
r.CheckCallApplyViaJS(right, rc_fn.function_index(), args_right, 1);
}
void RunJSSelectTest(ExecutionTier tier, int which) {
const int kMaxParams = 8;
PredictableInputValues inputs(0x100);
ValueType type = kWasmF64;
ValueType types[kMaxParams + 1] = {type, type, type, type, type,
type, type, type, type};
for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
HandleScope scope(CcTest::InitIsolateOnce());
FunctionSig sig(1, num_params, types);
ManuallyImportedJSFunction import = CreateJSSelector(&sig, which);
WasmRunner<void> r(tier, &import);
uint32_t js_index = 0;
WasmFunctionCompiler& t = r.NewFunction(&sig);
{
std::vector<byte> code;
for (int i = 0; i < num_params; i++) {
ADD_CODE(code, WASM_F64(inputs.arg_d(i)));
}
ADD_CODE(code, kExprCallFunction, static_cast<byte>(js_index));
size_t end = code.size();
code.push_back(0);
t.Build(&code[0], &code[end]);
}
double expected = inputs.arg_d(which);
r.CheckCallApplyViaJS(expected, t.function_index(), nullptr, 0);
}
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_0) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 0);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_1) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 1);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_2) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 2);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_3) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 3);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_4) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 4);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_5) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 5);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_6) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 6);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelect_7) {
CcTest::InitializeVM();
RunJSSelectTest(execution_tier, 7);
}
void RunWASMSelectTest(ExecutionTier tier, int which) {
PredictableInputValues inputs(0x200);
Isolate* isolate = CcTest::InitIsolateOnce();
const int kMaxParams = 8;
for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
ValueType type = kWasmF64;
ValueType types[kMaxParams + 1] = {type, type, type, type, type,
type, type, type, type};
FunctionSig sig(1, num_params, types);
WasmRunner<void> r(tier);
WasmFunctionCompiler& t = r.NewFunction(&sig);
BUILD(t, WASM_GET_LOCAL(which));
Handle<Object> args[] = {
isolate->factory()->NewNumber(inputs.arg_d(0)),
isolate->factory()->NewNumber(inputs.arg_d(1)),
isolate->factory()->NewNumber(inputs.arg_d(2)),
isolate->factory()->NewNumber(inputs.arg_d(3)),
isolate->factory()->NewNumber(inputs.arg_d(4)),
isolate->factory()->NewNumber(inputs.arg_d(5)),
isolate->factory()->NewNumber(inputs.arg_d(6)),
isolate->factory()->NewNumber(inputs.arg_d(7)),
};
double expected = inputs.arg_d(which);
r.CheckCallApplyViaJS(expected, t.function_index(), args, kMaxParams);
}
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_0) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 0);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_1) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 1);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_2) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 2);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_3) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 3);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_4) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 4);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_5) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 5);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_6) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 6);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelect_7) {
CcTest::InitializeVM();
RunWASMSelectTest(execution_tier, 7);
}
void RunWASMSelectAlignTest(ExecutionTier tier, int num_args, int num_params) {
PredictableInputValues inputs(0x300);
Isolate* isolate = CcTest::InitIsolateOnce();
const int kMaxParams = 10;
DCHECK_LE(num_args, kMaxParams);
ValueType type = kWasmF64;
ValueType types[kMaxParams + 1] = {type, type, type, type, type, type,
type, type, type, type, type};
FunctionSig sig(1, num_params, types);
for (int which = 0; which < num_params; which++) {
WasmRunner<void> r(tier);
WasmFunctionCompiler& t = r.NewFunction(&sig);
BUILD(t, WASM_GET_LOCAL(which));
Handle<Object> args[] = {isolate->factory()->NewNumber(inputs.arg_d(0)),
isolate->factory()->NewNumber(inputs.arg_d(1)),
isolate->factory()->NewNumber(inputs.arg_d(2)),
isolate->factory()->NewNumber(inputs.arg_d(3)),
isolate->factory()->NewNumber(inputs.arg_d(4)),
isolate->factory()->NewNumber(inputs.arg_d(5)),
isolate->factory()->NewNumber(inputs.arg_d(6)),
isolate->factory()->NewNumber(inputs.arg_d(7)),
isolate->factory()->NewNumber(inputs.arg_d(8)),
isolate->factory()->NewNumber(inputs.arg_d(9))};
double nan = std::numeric_limits<double>::quiet_NaN();
double expected = which < num_args ? inputs.arg_d(which) : nan;
r.CheckCallApplyViaJS(expected, t.function_index(), args, num_args);
}
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_0) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 0, 1);
RunWASMSelectAlignTest(execution_tier, 0, 2);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_1) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 1, 2);
RunWASMSelectAlignTest(execution_tier, 1, 3);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_2) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 2, 3);
RunWASMSelectAlignTest(execution_tier, 2, 4);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_3) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 3, 3);
RunWASMSelectAlignTest(execution_tier, 3, 4);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_4) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 4, 3);
RunWASMSelectAlignTest(execution_tier, 4, 4);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_7) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 7, 5);
RunWASMSelectAlignTest(execution_tier, 7, 6);
RunWASMSelectAlignTest(execution_tier, 7, 7);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_8) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 8, 5);
RunWASMSelectAlignTest(execution_tier, 8, 6);
RunWASMSelectAlignTest(execution_tier, 8, 7);
RunWASMSelectAlignTest(execution_tier, 8, 8);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_9) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 9, 6);
RunWASMSelectAlignTest(execution_tier, 9, 7);
RunWASMSelectAlignTest(execution_tier, 9, 8);
RunWASMSelectAlignTest(execution_tier, 9, 9);
}
WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_10) {
CcTest::InitializeVM();
RunWASMSelectAlignTest(execution_tier, 10, 7);
RunWASMSelectAlignTest(execution_tier, 10, 8);
RunWASMSelectAlignTest(execution_tier, 10, 9);
RunWASMSelectAlignTest(execution_tier, 10, 10);
}
void RunJSSelectAlignTest(ExecutionTier tier, int num_args, int num_params) {
PredictableInputValues inputs(0x400);
Isolate* isolate = CcTest::InitIsolateOnce();
Factory* factory = isolate->factory();
const int kMaxParams = 10;
CHECK_LE(num_args, kMaxParams);
CHECK_LE(num_params, kMaxParams);
ValueType type = kWasmF64;
ValueType types[kMaxParams + 1] = {type, type, type, type, type, type,
type, type, type, type, type};
FunctionSig sig(1, num_params, types);
i::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
// Build the calling code.
std::vector<byte> code;
for (int i = 0; i < num_params; i++) {
ADD_CODE(code, WASM_GET_LOCAL(i));
}
uint8_t imported_js_index = 0;
ADD_CODE(code, kExprCallFunction, imported_js_index);
size_t end = code.size();
code.push_back(0);
// Call different select JS functions.
for (int which = 0; which < num_params; which++) {
HandleScope scope(isolate);
ManuallyImportedJSFunction import = CreateJSSelector(&sig, which);
WasmRunner<void> r(tier, &import);
WasmFunctionCompiler& t = r.NewFunction(&sig);
t.Build(&code[0], &code[end]);
Handle<Object> args[] = {
factory->NewNumber(inputs.arg_d(0)),
factory->NewNumber(inputs.arg_d(1)),
factory->NewNumber(inputs.arg_d(2)),
factory->NewNumber(inputs.arg_d(3)),
factory->NewNumber(inputs.arg_d(4)),
factory->NewNumber(inputs.arg_d(5)),
factory->NewNumber(inputs.arg_d(6)),
factory->NewNumber(inputs.arg_d(7)),
factory->NewNumber(inputs.arg_d(8)),
factory->NewNumber(inputs.arg_d(9)),
};
double nan = std::numeric_limits<double>::quiet_NaN();
double expected = which < num_args ? inputs.arg_d(which) : nan;
r.CheckCallApplyViaJS(expected, t.function_index(), args, num_args);
}
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_0) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 0, 1);
RunJSSelectAlignTest(execution_tier, 0, 2);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_1) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 1, 2);
RunJSSelectAlignTest(execution_tier, 1, 3);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_2) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 2, 3);
RunJSSelectAlignTest(execution_tier, 2, 4);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_3) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 3, 3);
RunJSSelectAlignTest(execution_tier, 3, 4);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_4) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 4, 3);
RunJSSelectAlignTest(execution_tier, 4, 4);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_7) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 7, 3);
RunJSSelectAlignTest(execution_tier, 7, 4);
RunJSSelectAlignTest(execution_tier, 7, 4);
RunJSSelectAlignTest(execution_tier, 7, 4);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_8) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 8, 5);
RunJSSelectAlignTest(execution_tier, 8, 6);
RunJSSelectAlignTest(execution_tier, 8, 7);
RunJSSelectAlignTest(execution_tier, 8, 8);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_9) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 9, 6);
RunJSSelectAlignTest(execution_tier, 9, 7);
RunJSSelectAlignTest(execution_tier, 9, 8);
RunJSSelectAlignTest(execution_tier, 9, 9);
}
WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_10) {
CcTest::InitializeVM();
RunJSSelectAlignTest(execution_tier, 10, 7);
RunJSSelectAlignTest(execution_tier, 10, 8);
RunJSSelectAlignTest(execution_tier, 10, 9);
RunJSSelectAlignTest(execution_tier, 10, 10);
}
// Set up a test with an import, so we can return call it.
// Create a javascript function that returns left or right arguments
// depending on the value of the third argument
// function (a,b,c){ if(c)return a; return b; }
void RunPickerTest(ExecutionTier tier, bool indirect) {
EXPERIMENTAL_FLAG_SCOPE(return_call);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
TestSignatures sigs;
const char* source = "(function(a,b,c) { if(c)return a; return b; })";
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
ManuallyImportedJSFunction import = {sigs.i_iii(), js_function};
WasmRunner<int32_t, int32_t> r(tier, &import);
const uint32_t js_index = 0;
const int32_t left = -2;
const int32_t right = 3;
WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc");
if (indirect) {
byte sig_index = r.builder().AddSignature(sigs.i_iii());
uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)};
r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table));
BUILD(rc_fn, WASM_RETURN_CALL_INDIRECT(sig_index, WASM_I32V(left),
WASM_I32V(right), WASM_GET_LOCAL(0),
WASM_I32V(js_index)));
} else {
BUILD(rc_fn,
WASM_RETURN_CALL_FUNCTION(js_index, WASM_I32V(left), WASM_I32V(right),
WASM_GET_LOCAL(0)));
}
Handle<Object> args_left[] = {isolate->factory()->NewNumber(1)};
r.CheckCallApplyViaJS(left, rc_fn.function_index(), args_left, 1);
Handle<Object> args_right[] = {isolate->factory()->NewNumber(0)};
r.CheckCallApplyViaJS(right, rc_fn.function_index(), args_right, 1);
}
WASM_COMPILED_EXEC_TEST(Run_ReturnCallImportedFunction) {
RunPickerTest(execution_tier, false);
}
WASM_COMPILED_EXEC_TEST(Run_ReturnCallIndirectImportedFunction) {
RunPickerTest(execution_tier, true);
}
#undef ADD_CODE
} // namespace wasm
} // namespace internal
} // namespace v8