[wasm] Remove 'using namespace' from cctest/wasm
This required splitting wasm-run-utils.h in header and implementation, since the anonymous namespace in wasm-run-utils.h is now gone. This is a reasonable refactoring in itself. R=titzer@chromium.org CC=mstarzinger@chromium.org, mostynb@opera.com Bug: chromium:746958 Change-Id: I0f3b30fef1865cd88eca37b69d0c3a9eb19e77ea Reviewed-on: https://chromium-review.googlesource.com/647587 Reviewed-by: Ben Titzer <titzer@chromium.org> Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#47773}
This commit is contained in:
parent
5931cc9409
commit
57375079cd
@ -204,6 +204,7 @@ v8_executable("cctest") {
|
||||
"wasm/test-wasm-interpreter-entry.cc",
|
||||
"wasm/test-wasm-stack.cc",
|
||||
"wasm/test-wasm-trap-position.cc",
|
||||
"wasm/wasm-run-utils.cc",
|
||||
"wasm/wasm-run-utils.h",
|
||||
]
|
||||
|
||||
|
@ -222,6 +222,7 @@
|
||||
'wasm/test-wasm-interpreter-entry.cc',
|
||||
'wasm/test-wasm-stack.cc',
|
||||
'wasm/test-wasm-trap-position.cc',
|
||||
'wasm/wasm-run-utils.cc',
|
||||
'wasm/wasm-run-utils.h',
|
||||
],
|
||||
'cctest_sources_ia32': [ ### gcmole(arch:ia32) ###
|
||||
|
@ -332,9 +332,10 @@ class ValueHelper {
|
||||
|
||||
// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... }
|
||||
// Watch out, these macros aren't hygenic; they pollute your scope. Thanks STL.
|
||||
#define FOR_INPUTS(ctype, itype, var) \
|
||||
std::vector<ctype> var##_vec = ValueHelper::itype##_vector(); \
|
||||
for (std::vector<ctype>::iterator var = var##_vec.begin(); \
|
||||
#define FOR_INPUTS(ctype, itype, var) \
|
||||
std::vector<ctype> var##_vec = \
|
||||
::v8::internal::compiler::ValueHelper::itype##_vector(); \
|
||||
for (std::vector<ctype>::iterator var = var##_vec.begin(); \
|
||||
var != var##_vec.end(); ++var)
|
||||
|
||||
#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
|
||||
@ -362,10 +363,10 @@ static inline void CheckFloatEq(volatile float x, volatile float y) {
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_FLOAT_EQ(lhs, rhs) \
|
||||
do { \
|
||||
volatile float tmp = lhs; \
|
||||
CheckFloatEq(tmp, rhs); \
|
||||
#define CHECK_FLOAT_EQ(lhs, rhs) \
|
||||
do { \
|
||||
volatile float tmp = lhs; \
|
||||
::v8::internal::compiler::CheckFloatEq(tmp, rhs); \
|
||||
} while (0)
|
||||
|
||||
static inline void CheckDoubleEq(volatile double x, volatile double y) {
|
||||
@ -377,10 +378,10 @@ static inline void CheckDoubleEq(volatile double x, volatile double y) {
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_DOUBLE_EQ(lhs, rhs) \
|
||||
do { \
|
||||
volatile double tmp = lhs; \
|
||||
CheckDoubleEq(tmp, rhs); \
|
||||
#define CHECK_DOUBLE_EQ(lhs, rhs) \
|
||||
do { \
|
||||
volatile double tmp = lhs; \
|
||||
::v8::internal::compiler::CheckDoubleEq(tmp, rhs); \
|
||||
} while (0)
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include "test/cctest/compiler/c-signature.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define __ assm.
|
||||
|
||||
@ -40,8 +40,8 @@ TEST(WasmRelocationArmMemoryReference) {
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
compiler::CSignature0<int32_t> csig;
|
||||
compiler::CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
int32_t ret_value = runnable.Call();
|
||||
CHECK_EQ(ret_value, imm);
|
||||
|
||||
@ -95,8 +95,8 @@ TEST(WasmRelocationArmMemorySizeReference) {
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
compiler::CSignature0<int32_t> csig;
|
||||
compiler::CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
int32_t ret_value = runnable.Call();
|
||||
CHECK_NE(ret_value, bit_cast<int32_t>(0xdeadbeef));
|
||||
|
||||
@ -123,4 +123,9 @@ TEST(WasmRelocationArmMemorySizeReference) {
|
||||
::printf("f() = %d\n\n", ret_value);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "test/cctest/compiler/c-signature.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define __ masm.
|
||||
|
||||
@ -45,8 +45,8 @@ TEST(WasmRelocationArm64MemoryReference) {
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
|
||||
CSignature0<int64_t> csig;
|
||||
CodeRunner<int64_t> runnable(isolate, code, &csig);
|
||||
compiler::CSignature0<int64_t> csig;
|
||||
compiler::CodeRunner<int64_t> runnable(isolate, code, &csig);
|
||||
int64_t ret_value = runnable.Call();
|
||||
CHECK_EQ(ret_value, imm);
|
||||
|
||||
@ -101,8 +101,8 @@ TEST(WasmRelocationArm64MemorySizeReference) {
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
|
||||
CSignature0<int64_t> csig;
|
||||
CodeRunner<int64_t> runnable(isolate, code, &csig);
|
||||
compiler::CSignature0<int64_t> csig;
|
||||
compiler::CodeRunner<int64_t> runnable(isolate, code, &csig);
|
||||
int64_t ret_value = runnable.Call();
|
||||
CHECK_NE(ret_value, 0xdeadbeef);
|
||||
|
||||
@ -131,3 +131,7 @@ TEST(WasmRelocationArm64MemorySizeReference) {
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -16,8 +16,9 @@
|
||||
#include "test/cctest/compiler/c-signature.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define __ assm.
|
||||
|
||||
@ -37,14 +38,14 @@ TEST(WasmRelocationIa32MemoryReference) {
|
||||
__ nop();
|
||||
__ ret(0);
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
compiler::CSignature0<int32_t> csig;
|
||||
CodeDesc desc;
|
||||
assm.GetCode(isolate, &desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
USE(code);
|
||||
|
||||
CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
compiler::CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
int32_t ret_value = runnable.Call();
|
||||
CHECK_EQ(ret_value, imm);
|
||||
|
||||
@ -100,14 +101,14 @@ TEST(WasmRelocationIa32MemorySizeReference) {
|
||||
__ mov(eax, 0xdeadbeef);
|
||||
__ ret(0);
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
compiler::CSignature0<int32_t> csig;
|
||||
CodeDesc desc;
|
||||
assm.GetCode(isolate, &desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
USE(code);
|
||||
|
||||
CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
compiler::CodeRunner<int32_t> runnable(isolate, code, &csig);
|
||||
int32_t ret_value = runnable.Call();
|
||||
CHECK_NE(ret_value, bit_cast<int32_t>(0xdeadbeef));
|
||||
|
||||
@ -139,4 +140,9 @@ TEST(WasmRelocationIa32MemorySizeReference) {
|
||||
disasm::Disassembler::Disassemble(stdout, begin, end);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
// If the target architecture is 64-bit, enable all tests.
|
||||
#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
|
||||
#define WASM_64 1
|
||||
@ -1476,7 +1480,7 @@ WASM_EXEC_TEST(I64Ror) {
|
||||
|
||||
FOR_UINT64_INPUTS(i) {
|
||||
FOR_UINT64_INPUTS(j) {
|
||||
int64_t expected = bits::RotateRight64(*i, *j & 0x3f);
|
||||
int64_t expected = base::bits::RotateRight64(*i, *j & 0x3f);
|
||||
CHECK_EQ(expected, r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
@ -1489,7 +1493,7 @@ WASM_EXEC_TEST(I64Rol) {
|
||||
|
||||
FOR_UINT64_INPUTS(i) {
|
||||
FOR_UINT64_INPUTS(j) {
|
||||
int64_t expected = bits::RotateLeft64(*i, *j & 0x3f);
|
||||
int64_t expected = base::bits::RotateLeft64(*i, *j & 0x3f);
|
||||
CHECK_EQ(expected, r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
@ -1668,3 +1672,11 @@ WASM_EXEC_TEST(Regress5874) {
|
||||
|
||||
r.Call();
|
||||
}
|
||||
|
||||
// clang-format gets confused about these closing parentheses (wants to change
|
||||
// the first comment to "// namespace v8". Disable it.
|
||||
// clang-format off
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
// clang-format on
|
||||
|
@ -15,10 +15,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
// for even shorter tests.
|
||||
#define B2(a, b) kExprBlock, a, b, kExprEnd
|
||||
@ -298,3 +297,7 @@ TEST(RunWasm_AsmCheckedStoreFloat64RelocInfo) {
|
||||
CHECK_NE(0, GetMatchingRelocInfoCount(r.builder().GetFunctionCode(0),
|
||||
RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -7,6 +7,10 @@
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define WASM_ATOMICS_OP(op) kAtomicPrefix, static_cast<byte>(op)
|
||||
#define WASM_ATOMICS_BINOP(op, x, y) x, y, WASM_ATOMICS_OP(op)
|
||||
#define WASM_ATOMICS_TERNARY_OP(op, x, y, z) x, y, z, WASM_ATOMICS_OP(op)
|
||||
@ -186,3 +190,7 @@ WASM_EXEC_TEST(I32CompareExchange8U) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -16,11 +16,6 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
@ -14,10 +14,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define BUILD(r, ...) \
|
||||
do { \
|
||||
@ -84,7 +83,7 @@ void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc,
|
||||
CHECK_EQ(expected, Smi::ToInt(*result));
|
||||
} else {
|
||||
CHECK(result->IsHeapNumber());
|
||||
CheckFloatEq(expected, HeapNumber::cast(*result)->value());
|
||||
CHECK_FLOAT_EQ(expected, HeapNumber::cast(*result)->value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -504,3 +503,7 @@ TEST(Run_JSSelectAlign_10) {
|
||||
RunJSSelectAlignTest(10, 9);
|
||||
RunJSSelectAlignTest(10, 10);
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -19,10 +19,9 @@
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
#include "test/common/wasm/wasm-module-runner.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
namespace {
|
||||
void Cleanup(Isolate* isolate = nullptr) {
|
||||
@ -1170,3 +1169,7 @@ TEST(Run_WasmModule_Buffer_Externalized_Detach) {
|
||||
}
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -12,8 +12,9 @@
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define FOREACH_TYPE(TEST_BODY) \
|
||||
TEST_BODY(int32_t, WASM_I32_ADD) \
|
||||
@ -60,3 +61,7 @@ using namespace v8::internal::compiler;
|
||||
}
|
||||
|
||||
FOREACH_TYPE(LOAD_SET_GLOBAL_TEST_BODY)
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -8,10 +8,9 @@
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -2199,3 +2198,7 @@ WASM_SIMD_TEST(SimdLoadStoreLoad) {
|
||||
}
|
||||
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || SIMD_LOWERING_TARGET ||
|
||||
// V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -15,10 +15,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
// for even shorter tests.
|
||||
#define B1(a) WASM_BLOCK(a)
|
||||
@ -1941,11 +1940,13 @@ static void TestBuildGraphForSimpleExpression(WasmOpcode opcode) {
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
HandleScope scope(isolate);
|
||||
// Enable all optional operators.
|
||||
CommonOperatorBuilder common(&zone);
|
||||
MachineOperatorBuilder machine(&zone, MachineType::PointerRepresentation(),
|
||||
MachineOperatorBuilder::kAllOptionalOps);
|
||||
Graph graph(&zone);
|
||||
JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
|
||||
compiler::CommonOperatorBuilder common(&zone);
|
||||
compiler::MachineOperatorBuilder machine(
|
||||
&zone, MachineType::PointerRepresentation(),
|
||||
compiler::MachineOperatorBuilder::kAllOptionalOps);
|
||||
compiler::Graph graph(&zone);
|
||||
compiler::JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr,
|
||||
&machine);
|
||||
FunctionSig* sig = WasmOpcodes::Signature(opcode);
|
||||
|
||||
if (sig->parameter_count() == 1) {
|
||||
@ -3091,3 +3092,7 @@ WASM_EXEC_TEST(IfInsideUnreachable) {
|
||||
WASM_IF_ELSE_I(WASM_ONE, WASM_BRV(0, WASM_ONE), WASM_RETURN1(WASM_ONE)));
|
||||
CHECK_EQ(17, r.Call());
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace debug = v8::debug;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -422,3 +422,7 @@ TEST(WasmGetLocalsAndStack) {
|
||||
Handle<Object> args[]{handle(Smi::FromInt(7), isolate)};
|
||||
CHECK(!Execution::Call(isolate, main_fun_wrapper, global, 1, args).is_null());
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace debug = v8::debug;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
/**
|
||||
* We test the interface from Wasm compiled code to the Wasm interpreter by
|
||||
@ -257,3 +257,7 @@ TEST(TestArgumentPassing_AllTypes) {
|
||||
CheckCall(i32, i64, f32, f64);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -9,10 +9,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
using v8::Local;
|
||||
using v8::Utils;
|
||||
@ -191,3 +190,7 @@ TEST(CollectDetailedWasmStack_WasmError) {
|
||||
CheckExceptionInfos(isolate, exception, expected_exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -10,10 +10,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
using v8::Local;
|
||||
using v8::Utils;
|
||||
@ -141,3 +140,7 @@ TEST(IllegalLoad) {
|
||||
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
|
||||
expected_exceptions);
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
503
test/cctest/wasm/wasm-run-utils.cc
Normal file
503
test/cctest/wasm/wasm-run-utils.cc
Normal file
@ -0,0 +1,503 @@
|
||||
// Copyright 2017 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 "test/cctest/wasm/wasm-run-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
TestingModuleBuilder::TestingModuleBuilder(Zone* zone, WasmExecutionMode mode)
|
||||
: test_module_ptr_(&test_module_),
|
||||
isolate_(CcTest::InitIsolateOnce()),
|
||||
global_offset(0),
|
||||
mem_start_(nullptr),
|
||||
mem_size_(0),
|
||||
interpreter_(nullptr) {
|
||||
WasmJs::Install(isolate_);
|
||||
test_module_.globals_size = kMaxGlobalsSize;
|
||||
memset(globals_data_, 0, sizeof(globals_data_));
|
||||
instance_object_ = InitInstanceObject();
|
||||
if (mode == kExecuteInterpreted) {
|
||||
interpreter_ = WasmDebugInfo::SetupForTesting(instance_object_);
|
||||
}
|
||||
}
|
||||
|
||||
byte* TestingModuleBuilder::AddMemory(uint32_t size) {
|
||||
CHECK(!test_module_.has_memory);
|
||||
CHECK_NULL(mem_start_);
|
||||
CHECK_EQ(0, mem_size_);
|
||||
DCHECK(!instance_object_->has_memory_buffer());
|
||||
test_module_.has_memory = true;
|
||||
bool enable_guard_regions = EnableGuardRegions() && test_module_.is_wasm();
|
||||
uint32_t alloc_size =
|
||||
enable_guard_regions ? RoundUp(size, base::OS::CommitPageSize()) : size;
|
||||
Handle<JSArrayBuffer> new_buffer =
|
||||
wasm::NewArrayBuffer(isolate_, alloc_size, enable_guard_regions);
|
||||
CHECK(!new_buffer.is_null());
|
||||
instance_object_->set_memory_buffer(*new_buffer);
|
||||
mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
|
||||
mem_size_ = size;
|
||||
CHECK(size == 0 || mem_start_);
|
||||
memset(mem_start_, 0, size);
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
handle(instance_object_->compiled_module());
|
||||
Factory* factory = CcTest::i_isolate()->factory();
|
||||
// It's not really necessary we recreate the Number objects,
|
||||
// if we happened to have one, but this is a reasonable inefficiencly,
|
||||
// given this is test.
|
||||
WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory,
|
||||
mem_size_);
|
||||
WasmCompiledModule::recreate_embedded_mem_start(
|
||||
compiled_module, factory, reinterpret_cast<size_t>(mem_start_));
|
||||
|
||||
if (interpreter_) {
|
||||
interpreter_->UpdateMemory(mem_start_, mem_size_);
|
||||
}
|
||||
return mem_start_;
|
||||
}
|
||||
|
||||
uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, Handle<Code> code,
|
||||
const char* name) {
|
||||
if (test_module_.functions.size() == 0) {
|
||||
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction
|
||||
// structs from moving.
|
||||
test_module_.functions.reserve(kMaxFunctions);
|
||||
}
|
||||
uint32_t index = static_cast<uint32_t>(test_module_.functions.size());
|
||||
test_module_.functions.push_back(
|
||||
{sig, index, 0, {0, 0}, {0, 0}, false, false});
|
||||
if (name) {
|
||||
Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name));
|
||||
test_module_.functions.back().name = {
|
||||
AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())};
|
||||
}
|
||||
function_code_.push_back(code);
|
||||
if (interpreter_) {
|
||||
interpreter_->AddFunctionForTesting(&test_module_.functions.back());
|
||||
}
|
||||
DCHECK_LT(index, kMaxFunctions); // limited for testing.
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t TestingModuleBuilder::AddJsFunction(FunctionSig* sig,
|
||||
const char* source) {
|
||||
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CompileRun(source))));
|
||||
uint32_t index = AddFunction(sig, Handle<Code>::null(), nullptr);
|
||||
Handle<Code> code = compiler::CompileWasmToJSWrapper(
|
||||
isolate_, jsfunc, sig, index, Handle<String>::null(),
|
||||
Handle<String>::null(), test_module_.origin());
|
||||
function_code_[index] = code;
|
||||
return index;
|
||||
}
|
||||
|
||||
Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
|
||||
// Wrap the code so it can be called as a JS function.
|
||||
Handle<Code> code = function_code_[index];
|
||||
Handle<Code> ret_code =
|
||||
compiler::CompileJSToWasmWrapper(isolate_, &test_module_, code, index);
|
||||
Handle<JSFunction> ret = WasmExportedFunction::New(
|
||||
isolate_, instance_object(), MaybeHandle<String>(),
|
||||
static_cast<int>(index),
|
||||
static_cast<int>(test_module_.functions[index].sig->parameter_count()),
|
||||
ret_code);
|
||||
|
||||
// Add weak reference to exported functions.
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
instance_object()->compiled_module(), isolate_);
|
||||
Handle<FixedArray> old_arr = compiled_module->weak_exported_functions();
|
||||
Handle<FixedArray> new_arr =
|
||||
isolate_->factory()->NewFixedArray(old_arr->length() + 1);
|
||||
old_arr->CopyTo(0, *new_arr, 0, old_arr->length());
|
||||
Handle<WeakCell> weak_fn = isolate_->factory()->NewWeakCell(ret);
|
||||
new_arr->set(old_arr->length(), *weak_fn);
|
||||
compiled_module->set_weak_exported_functions(new_arr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TestingModuleBuilder::AddIndirectFunctionTable(uint16_t* function_indexes,
|
||||
uint32_t table_size) {
|
||||
test_module_.function_tables.emplace_back();
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables.back();
|
||||
table.initial_size = table_size;
|
||||
table.maximum_size = table_size;
|
||||
table.has_maximum_size = true;
|
||||
for (uint32_t i = 0; i < table_size; ++i) {
|
||||
table.values.push_back(function_indexes[i]);
|
||||
table.map.FindOrInsert(test_module_.functions[function_indexes[i]].sig);
|
||||
}
|
||||
|
||||
function_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
signature_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
}
|
||||
|
||||
void TestingModuleBuilder::PopulateIndirectFunctionTable() {
|
||||
if (interpret()) return;
|
||||
// Initialize the fixed arrays in instance->function_tables.
|
||||
for (uint32_t i = 0; i < function_tables_.size(); i++) {
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables[i];
|
||||
Handle<FixedArray> function_table(
|
||||
reinterpret_cast<FixedArray**>(function_tables_[i]));
|
||||
Handle<FixedArray> signature_table(
|
||||
reinterpret_cast<FixedArray**>(signature_tables_[i]));
|
||||
int table_size = static_cast<int>(table.values.size());
|
||||
for (int j = 0; j < table_size; j++) {
|
||||
WasmFunction& function = test_module_.functions[table.values[j]];
|
||||
signature_table->set(j, Smi::FromInt(table.map.Find(function.sig)));
|
||||
function_table->set(j, *function_code_[function.func_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) {
|
||||
Handle<SeqOneByteString> old_bytes(
|
||||
instance_object_->compiled_module()->module_bytes(), isolate_);
|
||||
uint32_t old_size = static_cast<uint32_t>(old_bytes->length());
|
||||
// Avoid placing strings at offset 0, this might be interpreted as "not
|
||||
// set", e.g. for function names.
|
||||
uint32_t bytes_offset = old_size ? old_size : 1;
|
||||
ScopedVector<byte> new_bytes(bytes_offset + bytes.length());
|
||||
memcpy(new_bytes.start(), old_bytes->GetChars(), old_size);
|
||||
memcpy(new_bytes.start() + bytes_offset, bytes.start(), bytes.length());
|
||||
Handle<SeqOneByteString> new_bytes_str = Handle<SeqOneByteString>::cast(
|
||||
isolate_->factory()->NewStringFromOneByte(new_bytes).ToHandleChecked());
|
||||
instance_object_->compiled_module()->shared()->set_module_bytes(
|
||||
*new_bytes_str);
|
||||
return bytes_offset;
|
||||
}
|
||||
|
||||
compiler::ModuleEnv TestingModuleBuilder::CreateModuleEnv() {
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
for (size_t i = 0; i < test_module_.function_tables.size(); i++) {
|
||||
auto& function_table = test_module_.function_tables[i];
|
||||
signature_maps.push_back(&function_table.map);
|
||||
}
|
||||
return {
|
||||
&test_module_,
|
||||
function_tables_,
|
||||
signature_tables_,
|
||||
signature_maps,
|
||||
function_code_,
|
||||
Handle<Code>::null(),
|
||||
reinterpret_cast<uintptr_t>(mem_start_),
|
||||
mem_size_,
|
||||
reinterpret_cast<uintptr_t>(globals_data_),
|
||||
};
|
||||
}
|
||||
|
||||
const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) {
|
||||
byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type));
|
||||
global_offset = (global_offset + size - 1) & ~(size - 1); // align
|
||||
test_module_.globals.push_back(
|
||||
{type, true, WasmInitExpr(), global_offset, false, false});
|
||||
global_offset += size;
|
||||
// limit number of globals.
|
||||
CHECK_LT(global_offset, kMaxGlobalsSize);
|
||||
return &test_module_.globals.back();
|
||||
}
|
||||
|
||||
Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
|
||||
Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast(
|
||||
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
|
||||
// The lifetime of the wasm module is tied to this object's, and we cannot
|
||||
// rely on the mechanics of Managed<T>.
|
||||
Handle<Foreign> module_wrapper = isolate_->factory()->NewForeign(
|
||||
reinterpret_cast<Address>(&test_module_ptr_));
|
||||
Handle<Script> script =
|
||||
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
|
||||
script->set_type(Script::TYPE_WASM);
|
||||
Handle<WasmSharedModuleData> shared_module_data =
|
||||
WasmSharedModuleData::New(isolate_, module_wrapper, empty_string, script,
|
||||
Handle<ByteArray>::null());
|
||||
Handle<FixedArray> code_table = isolate_->factory()->NewFixedArray(0);
|
||||
Handle<FixedArray> export_wrappers = isolate_->factory()->NewFixedArray(0);
|
||||
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
|
||||
isolate_, shared_module_data, code_table, export_wrappers,
|
||||
function_tables_, signature_tables_);
|
||||
// This method is called when we initialize TestEnvironment. We don't
|
||||
// have a memory yet, so we won't create it here. We'll update the
|
||||
// interpreter when we get a memory. We do have globals, though.
|
||||
WasmCompiledModule::recreate_globals_start(
|
||||
compiled_module, isolate_->factory(),
|
||||
reinterpret_cast<size_t>(globals_data_));
|
||||
Handle<FixedArray> weak_exported = isolate_->factory()->NewFixedArray(0);
|
||||
compiled_module->set_weak_exported_functions(weak_exported);
|
||||
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
|
||||
script->set_wasm_compiled_module(*compiled_module);
|
||||
return WasmInstanceObject::New(isolate_, compiled_module);
|
||||
}
|
||||
|
||||
void TestBuildingGraph(Zone* zone, compiler::JSGraph* jsgraph,
|
||||
compiler::ModuleEnv* module, FunctionSig* sig,
|
||||
compiler::SourcePositionTable* source_position_table,
|
||||
const byte* start, const byte* end,
|
||||
bool runtime_exception_support) {
|
||||
compiler::WasmGraphBuilder builder(
|
||||
module, zone, jsgraph, CEntryStub(jsgraph->isolate(), 1).GetCode(), sig,
|
||||
source_position_table);
|
||||
builder.SetRuntimeExceptionSupport(runtime_exception_support);
|
||||
|
||||
DecodeResult result =
|
||||
BuildTFGraph(zone->allocator(), &builder, sig, start, end);
|
||||
if (result.failed()) {
|
||||
if (!FLAG_trace_wasm_decoder) {
|
||||
// Retry the compilation with the tracing flag on, to help in debugging.
|
||||
FLAG_trace_wasm_decoder = true;
|
||||
result = BuildTFGraph(zone->allocator(), &builder, sig, start, end);
|
||||
}
|
||||
|
||||
uint32_t pc = result.error_offset();
|
||||
std::ostringstream str;
|
||||
str << "Verification failed; pc = +" << pc
|
||||
<< ", msg = " << result.error_msg().c_str();
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
builder.LowerInt64();
|
||||
if (!CpuFeatures::SupportsWasmSimd128()) {
|
||||
builder.SimdScalarLoweringForTesting();
|
||||
}
|
||||
}
|
||||
|
||||
WasmFunctionWrapper::WasmFunctionWrapper(Zone* zone, int num_params)
|
||||
: GraphAndBuilders(zone), inner_code_node_(nullptr), signature_(nullptr) {
|
||||
// One additional parameter for the pointer to the return value memory.
|
||||
Signature<MachineType>::Builder sig_builder(zone, 1, num_params + 1);
|
||||
|
||||
sig_builder.AddReturn(MachineType::Int32());
|
||||
for (int i = 0; i < num_params + 1; i++) {
|
||||
sig_builder.AddParam(MachineType::Pointer());
|
||||
}
|
||||
signature_ = sig_builder.Build();
|
||||
}
|
||||
|
||||
void WasmFunctionWrapper::Init(CallDescriptor* descriptor,
|
||||
MachineType return_type,
|
||||
Vector<MachineType> param_types) {
|
||||
DCHECK_NOT_NULL(descriptor);
|
||||
DCHECK_EQ(signature_->parameter_count(), param_types.length() + 1);
|
||||
|
||||
// Create the TF graph for the wrapper.
|
||||
|
||||
// Function, effect, and control.
|
||||
Node** parameters = zone()->NewArray<Node*>(param_types.length() + 3);
|
||||
graph()->SetStart(graph()->NewNode(common()->Start(6)));
|
||||
Node* effect = graph()->start();
|
||||
int parameter_count = 0;
|
||||
|
||||
// Dummy node which gets replaced in SetInnerCode.
|
||||
inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
|
||||
parameters[parameter_count++] = inner_code_node_;
|
||||
|
||||
int param_idx = 0;
|
||||
for (MachineType t : param_types) {
|
||||
DCHECK_NE(MachineType::None(), t);
|
||||
parameters[parameter_count] = graph()->NewNode(
|
||||
machine()->Load(t),
|
||||
graph()->NewNode(common()->Parameter(param_idx++), graph()->start()),
|
||||
graph()->NewNode(common()->Int32Constant(0)), effect, graph()->start());
|
||||
effect = parameters[parameter_count++];
|
||||
}
|
||||
|
||||
parameters[parameter_count++] = effect;
|
||||
parameters[parameter_count++] = graph()->start();
|
||||
Node* call =
|
||||
graph()->NewNode(common()->Call(descriptor), parameter_count, parameters);
|
||||
|
||||
if (!return_type.IsNone()) {
|
||||
effect = graph()->NewNode(
|
||||
machine()->Store(compiler::StoreRepresentation(
|
||||
return_type.representation(), WriteBarrierKind::kNoWriteBarrier)),
|
||||
graph()->NewNode(common()->Parameter(param_types.length()),
|
||||
graph()->start()),
|
||||
graph()->NewNode(common()->Int32Constant(0)), call, effect,
|
||||
graph()->start());
|
||||
}
|
||||
Node* zero = graph()->NewNode(common()->Int32Constant(0));
|
||||
Node* r = graph()->NewNode(
|
||||
common()->Return(), zero,
|
||||
graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
|
||||
effect, graph()->start());
|
||||
graph()->SetEnd(graph()->NewNode(common()->End(1), r));
|
||||
}
|
||||
|
||||
Handle<Code> WasmFunctionWrapper::GetWrapperCode() {
|
||||
if (code_.is_null()) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
|
||||
CallDescriptor* descriptor =
|
||||
compiler::Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
|
||||
|
||||
if (kPointerSize == 4) {
|
||||
size_t num_params = signature_->parameter_count();
|
||||
// One additional parameter for the pointer of the return value.
|
||||
Signature<MachineRepresentation>::Builder rep_builder(zone(), 1,
|
||||
num_params + 1);
|
||||
|
||||
rep_builder.AddReturn(MachineRepresentation::kWord32);
|
||||
for (size_t i = 0; i < num_params + 1; i++) {
|
||||
rep_builder.AddParam(MachineRepresentation::kWord32);
|
||||
}
|
||||
compiler::Int64Lowering r(graph(), machine(), common(), zone(),
|
||||
rep_builder.Build());
|
||||
r.LowerGraph();
|
||||
}
|
||||
|
||||
CompilationInfo info(ArrayVector("testing"), isolate, graph()->zone(),
|
||||
Code::ComputeFlags(Code::STUB));
|
||||
code_ = compiler::Pipeline::GenerateCodeForTesting(&info, descriptor,
|
||||
graph(), nullptr);
|
||||
CHECK(!code_.is_null());
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
code_->Disassemble("wasm wrapper", os);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return code_;
|
||||
}
|
||||
|
||||
void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
|
||||
size_t locals_size = local_decls.Size();
|
||||
size_t total_size = end - start + locals_size + 1;
|
||||
byte* buffer = static_cast<byte*>(zone()->New(total_size));
|
||||
// Prepend the local decls to the code.
|
||||
local_decls.Emit(buffer);
|
||||
// Emit the code.
|
||||
memcpy(buffer + locals_size, start, end - start);
|
||||
// Append an extra end opcode.
|
||||
buffer[total_size - 1] = kExprEnd;
|
||||
|
||||
start = buffer;
|
||||
end = buffer + total_size;
|
||||
|
||||
CHECK_GE(kMaxInt, end - start);
|
||||
int len = static_cast<int>(end - start);
|
||||
function_->code = {builder_->AddBytes(Vector<const byte>(start, len)),
|
||||
static_cast<uint32_t>(len)};
|
||||
|
||||
if (interpreter_) {
|
||||
// Add the code to the interpreter.
|
||||
interpreter_->SetFunctionCodeForTesting(function_, start, end);
|
||||
}
|
||||
|
||||
// Build the TurboFan graph.
|
||||
compiler::ModuleEnv module_env = builder_->CreateModuleEnv();
|
||||
TestBuildingGraph(zone(), &jsgraph, &module_env, sig, &source_position_table_,
|
||||
start, end, runtime_exception_support_);
|
||||
Handle<Code> code = Compile();
|
||||
builder_->SetFunctionCode(function_index(), code);
|
||||
|
||||
// Add to code table.
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
builder_->instance_object()->compiled_module(), isolate());
|
||||
Handle<FixedArray> code_table = compiled_module->code_table();
|
||||
if (static_cast<int>(function_index()) >= code_table->length()) {
|
||||
Handle<FixedArray> new_arr = isolate()->factory()->NewFixedArray(
|
||||
static_cast<int>(function_index()) + 1);
|
||||
code_table->CopyTo(0, *new_arr, 0, code_table->length());
|
||||
code_table = new_arr;
|
||||
compiled_module->ReplaceCodeTableForTesting(code_table);
|
||||
}
|
||||
DCHECK(code_table->get(static_cast<int>(function_index()))
|
||||
->IsUndefined(isolate()));
|
||||
code_table->set(static_cast<int>(function_index()), *code);
|
||||
if (trap_handler::UseTrapHandler()) {
|
||||
UnpackAndRegisterProtectedInstructions(isolate(), code_table);
|
||||
}
|
||||
}
|
||||
|
||||
WasmFunctionCompiler::WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
|
||||
TestingModuleBuilder* builder,
|
||||
const char* name,
|
||||
bool runtime_exception_support)
|
||||
: GraphAndBuilders(zone),
|
||||
jsgraph(builder->isolate(), this->graph(), this->common(), nullptr,
|
||||
nullptr, this->machine()),
|
||||
sig(sig),
|
||||
descriptor_(nullptr),
|
||||
builder_(builder),
|
||||
local_decls(zone, sig),
|
||||
source_position_table_(this->graph()),
|
||||
interpreter_(builder->interpreter()),
|
||||
runtime_exception_support_(runtime_exception_support) {
|
||||
// Get a new function from the testing module.
|
||||
int index = builder->AddFunction(sig, Handle<Code>::null(), name);
|
||||
function_ = builder_->GetFunctionAt(index);
|
||||
}
|
||||
|
||||
Handle<Code> WasmFunctionCompiler::Compile() {
|
||||
CallDescriptor* desc = descriptor();
|
||||
if (kPointerSize == 4) {
|
||||
desc = compiler::GetI32WasmCallDescriptor(this->zone(), desc);
|
||||
}
|
||||
EmbeddedVector<char, 16> comp_name;
|
||||
int comp_name_len = SNPrintF(comp_name, "wasm#%u", this->function_index());
|
||||
comp_name.Truncate(comp_name_len);
|
||||
CompilationInfo info(comp_name, this->isolate(), this->zone(),
|
||||
Code::ComputeFlags(Code::WASM_FUNCTION));
|
||||
std::unique_ptr<CompilationJob> job(compiler::Pipeline::NewWasmCompilationJob(
|
||||
&info, &jsgraph, desc, &source_position_table_, nullptr,
|
||||
ModuleOrigin::kAsmJsOrigin));
|
||||
if (job->ExecuteJob() != CompilationJob::SUCCEEDED ||
|
||||
job->FinalizeJob() != CompilationJob::SUCCEEDED)
|
||||
return Handle<Code>::null();
|
||||
|
||||
Handle<Code> code = info.code();
|
||||
|
||||
// Deopt data holds <WeakCell<wasm_instance>, func_index>.
|
||||
DCHECK(code->deoptimization_data() == nullptr ||
|
||||
code->deoptimization_data()->length() == 0);
|
||||
Handle<FixedArray> deopt_data =
|
||||
isolate()->factory()->NewFixedArray(2, TENURED);
|
||||
Handle<Object> weak_instance =
|
||||
isolate()->factory()->NewWeakCell(builder_->instance_object());
|
||||
deopt_data->set(0, *weak_instance);
|
||||
deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
|
||||
code->set_deoptimization_data(*deopt_data);
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble("wasm code", os);
|
||||
}
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
FunctionSig* WasmRunnerBase::CreateSig(MachineType return_type,
|
||||
Vector<MachineType> param_types) {
|
||||
int return_count = return_type.IsNone() ? 0 : 1;
|
||||
int param_count = param_types.length();
|
||||
|
||||
// Allocate storage array in zone.
|
||||
ValueType* sig_types = zone_.NewArray<ValueType>(return_count + param_count);
|
||||
|
||||
// Convert machine types to local types, and check that there are no
|
||||
// MachineType::None()'s in the parameters.
|
||||
int idx = 0;
|
||||
if (return_count) sig_types[idx++] = WasmOpcodes::ValueTypeFor(return_type);
|
||||
for (MachineType param : param_types) {
|
||||
CHECK_NE(MachineType::None(), param);
|
||||
sig_types[idx++] = WasmOpcodes::ValueTypeFor(param);
|
||||
}
|
||||
return new (&zone_) FunctionSig(return_count, param_count, sig_types);
|
||||
}
|
||||
|
||||
// static
|
||||
bool WasmRunnerBase::trap_happened;
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -39,10 +39,19 @@
|
||||
#include "test/cctest/compiler/graph-builder-tester.h"
|
||||
#include "test/common/wasm/flag-utils.h"
|
||||
|
||||
static const uint32_t kMaxFunctions = 10;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
constexpr uint32_t kMaxFunctions = 10;
|
||||
constexpr uint32_t kMaxGlobalsSize = 128;
|
||||
|
||||
enum WasmExecutionMode { kExecuteInterpreted, kExecuteCompiled };
|
||||
|
||||
using compiler::CallDescriptor;
|
||||
using compiler::MachineTypeForC;
|
||||
using compiler::Node;
|
||||
|
||||
// TODO(titzer): check traps more robustly in tests.
|
||||
// Currently, in tests, we just return 0xdeadbeef from the function in which
|
||||
// the trap occurs if the runtime context is not available to throw a JavaScript
|
||||
@ -61,14 +70,6 @@ enum WasmExecutionMode { kExecuteInterpreted, kExecuteCompiled };
|
||||
r.Build(code, code + arraysize(code)); \
|
||||
} while (false)
|
||||
|
||||
namespace {
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
|
||||
const uint32_t kMaxGlobalsSize = 128;
|
||||
|
||||
// A buildable ModuleEnv. Globals are pre-set, however, memory and code may be
|
||||
// progressively added by a test. In turn, we piecemeal update the runtime
|
||||
// objects, i.e. {WasmInstanceObject}, {WasmCompiledModule} and, if necessary,
|
||||
@ -76,57 +77,11 @@ const uint32_t kMaxGlobalsSize = 128;
|
||||
class TestingModuleBuilder {
|
||||
public:
|
||||
explicit TestingModuleBuilder(Zone* zone,
|
||||
WasmExecutionMode mode = kExecuteCompiled)
|
||||
: test_module_ptr_(&test_module_),
|
||||
isolate_(CcTest::InitIsolateOnce()),
|
||||
global_offset(0),
|
||||
mem_start_(nullptr),
|
||||
mem_size_(0),
|
||||
interpreter_(nullptr) {
|
||||
WasmJs::Install(isolate_);
|
||||
test_module_.globals_size = kMaxGlobalsSize;
|
||||
memset(globals_data_, 0, sizeof(globals_data_));
|
||||
instance_object_ = InitInstanceObject();
|
||||
if (mode == kExecuteInterpreted) {
|
||||
interpreter_ = WasmDebugInfo::SetupForTesting(instance_object_);
|
||||
}
|
||||
}
|
||||
WasmExecutionMode mode = kExecuteCompiled);
|
||||
|
||||
void ChangeOriginToAsmjs() { test_module_.set_origin(kAsmJsOrigin); }
|
||||
|
||||
byte* AddMemory(uint32_t size) {
|
||||
CHECK(!test_module_.has_memory);
|
||||
CHECK_NULL(mem_start_);
|
||||
CHECK_EQ(0, mem_size_);
|
||||
DCHECK(!instance_object_->has_memory_buffer());
|
||||
test_module_.has_memory = true;
|
||||
bool enable_guard_regions = EnableGuardRegions() && test_module_.is_wasm();
|
||||
uint32_t alloc_size =
|
||||
enable_guard_regions ? RoundUp(size, OS::CommitPageSize()) : size;
|
||||
Handle<JSArrayBuffer> new_buffer =
|
||||
wasm::NewArrayBuffer(isolate_, alloc_size, enable_guard_regions);
|
||||
CHECK(!new_buffer.is_null());
|
||||
instance_object_->set_memory_buffer(*new_buffer);
|
||||
mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
|
||||
mem_size_ = size;
|
||||
CHECK(size == 0 || mem_start_);
|
||||
memset(mem_start_, 0, size);
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
handle(instance_object_->compiled_module());
|
||||
Factory* factory = CcTest::i_isolate()->factory();
|
||||
// It's not really necessary we recreate the Number objects,
|
||||
// if we happened to have one, but this is a reasonable inefficiencly,
|
||||
// given this is test.
|
||||
WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory,
|
||||
mem_size_);
|
||||
WasmCompiledModule::recreate_embedded_mem_start(
|
||||
compiled_module, factory, reinterpret_cast<size_t>(mem_start_));
|
||||
|
||||
if (interpreter_) {
|
||||
interpreter_->UpdateMemory(mem_start_, mem_size_);
|
||||
}
|
||||
return mem_start_;
|
||||
}
|
||||
byte* AddMemory(uint32_t size);
|
||||
|
||||
size_t CodeTableLength() const { return function_code_.size(); }
|
||||
|
||||
@ -202,124 +157,22 @@ class TestingModuleBuilder {
|
||||
test_module_.maximum_pages = maximum_pages;
|
||||
}
|
||||
|
||||
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name) {
|
||||
if (test_module_.functions.size() == 0) {
|
||||
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction
|
||||
// structs from moving.
|
||||
test_module_.functions.reserve(kMaxFunctions);
|
||||
}
|
||||
uint32_t index = static_cast<uint32_t>(test_module_.functions.size());
|
||||
test_module_.functions.push_back(
|
||||
{sig, index, 0, {0, 0}, {0, 0}, false, false});
|
||||
if (name) {
|
||||
Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name));
|
||||
test_module_.functions.back().name = {
|
||||
AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())};
|
||||
}
|
||||
function_code_.push_back(code);
|
||||
if (interpreter_) {
|
||||
interpreter_->AddFunctionForTesting(&test_module_.functions.back());
|
||||
}
|
||||
DCHECK_LT(index, kMaxFunctions); // limited for testing.
|
||||
return index;
|
||||
}
|
||||
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name);
|
||||
|
||||
uint32_t AddJsFunction(FunctionSig* sig, const char* source) {
|
||||
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CompileRun(source))));
|
||||
uint32_t index = AddFunction(sig, Handle<Code>::null(), nullptr);
|
||||
Handle<Code> code = CompileWasmToJSWrapper(
|
||||
isolate_, jsfunc, sig, index, Handle<String>::null(),
|
||||
Handle<String>::null(), test_module_.origin());
|
||||
function_code_[index] = code;
|
||||
return index;
|
||||
}
|
||||
uint32_t AddJsFunction(FunctionSig* sig, const char* source);
|
||||
|
||||
Handle<JSFunction> WrapCode(uint32_t index) {
|
||||
// Wrap the code so it can be called as a JS function.
|
||||
Handle<Code> code = function_code_[index];
|
||||
Handle<Code> ret_code =
|
||||
compiler::CompileJSToWasmWrapper(isolate_, &test_module_, code, index);
|
||||
Handle<JSFunction> ret = WasmExportedFunction::New(
|
||||
isolate_, instance_object(), MaybeHandle<String>(),
|
||||
static_cast<int>(index),
|
||||
static_cast<int>(test_module_.functions[index].sig->parameter_count()),
|
||||
ret_code);
|
||||
|
||||
// Add weak reference to exported functions.
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
instance_object()->compiled_module(), isolate_);
|
||||
Handle<FixedArray> old_arr = compiled_module->weak_exported_functions();
|
||||
Handle<FixedArray> new_arr =
|
||||
isolate_->factory()->NewFixedArray(old_arr->length() + 1);
|
||||
old_arr->CopyTo(0, *new_arr, 0, old_arr->length());
|
||||
Handle<WeakCell> weak_fn = isolate_->factory()->NewWeakCell(ret);
|
||||
new_arr->set(old_arr->length(), *weak_fn);
|
||||
compiled_module->set_weak_exported_functions(new_arr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Handle<JSFunction> WrapCode(uint32_t index);
|
||||
|
||||
void SetFunctionCode(uint32_t index, Handle<Code> code) {
|
||||
function_code_[index] = code;
|
||||
}
|
||||
|
||||
void AddIndirectFunctionTable(uint16_t* function_indexes,
|
||||
uint32_t table_size) {
|
||||
test_module_.function_tables.emplace_back();
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables.back();
|
||||
table.initial_size = table_size;
|
||||
table.maximum_size = table_size;
|
||||
table.has_maximum_size = true;
|
||||
for (uint32_t i = 0; i < table_size; ++i) {
|
||||
table.values.push_back(function_indexes[i]);
|
||||
table.map.FindOrInsert(test_module_.functions[function_indexes[i]].sig);
|
||||
}
|
||||
uint32_t table_size);
|
||||
|
||||
function_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
signature_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
}
|
||||
void PopulateIndirectFunctionTable();
|
||||
|
||||
void PopulateIndirectFunctionTable() {
|
||||
if (interpret()) return;
|
||||
// Initialize the fixed arrays in instance->function_tables.
|
||||
for (uint32_t i = 0; i < function_tables_.size(); i++) {
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables[i];
|
||||
Handle<FixedArray> function_table(
|
||||
reinterpret_cast<FixedArray**>(function_tables_[i]));
|
||||
Handle<FixedArray> signature_table(
|
||||
reinterpret_cast<FixedArray**>(signature_tables_[i]));
|
||||
int table_size = static_cast<int>(table.values.size());
|
||||
for (int j = 0; j < table_size; j++) {
|
||||
WasmFunction& function = test_module_.functions[table.values[j]];
|
||||
signature_table->set(j, Smi::FromInt(table.map.Find(function.sig)));
|
||||
function_table->set(j, *function_code_[function.func_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AddBytes(Vector<const byte> bytes) {
|
||||
Handle<SeqOneByteString> old_bytes(
|
||||
instance_object_->compiled_module()->module_bytes(), isolate_);
|
||||
uint32_t old_size = static_cast<uint32_t>(old_bytes->length());
|
||||
// Avoid placing strings at offset 0, this might be interpreted as "not
|
||||
// set", e.g. for function names.
|
||||
uint32_t bytes_offset = old_size ? old_size : 1;
|
||||
ScopedVector<byte> new_bytes(bytes_offset + bytes.length());
|
||||
memcpy(new_bytes.start(), old_bytes->GetChars(), old_size);
|
||||
memcpy(new_bytes.start() + bytes_offset, bytes.start(), bytes.length());
|
||||
Handle<SeqOneByteString> new_bytes_str = Handle<SeqOneByteString>::cast(
|
||||
isolate_->factory()->NewStringFromOneByte(new_bytes).ToHandleChecked());
|
||||
instance_object_->compiled_module()->shared()->set_module_bytes(
|
||||
*new_bytes_str);
|
||||
return bytes_offset;
|
||||
}
|
||||
uint32_t AddBytes(Vector<const byte> bytes);
|
||||
|
||||
WasmFunction* GetFunctionAt(int index) {
|
||||
return &test_module_.functions[index];
|
||||
@ -335,24 +188,7 @@ class TestingModuleBuilder {
|
||||
}
|
||||
Address globals_start() { return reinterpret_cast<Address>(globals_data_); }
|
||||
|
||||
compiler::ModuleEnv CreateModuleEnv() {
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
for (size_t i = 0; i < test_module_.function_tables.size(); i++) {
|
||||
auto& function_table = test_module_.function_tables[i];
|
||||
signature_maps.push_back(&function_table.map);
|
||||
}
|
||||
return {
|
||||
&test_module_,
|
||||
function_tables_,
|
||||
signature_tables_,
|
||||
signature_maps,
|
||||
function_code_,
|
||||
Handle<Code>::null(),
|
||||
reinterpret_cast<uintptr_t>(mem_start_),
|
||||
mem_size_,
|
||||
reinterpret_cast<uintptr_t>(globals_data_),
|
||||
};
|
||||
}
|
||||
compiler::ModuleEnv CreateModuleEnv();
|
||||
|
||||
private:
|
||||
WasmModule test_module_;
|
||||
@ -368,143 +204,23 @@ class TestingModuleBuilder {
|
||||
WasmInterpreter* interpreter_;
|
||||
Handle<WasmInstanceObject> instance_object_;
|
||||
|
||||
const WasmGlobal* AddGlobal(ValueType type) {
|
||||
byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type));
|
||||
global_offset = (global_offset + size - 1) & ~(size - 1); // align
|
||||
test_module_.globals.push_back(
|
||||
{type, true, WasmInitExpr(), global_offset, false, false});
|
||||
global_offset += size;
|
||||
// limit number of globals.
|
||||
CHECK_LT(global_offset, kMaxGlobalsSize);
|
||||
return &test_module_.globals.back();
|
||||
}
|
||||
const WasmGlobal* AddGlobal(ValueType type);
|
||||
|
||||
Handle<WasmInstanceObject> InitInstanceObject() {
|
||||
Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast(
|
||||
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
|
||||
// The lifetime of the wasm module is tied to this object's, and we cannot
|
||||
// rely on the mechanics of Managed<T>.
|
||||
Handle<Foreign> module_wrapper = isolate_->factory()->NewForeign(
|
||||
reinterpret_cast<Address>(&test_module_ptr_));
|
||||
Handle<Script> script =
|
||||
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
|
||||
script->set_type(Script::TYPE_WASM);
|
||||
Handle<WasmSharedModuleData> shared_module_data =
|
||||
WasmSharedModuleData::New(isolate_, module_wrapper, empty_string,
|
||||
script, Handle<ByteArray>::null());
|
||||
Handle<FixedArray> code_table = isolate_->factory()->NewFixedArray(0);
|
||||
Handle<FixedArray> export_wrappers = isolate_->factory()->NewFixedArray(0);
|
||||
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
|
||||
isolate_, shared_module_data, code_table, export_wrappers,
|
||||
function_tables_, signature_tables_);
|
||||
// This method is called when we initialize TestEnvironment. We don't
|
||||
// have a memory yet, so we won't create it here. We'll update the
|
||||
// interpreter when we get a memory. We do have globals, though.
|
||||
WasmCompiledModule::recreate_globals_start(
|
||||
compiled_module, isolate_->factory(),
|
||||
reinterpret_cast<size_t>(globals_data_));
|
||||
Handle<FixedArray> weak_exported = isolate_->factory()->NewFixedArray(0);
|
||||
compiled_module->set_weak_exported_functions(weak_exported);
|
||||
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
|
||||
script->set_wasm_compiled_module(*compiled_module);
|
||||
return WasmInstanceObject::New(isolate_, compiled_module);
|
||||
}
|
||||
Handle<WasmInstanceObject> InitInstanceObject();
|
||||
};
|
||||
|
||||
inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
|
||||
FunctionSig* sig,
|
||||
SourcePositionTable* source_position_table,
|
||||
const byte* start, const byte* end,
|
||||
bool runtime_exception_support = false) {
|
||||
compiler::WasmGraphBuilder builder(
|
||||
module, zone, jsgraph, CEntryStub(jsgraph->isolate(), 1).GetCode(), sig,
|
||||
source_position_table);
|
||||
builder.SetRuntimeExceptionSupport(runtime_exception_support);
|
||||
void TestBuildingGraph(Zone* zone, compiler::JSGraph* jsgraph,
|
||||
compiler::ModuleEnv* module, FunctionSig* sig,
|
||||
compiler::SourcePositionTable* source_position_table,
|
||||
const byte* start, const byte* end,
|
||||
bool runtime_exception_support = false);
|
||||
|
||||
DecodeResult result =
|
||||
BuildTFGraph(zone->allocator(), &builder, sig, start, end);
|
||||
if (result.failed()) {
|
||||
if (!FLAG_trace_wasm_decoder) {
|
||||
// Retry the compilation with the tracing flag on, to help in debugging.
|
||||
FLAG_trace_wasm_decoder = true;
|
||||
result = BuildTFGraph(zone->allocator(), &builder, sig, start, end);
|
||||
}
|
||||
|
||||
uint32_t pc = result.error_offset();
|
||||
std::ostringstream str;
|
||||
str << "Verification failed; pc = +" << pc
|
||||
<< ", msg = " << result.error_msg().c_str();
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
builder.LowerInt64();
|
||||
if (!CpuFeatures::SupportsWasmSimd128()) {
|
||||
builder.SimdScalarLoweringForTesting();
|
||||
}
|
||||
}
|
||||
|
||||
class WasmFunctionWrapper : private GraphAndBuilders {
|
||||
class WasmFunctionWrapper : private compiler::GraphAndBuilders {
|
||||
public:
|
||||
explicit WasmFunctionWrapper(Zone* zone, int num_params)
|
||||
: GraphAndBuilders(zone), inner_code_node_(nullptr), signature_(nullptr) {
|
||||
// One additional parameter for the pointer to the return value memory.
|
||||
Signature<MachineType>::Builder sig_builder(zone, 1, num_params + 1);
|
||||
|
||||
sig_builder.AddReturn(MachineType::Int32());
|
||||
for (int i = 0; i < num_params + 1; i++) {
|
||||
sig_builder.AddParam(MachineType::Pointer());
|
||||
}
|
||||
signature_ = sig_builder.Build();
|
||||
}
|
||||
WasmFunctionWrapper(Zone* zone, int num_params);
|
||||
|
||||
void Init(CallDescriptor* descriptor, MachineType return_type,
|
||||
Vector<MachineType> param_types) {
|
||||
DCHECK_NOT_NULL(descriptor);
|
||||
DCHECK_EQ(signature_->parameter_count(), param_types.length() + 1);
|
||||
|
||||
// Create the TF graph for the wrapper.
|
||||
|
||||
// Function, effect, and control.
|
||||
Node** parameters = zone()->NewArray<Node*>(param_types.length() + 3);
|
||||
graph()->SetStart(graph()->NewNode(common()->Start(6)));
|
||||
Node* effect = graph()->start();
|
||||
int parameter_count = 0;
|
||||
|
||||
// Dummy node which gets replaced in SetInnerCode.
|
||||
inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
|
||||
parameters[parameter_count++] = inner_code_node_;
|
||||
|
||||
int param_idx = 0;
|
||||
for (MachineType t : param_types) {
|
||||
DCHECK_NE(MachineType::None(), t);
|
||||
parameters[parameter_count] = graph()->NewNode(
|
||||
machine()->Load(t),
|
||||
graph()->NewNode(common()->Parameter(param_idx++), graph()->start()),
|
||||
graph()->NewNode(common()->Int32Constant(0)), effect,
|
||||
graph()->start());
|
||||
effect = parameters[parameter_count++];
|
||||
}
|
||||
|
||||
parameters[parameter_count++] = effect;
|
||||
parameters[parameter_count++] = graph()->start();
|
||||
Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count,
|
||||
parameters);
|
||||
|
||||
if (!return_type.IsNone()) {
|
||||
effect = graph()->NewNode(
|
||||
machine()->Store(StoreRepresentation(
|
||||
return_type.representation(), WriteBarrierKind::kNoWriteBarrier)),
|
||||
graph()->NewNode(common()->Parameter(param_types.length()),
|
||||
graph()->start()),
|
||||
graph()->NewNode(common()->Int32Constant(0)), call, effect,
|
||||
graph()->start());
|
||||
}
|
||||
Node* zero = graph()->NewNode(common()->Int32Constant(0));
|
||||
Node* r = graph()->NewNode(
|
||||
common()->Return(), zero,
|
||||
graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
|
||||
effect, graph()->start());
|
||||
graph()->SetEnd(graph()->NewNode(common()->End(1), r));
|
||||
}
|
||||
Vector<MachineType> param_types);
|
||||
|
||||
template <typename ReturnType, typename... ParamTypes>
|
||||
void Init(CallDescriptor* descriptor) {
|
||||
@ -516,47 +232,11 @@ class WasmFunctionWrapper : private GraphAndBuilders {
|
||||
}
|
||||
|
||||
void SetInnerCode(Handle<Code> code_handle) {
|
||||
NodeProperties::ChangeOp(inner_code_node_,
|
||||
common()->HeapConstant(code_handle));
|
||||
compiler::NodeProperties::ChangeOp(inner_code_node_,
|
||||
common()->HeapConstant(code_handle));
|
||||
}
|
||||
|
||||
Handle<Code> GetWrapperCode() {
|
||||
if (code_.is_null()) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
|
||||
CallDescriptor* descriptor =
|
||||
Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
|
||||
|
||||
if (kPointerSize == 4) {
|
||||
size_t num_params = signature_->parameter_count();
|
||||
// One additional parameter for the pointer of the return value.
|
||||
Signature<MachineRepresentation>::Builder rep_builder(zone(), 1,
|
||||
num_params + 1);
|
||||
|
||||
rep_builder.AddReturn(MachineRepresentation::kWord32);
|
||||
for (size_t i = 0; i < num_params + 1; i++) {
|
||||
rep_builder.AddParam(MachineRepresentation::kWord32);
|
||||
}
|
||||
Int64Lowering r(graph(), machine(), common(), zone(),
|
||||
rep_builder.Build());
|
||||
r.LowerGraph();
|
||||
}
|
||||
|
||||
CompilationInfo info(ArrayVector("testing"), isolate, graph()->zone(),
|
||||
Code::ComputeFlags(Code::STUB));
|
||||
code_ =
|
||||
Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
|
||||
CHECK(!code_.is_null());
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
code_->Disassemble("wasm wrapper", os);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return code_;
|
||||
}
|
||||
Handle<Code> GetWrapperCode();
|
||||
|
||||
Signature<MachineType>* signature() const { return signature_; }
|
||||
|
||||
@ -569,13 +249,9 @@ class WasmFunctionWrapper : private GraphAndBuilders {
|
||||
// A helper for compiling wasm functions for testing.
|
||||
// It contains the internal state for compilation (i.e. TurboFan graph) and
|
||||
// interpretation (by adding to the interpreter manually).
|
||||
class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
class WasmFunctionCompiler : public compiler::GraphAndBuilders {
|
||||
public:
|
||||
Isolate* isolate() { return builder_->isolate(); }
|
||||
Graph* graph() const { return main_graph_; }
|
||||
Zone* zone() const { return graph()->zone(); }
|
||||
CommonOperatorBuilder* common() { return &main_common_; }
|
||||
MachineOperatorBuilder* machine() { return &main_machine_; }
|
||||
CallDescriptor* descriptor() {
|
||||
if (descriptor_ == nullptr) {
|
||||
descriptor_ = compiler::GetWasmCallDescriptor(zone(), sig);
|
||||
@ -584,56 +260,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
}
|
||||
uint32_t function_index() { return function_->func_index; }
|
||||
|
||||
void Build(const byte* start, const byte* end) {
|
||||
size_t locals_size = local_decls.Size();
|
||||
size_t total_size = end - start + locals_size + 1;
|
||||
byte* buffer = static_cast<byte*>(zone()->New(total_size));
|
||||
// Prepend the local decls to the code.
|
||||
local_decls.Emit(buffer);
|
||||
// Emit the code.
|
||||
memcpy(buffer + locals_size, start, end - start);
|
||||
// Append an extra end opcode.
|
||||
buffer[total_size - 1] = kExprEnd;
|
||||
|
||||
start = buffer;
|
||||
end = buffer + total_size;
|
||||
|
||||
CHECK_GE(kMaxInt, end - start);
|
||||
int len = static_cast<int>(end - start);
|
||||
function_->code = {builder_->AddBytes(Vector<const byte>(start, len)),
|
||||
static_cast<uint32_t>(len)};
|
||||
|
||||
if (interpreter_) {
|
||||
// Add the code to the interpreter.
|
||||
interpreter_->SetFunctionCodeForTesting(function_, start, end);
|
||||
}
|
||||
|
||||
// Build the TurboFan graph.
|
||||
compiler::ModuleEnv module_env = builder_->CreateModuleEnv();
|
||||
TestBuildingGraph(zone(), &jsgraph, &module_env, sig,
|
||||
&source_position_table_, start, end,
|
||||
runtime_exception_support_);
|
||||
Handle<Code> code = Compile();
|
||||
builder_->SetFunctionCode(function_index(), code);
|
||||
|
||||
// Add to code table.
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
builder_->instance_object()->compiled_module(), isolate());
|
||||
Handle<FixedArray> code_table = compiled_module->code_table();
|
||||
if (static_cast<int>(function_index()) >= code_table->length()) {
|
||||
Handle<FixedArray> new_arr = isolate()->factory()->NewFixedArray(
|
||||
static_cast<int>(function_index()) + 1);
|
||||
code_table->CopyTo(0, *new_arr, 0, code_table->length());
|
||||
code_table = new_arr;
|
||||
compiled_module->ReplaceCodeTableForTesting(code_table);
|
||||
}
|
||||
DCHECK(code_table->get(static_cast<int>(function_index()))
|
||||
->IsUndefined(isolate()));
|
||||
code_table->set(static_cast<int>(function_index()), *code);
|
||||
if (trap_handler::UseTrapHandler()) {
|
||||
UnpackAndRegisterProtectedInstructions(isolate(), code_table);
|
||||
}
|
||||
}
|
||||
void Build(const byte* start, const byte* end);
|
||||
|
||||
byte AllocateLocal(ValueType type) {
|
||||
uint32_t index = local_decls.AddLocals(1, type);
|
||||
@ -647,65 +274,13 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
private:
|
||||
friend class WasmRunnerBase;
|
||||
|
||||
explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
|
||||
TestingModuleBuilder* builder, const char* name,
|
||||
bool runtime_exception_support)
|
||||
: GraphAndBuilders(zone),
|
||||
jsgraph(builder->isolate(), this->graph(), this->common(), nullptr,
|
||||
nullptr, this->machine()),
|
||||
sig(sig),
|
||||
descriptor_(nullptr),
|
||||
builder_(builder),
|
||||
local_decls(zone, sig),
|
||||
source_position_table_(this->graph()),
|
||||
interpreter_(builder->interpreter()),
|
||||
runtime_exception_support_(runtime_exception_support) {
|
||||
// Get a new function from the testing module.
|
||||
int index = builder->AddFunction(sig, Handle<Code>::null(), name);
|
||||
function_ = builder_->GetFunctionAt(index);
|
||||
}
|
||||
WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
|
||||
TestingModuleBuilder* builder, const char* name,
|
||||
bool runtime_exception_support);
|
||||
|
||||
Handle<Code> Compile() {
|
||||
CallDescriptor* desc = descriptor();
|
||||
if (kPointerSize == 4) {
|
||||
desc = compiler::GetI32WasmCallDescriptor(this->zone(), desc);
|
||||
}
|
||||
EmbeddedVector<char, 16> comp_name;
|
||||
int comp_name_len = SNPrintF(comp_name, "wasm#%u", this->function_index());
|
||||
comp_name.Truncate(comp_name_len);
|
||||
CompilationInfo info(comp_name, this->isolate(), this->zone(),
|
||||
Code::ComputeFlags(Code::WASM_FUNCTION));
|
||||
std::unique_ptr<CompilationJob> job(Pipeline::NewWasmCompilationJob(
|
||||
&info, &jsgraph, desc, &source_position_table_, nullptr,
|
||||
ModuleOrigin::kAsmJsOrigin));
|
||||
if (job->ExecuteJob() != CompilationJob::SUCCEEDED ||
|
||||
job->FinalizeJob() != CompilationJob::SUCCEEDED)
|
||||
return Handle<Code>::null();
|
||||
Handle<Code> Compile();
|
||||
|
||||
Handle<Code> code = info.code();
|
||||
|
||||
// Deopt data holds <WeakCell<wasm_instance>, func_index>.
|
||||
DCHECK(code->deoptimization_data() == nullptr ||
|
||||
code->deoptimization_data()->length() == 0);
|
||||
Handle<FixedArray> deopt_data =
|
||||
isolate()->factory()->NewFixedArray(2, TENURED);
|
||||
Handle<Object> weak_instance =
|
||||
isolate()->factory()->NewWeakCell(builder_->instance_object());
|
||||
deopt_data->set(0, *weak_instance);
|
||||
deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
|
||||
code->set_deoptimization_data(*deopt_data);
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble("wasm code", os);
|
||||
}
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
JSGraph jsgraph;
|
||||
compiler::JSGraph jsgraph;
|
||||
FunctionSig* sig;
|
||||
// The call descriptor is initialized when the function is compiled.
|
||||
CallDescriptor* descriptor_;
|
||||
@ -713,7 +288,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
Vector<const char> debug_name_;
|
||||
WasmFunction* function_;
|
||||
LocalDeclEncoder local_decls;
|
||||
SourcePositionTable source_position_table_;
|
||||
compiler::SourcePositionTable source_position_table_;
|
||||
WasmInterpreter* interpreter_;
|
||||
bool runtime_exception_support_ = false;
|
||||
};
|
||||
@ -722,8 +297,8 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
// code, and run that code.
|
||||
class WasmRunnerBase : public HandleAndZoneScope {
|
||||
public:
|
||||
explicit WasmRunnerBase(WasmExecutionMode execution_mode, int num_params,
|
||||
bool runtime_exception_support)
|
||||
WasmRunnerBase(WasmExecutionMode execution_mode, int num_params,
|
||||
bool runtime_exception_support)
|
||||
: zone_(&allocator_, ZONE_NAME),
|
||||
builder_(&zone_, execution_mode),
|
||||
wrapper_(&zone_, num_params),
|
||||
@ -782,24 +357,7 @@ class WasmRunnerBase : public HandleAndZoneScope {
|
||||
|
||||
private:
|
||||
FunctionSig* CreateSig(MachineType return_type,
|
||||
Vector<MachineType> param_types) {
|
||||
int return_count = return_type.IsNone() ? 0 : 1;
|
||||
int param_count = param_types.length();
|
||||
|
||||
// Allocate storage array in zone.
|
||||
ValueType* sig_types =
|
||||
zone_.NewArray<ValueType>(return_count + param_count);
|
||||
|
||||
// Convert machine types to local types, and check that there are no
|
||||
// MachineType::None()'s in the parameters.
|
||||
int idx = 0;
|
||||
if (return_count) sig_types[idx++] = WasmOpcodes::ValueTypeFor(return_type);
|
||||
for (MachineType param : param_types) {
|
||||
CHECK_NE(MachineType::None(), param);
|
||||
sig_types[idx++] = WasmOpcodes::ValueTypeFor(param);
|
||||
}
|
||||
return new (&zone_) FunctionSig(return_count, param_count, sig_types);
|
||||
}
|
||||
Vector<MachineType> param_types);
|
||||
|
||||
protected:
|
||||
v8::internal::AccountingAllocator allocator_;
|
||||
@ -820,9 +378,9 @@ class WasmRunnerBase : public HandleAndZoneScope {
|
||||
template <typename ReturnType, typename... ParamTypes>
|
||||
class WasmRunner : public WasmRunnerBase {
|
||||
public:
|
||||
explicit WasmRunner(WasmExecutionMode execution_mode,
|
||||
const char* main_fn_name = "main",
|
||||
bool runtime_exception_support = false)
|
||||
WasmRunner(WasmExecutionMode execution_mode,
|
||||
const char* main_fn_name = "main",
|
||||
bool runtime_exception_support = false)
|
||||
: WasmRunnerBase(execution_mode, sizeof...(ParamTypes),
|
||||
runtime_exception_support) {
|
||||
NewFunction<ReturnType, ParamTypes...>(main_fn_name);
|
||||
@ -844,8 +402,9 @@ class WasmRunner : public WasmRunnerBase {
|
||||
set_trap_callback_for_testing(trap_callback);
|
||||
|
||||
wrapper_.SetInnerCode(builder_.GetFunctionCode(0));
|
||||
CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
|
||||
wrapper_.GetWrapperCode(), wrapper_.signature());
|
||||
compiler::CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
|
||||
wrapper_.GetWrapperCode(),
|
||||
wrapper_.signature());
|
||||
int32_t result = runner.Call(static_cast<void*>(&p)...,
|
||||
static_cast<void*>(&return_value));
|
||||
CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
|
||||
@ -876,9 +435,6 @@ class WasmRunner : public WasmRunnerBase {
|
||||
}
|
||||
};
|
||||
|
||||
// Declare static variable.
|
||||
bool WasmRunnerBase::trap_happened;
|
||||
|
||||
// A macro to define tests that run in different engine configurations.
|
||||
#define WASM_EXEC_TEST(name) \
|
||||
void RunWasm_##name(WasmExecutionMode execution_mode); \
|
||||
@ -902,6 +458,8 @@ bool WasmRunnerBase::trap_happened;
|
||||
} \
|
||||
void RunWasm_##name(WasmExecutionMode execution_mode)
|
||||
|
||||
} // namespace
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "test/common/wasm/test-signatures.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::wasm;
|
||||
using namespace v8::internal::wasm::testing;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define B1(a) WASM_BLOCK(a)
|
||||
#define B2(a, b) WASM_BLOCK(a, b)
|
||||
@ -2853,3 +2853,7 @@ TEST_F(BytecodeIteratorTest, WithLocalDecls) {
|
||||
iter.next();
|
||||
EXPECT_FALSE(iter.has_next());
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user