[wasm] Test argument passing in the interpreter entry
Test the wasm interpreter entry stub by creating two wasm functions A and B, make A pass arguments to B, then redirect B to be executed in the interpreter. Test different number and types or arguments. BUG=v8:5822 R=titzer@chromium.org Review-Url: https://codereview.chromium.org/2651793003 Cr-Commit-Position: refs/heads/master@{#43353}
This commit is contained in:
parent
cc805e42af
commit
e6819ee286
@ -273,6 +273,11 @@ class InterpreterHandle {
|
||||
return std::unique_ptr<wasm::InterpretedFrame>(
|
||||
new wasm::InterpretedFrame(thread->GetMutableFrame(idx)));
|
||||
}
|
||||
|
||||
uint64_t NumInterpretedCalls() {
|
||||
DCHECK_EQ(1, interpreter()->GetThreadCount());
|
||||
return interpreter()->GetThread(0)->NumInterpretedCalls();
|
||||
}
|
||||
};
|
||||
|
||||
InterpreterHandle* GetOrCreateInterpreterHandle(
|
||||
@ -294,6 +299,12 @@ InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
|
||||
return Managed<InterpreterHandle>::cast(handle_obj)->get();
|
||||
}
|
||||
|
||||
InterpreterHandle* GetInterpreterHandleOrNull(WasmDebugInfo* debug_info) {
|
||||
Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
|
||||
if (handle_obj->IsUndefined(debug_info->GetIsolate())) return nullptr;
|
||||
return Managed<InterpreterHandle>::cast(handle_obj)->get();
|
||||
}
|
||||
|
||||
int GetNumFunctions(WasmInstanceObject* instance) {
|
||||
size_t num_functions =
|
||||
instance->compiled_module()->module()->functions.size();
|
||||
@ -345,26 +356,6 @@ void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureRedirectToInterpreter(Isolate* isolate,
|
||||
Handle<WasmDebugInfo> debug_info,
|
||||
int func_index) {
|
||||
Handle<FixedArray> interpreted_functions =
|
||||
GetOrCreateInterpretedFunctions(isolate, debug_info);
|
||||
if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) return;
|
||||
|
||||
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
|
||||
Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
|
||||
isolate, func_index,
|
||||
instance->compiled_module()->module()->functions[func_index].sig,
|
||||
instance);
|
||||
|
||||
Handle<FixedArray> code_table = instance->compiled_module()->code_table();
|
||||
Handle<Code> old_code(Code::cast(code_table->get(func_index)), isolate);
|
||||
interpreted_functions->set(func_index, *new_code);
|
||||
|
||||
RedirectCallsitesInInstance(isolate, *instance, *old_code, *new_code);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
|
||||
@ -400,12 +391,34 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
|
||||
int func_index, int offset) {
|
||||
Isolate* isolate = debug_info->GetIsolate();
|
||||
InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
|
||||
WasmInterpreter* interpreter = handle->interpreter();
|
||||
DCHECK_LE(0, func_index);
|
||||
DCHECK_GT(handle->module()->functions.size(), func_index);
|
||||
RedirectToInterpreter(debug_info, func_index);
|
||||
const WasmFunction* func = &handle->module()->functions[func_index];
|
||||
interpreter->SetBreakpoint(func, offset, true);
|
||||
EnsureRedirectToInterpreter(isolate, debug_info, func_index);
|
||||
handle->interpreter()->SetBreakpoint(func, offset, true);
|
||||
}
|
||||
|
||||
void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
|
||||
int func_index) {
|
||||
Isolate* isolate = debug_info->GetIsolate();
|
||||
DCHECK_LE(0, func_index);
|
||||
DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
|
||||
func_index);
|
||||
Handle<FixedArray> interpreted_functions =
|
||||
GetOrCreateInterpretedFunctions(isolate, debug_info);
|
||||
if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) return;
|
||||
|
||||
// Ensure that the interpreter is instantiated.
|
||||
GetOrCreateInterpreterHandle(isolate, debug_info);
|
||||
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
|
||||
Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
|
||||
isolate, func_index,
|
||||
instance->compiled_module()->module()->functions[func_index].sig,
|
||||
instance);
|
||||
|
||||
Handle<FixedArray> code_table = instance->compiled_module()->code_table();
|
||||
Handle<Code> old_code(Code::cast(code_table->get(func_index)), isolate);
|
||||
interpreted_functions->set(func_index, *new_code);
|
||||
|
||||
RedirectCallsitesInInstance(isolate, *instance, *old_code, *new_code);
|
||||
}
|
||||
|
||||
void WasmDebugInfo::PrepareStep(StepAction step_action) {
|
||||
@ -427,3 +440,8 @@ std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame(
|
||||
Address frame_pointer, int idx) {
|
||||
return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx);
|
||||
}
|
||||
|
||||
uint64_t WasmDebugInfo::NumInterpretedCalls() {
|
||||
auto handle = GetInterpreterHandleOrNull(this);
|
||||
return handle ? handle->NumInterpretedCalls() : 0;
|
||||
}
|
||||
|
@ -935,6 +935,7 @@ class ThreadImpl {
|
||||
void PushFrame(const WasmFunction* function, WasmVal* args) {
|
||||
InterpreterCode* code = codemap()->FindCode(function);
|
||||
CHECK_NOT_NULL(code);
|
||||
++num_interpreted_calls_;
|
||||
frames_.push_back({code, 0, 0, stack_.size()});
|
||||
for (size_t i = 0; i < function->sig->parameter_count(); ++i) {
|
||||
stack_.push_back(args[i]);
|
||||
@ -1009,6 +1010,8 @@ class ThreadImpl {
|
||||
|
||||
bool PossibleNondeterminism() { return possible_nondeterminism_; }
|
||||
|
||||
uint64_t NumInterpretedCalls() { return num_interpreted_calls_; }
|
||||
|
||||
void AddBreakFlags(uint8_t flags) { break_flags_ |= flags; }
|
||||
|
||||
void ClearBreakFlags() { break_flags_ = WasmInterpreter::BreakFlag::None; }
|
||||
@ -1044,6 +1047,7 @@ class ThreadImpl {
|
||||
TrapReason trap_reason_ = kTrapCount;
|
||||
bool possible_nondeterminism_ = false;
|
||||
uint8_t break_flags_ = 0; // a combination of WasmInterpreter::BreakFlag
|
||||
uint64_t num_interpreted_calls_ = 0;
|
||||
|
||||
CodeMap* codemap() { return codemap_; }
|
||||
WasmInstance* instance() { return instance_; }
|
||||
@ -1059,6 +1063,7 @@ class ThreadImpl {
|
||||
void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) {
|
||||
CHECK_NOT_NULL(code);
|
||||
DCHECK(!frames_.empty());
|
||||
++num_interpreted_calls_;
|
||||
frames_.back().call_pc = call_pc;
|
||||
frames_.back().ret_pc = ret_pc;
|
||||
size_t arity = code->function->sig->parameter_count();
|
||||
@ -1797,6 +1802,9 @@ WasmVal WasmInterpreter::Thread::GetReturnValue(int index) {
|
||||
bool WasmInterpreter::Thread::PossibleNondeterminism() {
|
||||
return ToImpl(this)->PossibleNondeterminism();
|
||||
}
|
||||
uint64_t WasmInterpreter::Thread::NumInterpretedCalls() {
|
||||
return ToImpl(this)->NumInterpretedCalls();
|
||||
}
|
||||
void WasmInterpreter::Thread::AddBreakFlags(uint8_t flags) {
|
||||
ToImpl(this)->AddBreakFlags(flags);
|
||||
}
|
||||
|
@ -148,11 +148,15 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
const InterpretedFrame GetFrame(int index);
|
||||
InterpretedFrame GetMutableFrame(int index);
|
||||
WasmVal GetReturnValue(int index = 0);
|
||||
|
||||
// Returns true if the thread executed an instruction which may produce
|
||||
// nondeterministic results, e.g. float div, float sqrt, and float mul,
|
||||
// where the sign bit of a NaN is nondeterministic.
|
||||
bool PossibleNondeterminism();
|
||||
|
||||
// Returns the number of calls / function frames executed on this thread.
|
||||
uint64_t NumInterpretedCalls();
|
||||
|
||||
// Thread-specific breakpoints.
|
||||
// TODO(wasm): Implement this once we support multiple threads.
|
||||
// bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
|
||||
|
@ -372,15 +372,16 @@ class LocalDeclEncoder {
|
||||
static_cast<byte>(bit_cast<uint32_t>(static_cast<float>(val)) >> 8), \
|
||||
static_cast<byte>(bit_cast<uint32_t>(static_cast<float>(val)) >> 16), \
|
||||
static_cast<byte>(bit_cast<uint32_t>(static_cast<float>(val)) >> 24)
|
||||
#define WASM_F64(val) \
|
||||
kExprF64Const, static_cast<byte>(bit_cast<uint64_t>(val)), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 8), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 16), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 24), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 32), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 40), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 48), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(val) >> 56)
|
||||
#define WASM_F64(val) \
|
||||
kExprF64Const, \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val))), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 8), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 16), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 24), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 32), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 40), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 48), \
|
||||
static_cast<byte>(bit_cast<uint64_t>(static_cast<double>(val)) >> 56)
|
||||
#define WASM_GET_LOCAL(index) kExprGetLocal, static_cast<byte>(index)
|
||||
#define WASM_SET_LOCAL(index, val) val, kExprSetLocal, static_cast<byte>(index)
|
||||
#define WASM_TEE_LOCAL(index, val) val, kExprTeeLocal, static_cast<byte>(index)
|
||||
|
@ -420,8 +420,15 @@ class WasmDebugInfo : public FixedArray {
|
||||
static bool IsDebugInfo(Object*);
|
||||
static WasmDebugInfo* cast(Object*);
|
||||
|
||||
// Set a breakpoint in the given function at the given byte offset within that
|
||||
// function. This will redirect all future calls to this function to the
|
||||
// interpreter and will always pause at the given offset.
|
||||
static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset);
|
||||
|
||||
// Make a function always execute in the interpreter without setting a
|
||||
// breakpoints.
|
||||
static void RedirectToInterpreter(Handle<WasmDebugInfo>, int func_index);
|
||||
|
||||
void PrepareStep(StepAction);
|
||||
|
||||
void RunInterpreter(int func_index, uint8_t* arg_buffer);
|
||||
@ -434,6 +441,9 @@ class WasmDebugInfo : public FixedArray {
|
||||
std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
|
||||
Address frame_pointer, int idx);
|
||||
|
||||
// Returns the number of calls / function frames executed in the interpreter.
|
||||
uint64_t NumInterpretedCalls();
|
||||
|
||||
DECLARE_GETTER(wasm_instance, WasmInstanceObject);
|
||||
};
|
||||
|
||||
|
@ -195,6 +195,7 @@ v8_executable("cctest") {
|
||||
"wasm/test-run-wasm-relocation.cc",
|
||||
"wasm/test-run-wasm.cc",
|
||||
"wasm/test-wasm-breakpoints.cc",
|
||||
"wasm/test-wasm-interpreter-entry.cc",
|
||||
"wasm/test-wasm-stack.cc",
|
||||
"wasm/test-wasm-trap-position.cc",
|
||||
"wasm/wasm-run-utils.h",
|
||||
|
@ -216,6 +216,7 @@
|
||||
'wasm/test-run-wasm-module.cc',
|
||||
'wasm/test-run-wasm-relocation.cc',
|
||||
'wasm/test-wasm-breakpoints.cc',
|
||||
'wasm/test-wasm-interpreter-entry.cc',
|
||||
'wasm/test-wasm-stack.cc',
|
||||
'wasm/test-wasm-trap-position.cc',
|
||||
'wasm/wasm-run-utils.h',
|
||||
|
231
test/cctest/wasm/test-wasm-interpreter-entry.cc
Normal file
231
test/cctest/wasm/test-wasm-interpreter-entry.cc
Normal file
@ -0,0 +1,231 @@
|
||||
// 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 <cstdint>
|
||||
|
||||
#include "src/wasm/wasm-macro-gen.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::wasm;
|
||||
namespace debug = v8::debug;
|
||||
|
||||
/**
|
||||
* We test the interface from Wasm compiled code to the Wasm interpreter by
|
||||
* building a module with two functions. The external function is called from
|
||||
* this test, and will be compiled code. It takes its arguments and passes them
|
||||
* on to the internal function, which will be redirected to the interpreter.
|
||||
* If the internal function has an i64 parameter, is has to be replaced by two
|
||||
* i32 parameters on the external function.
|
||||
* The internal function just converts all its arguments to f64, sums them up
|
||||
* and returns the sum.
|
||||
*/
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
class ArgPassingHelper {
|
||||
public:
|
||||
ArgPassingHelper(WasmRunnerBase& runner, WasmFunctionCompiler& inner_compiler,
|
||||
std::initializer_list<uint8_t> bytes_inner_function,
|
||||
std::initializer_list<uint8_t> bytes_outer_function,
|
||||
const T& expected_lambda)
|
||||
: isolate_(runner.main_isolate()),
|
||||
expected_lambda_(expected_lambda),
|
||||
debug_info_(WasmInstanceObject::GetOrCreateDebugInfo(
|
||||
runner.module().instance_object())) {
|
||||
std::vector<uint8_t> inner_code{bytes_inner_function};
|
||||
inner_compiler.Build(inner_code.data(),
|
||||
inner_code.data() + inner_code.size());
|
||||
|
||||
std::vector<uint8_t> outer_code{bytes_outer_function};
|
||||
runner.Build(outer_code.data(), outer_code.data() + outer_code.size());
|
||||
|
||||
WasmDebugInfo::RedirectToInterpreter(debug_info_,
|
||||
inner_compiler.function_index());
|
||||
main_fun_wrapper_ = runner.module().WrapCode(runner.function_index());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void CheckCall(Args... args) {
|
||||
Handle<Object> arg_objs[] = {isolate_->factory()->NewNumber(args)...};
|
||||
|
||||
uint64_t num_interpreted_before = debug_info_->NumInterpretedCalls();
|
||||
Handle<Object> global(isolate_->context()->global_object(), isolate_);
|
||||
MaybeHandle<Object> retval = Execution::Call(
|
||||
isolate_, main_fun_wrapper_, global, arraysize(arg_objs), arg_objs);
|
||||
uint64_t num_interpreted_after = debug_info_->NumInterpretedCalls();
|
||||
// Check that we really went through the interpreter.
|
||||
CHECK_EQ(num_interpreted_before + 1, num_interpreted_after);
|
||||
// Check the result.
|
||||
double result = retval.ToHandleChecked()->Number();
|
||||
double expected = expected_lambda_(args...);
|
||||
CHECK_DOUBLE_EQ(expected, result);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
T expected_lambda_;
|
||||
Handle<WasmDebugInfo> debug_info_;
|
||||
Handle<JSFunction> main_fun_wrapper_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static ArgPassingHelper<T> GetHelper(
|
||||
WasmRunnerBase& runner, WasmFunctionCompiler& inner_compiler,
|
||||
std::initializer_list<uint8_t> bytes_inner_function,
|
||||
std::initializer_list<uint8_t> bytes_outer_function,
|
||||
const T& expected_lambda) {
|
||||
return ArgPassingHelper<T>(runner, inner_compiler, bytes_inner_function,
|
||||
bytes_outer_function, expected_lambda);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(TestArgumentPassing_int32) {
|
||||
WasmRunner<int32_t, int32_t> runner(kExecuteCompiled);
|
||||
WasmFunctionCompiler& f2 = runner.NewFunction<int32_t, int32_t>();
|
||||
|
||||
auto helper = GetHelper(
|
||||
runner, f2,
|
||||
{// Return 2*<0> + 1.
|
||||
WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
|
||||
{// Call f2 with param <0>.
|
||||
WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](int32_t a) { return 2 * a + 1; });
|
||||
|
||||
std::vector<int32_t> test_values = compiler::ValueHelper::int32_vector();
|
||||
for (int32_t v : test_values) helper.CheckCall(v);
|
||||
}
|
||||
|
||||
TEST(TestArgumentPassing_int64) {
|
||||
WasmRunner<double, int32_t, int32_t> runner(kExecuteCompiled);
|
||||
WasmFunctionCompiler& f2 = runner.NewFunction<double, int64_t>();
|
||||
|
||||
auto helper = GetHelper(
|
||||
runner, f2,
|
||||
{// Return (double)<0>.
|
||||
WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))},
|
||||
{// Call f2 with param (<0> | (<1> << 32)).
|
||||
WASM_I64_IOR(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(0)),
|
||||
WASM_I64_SHL(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(1)),
|
||||
WASM_I64V_1(32))),
|
||||
WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](int32_t a, int32_t b) {
|
||||
int64_t a64 = static_cast<int64_t>(a) & 0xffffffff;
|
||||
int64_t b64 = static_cast<int64_t>(b) << 32;
|
||||
return static_cast<double>(a64 | b64);
|
||||
});
|
||||
|
||||
std::vector<int32_t> test_values_i32 = compiler::ValueHelper::int32_vector();
|
||||
for (int32_t v1 : test_values_i32) {
|
||||
for (int32_t v2 : test_values_i32) {
|
||||
helper.CheckCall(v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int64_t> test_values_i64 = compiler::ValueHelper::int64_vector();
|
||||
for (int64_t v : test_values_i64) {
|
||||
int32_t v1 = static_cast<int32_t>(v);
|
||||
int32_t v2 = static_cast<int32_t>(v >> 32);
|
||||
helper.CheckCall(v1, v2);
|
||||
helper.CheckCall(v2, v1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestArgumentPassing_float_double) {
|
||||
WasmRunner<double, float> runner(kExecuteCompiled);
|
||||
WasmFunctionCompiler& f2 = runner.NewFunction<double, float>();
|
||||
|
||||
auto helper = GetHelper(
|
||||
runner, f2,
|
||||
{// Return 2*(double)<0> + 1.
|
||||
WASM_F64_ADD(
|
||||
WASM_F64_MUL(WASM_F64(2), WASM_F64_CONVERT_F32(WASM_GET_LOCAL(0))),
|
||||
WASM_F64(1))},
|
||||
{// Call f2 with param <0>.
|
||||
WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](float f) { return 2. * static_cast<double>(f) + 1.; });
|
||||
|
||||
std::vector<float> test_values = compiler::ValueHelper::float32_vector();
|
||||
for (float f : test_values) helper.CheckCall(f);
|
||||
}
|
||||
|
||||
TEST(TestArgumentPassing_double_double) {
|
||||
WasmRunner<double, double, double> runner(kExecuteCompiled);
|
||||
WasmFunctionCompiler& f2 = runner.NewFunction<double, double, double>();
|
||||
|
||||
auto helper = GetHelper(runner, f2,
|
||||
{// Return <0> + <1>.
|
||||
WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))},
|
||||
{// Call f2 with params <0>, <1>.
|
||||
WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
|
||||
WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](double a, double b) { return a + b; });
|
||||
|
||||
std::vector<double> test_values = compiler::ValueHelper::float64_vector();
|
||||
for (double d1 : test_values) {
|
||||
for (double d2 : test_values) {
|
||||
helper.CheckCall(d1, d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestArgumentPassing_AllTypes) {
|
||||
// The second and third argument will be combined to an i64.
|
||||
WasmRunner<double, int, int, int, float, double> runner(kExecuteCompiled);
|
||||
WasmFunctionCompiler& f2 =
|
||||
runner.NewFunction<double, int, int64_t, float, double>();
|
||||
|
||||
auto helper = GetHelper(
|
||||
runner, f2,
|
||||
{
|
||||
// Convert all arguments to double, add them and return the sum.
|
||||
WASM_F64_ADD( // <0+1+2> + <3>
|
||||
WASM_F64_ADD( // <0+1> + <2>
|
||||
WASM_F64_ADD( // <0> + <1>
|
||||
WASM_F64_SCONVERT_I32(
|
||||
WASM_GET_LOCAL(0)), // <0> to double
|
||||
WASM_F64_SCONVERT_I64(
|
||||
WASM_GET_LOCAL(1))), // <1> to double
|
||||
WASM_F64_CONVERT_F32(WASM_GET_LOCAL(2))), // <2> to double
|
||||
WASM_GET_LOCAL(3)) // <3>
|
||||
},
|
||||
{WASM_GET_LOCAL(0), // first arg
|
||||
WASM_I64_IOR(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(1)), // second arg
|
||||
WASM_I64_SHL(WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(2)),
|
||||
WASM_I64V_1(32))),
|
||||
WASM_GET_LOCAL(3), // third arg
|
||||
WASM_GET_LOCAL(4), // fourth arg
|
||||
WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](int32_t a, int32_t b, int32_t c, float d, double e) {
|
||||
return 0. + a + (static_cast<int64_t>(b) & 0xffffffff) +
|
||||
((static_cast<int64_t>(c) & 0xffffffff) << 32) + d + e;
|
||||
});
|
||||
|
||||
auto CheckCall = [&](int32_t a, int64_t b, float c, double d) {
|
||||
int32_t b0 = static_cast<int32_t>(b);
|
||||
int32_t b1 = static_cast<int32_t>(b >> 32);
|
||||
helper.CheckCall(a, b0, b1, c, d);
|
||||
helper.CheckCall(a, b1, b0, c, d);
|
||||
};
|
||||
|
||||
std::vector<int32_t> test_values_i32 = compiler::ValueHelper::int32_vector();
|
||||
std::vector<int64_t> test_values_i64 = compiler::ValueHelper::int64_vector();
|
||||
std::vector<float> test_values_f32 = compiler::ValueHelper::float32_vector();
|
||||
std::vector<double> test_values_f64 = compiler::ValueHelper::float64_vector();
|
||||
size_t max_len =
|
||||
std::max(std::max(test_values_i32.size(), test_values_i64.size()),
|
||||
std::max(test_values_f32.size(), test_values_f64.size()));
|
||||
for (size_t i = 0; i < max_len; ++i) {
|
||||
int32_t i32 = test_values_i32[i % test_values_i32.size()];
|
||||
int64_t i64 = test_values_i64[i % test_values_i64.size()];
|
||||
float f32 = test_values_f32[i % test_values_f32.size()];
|
||||
double f64 = test_values_f64[i % test_values_f64.size()];
|
||||
CheckCall(i32, i64, f32, f64);
|
||||
}
|
||||
}
|
@ -564,8 +564,16 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
testing_module_->instance_object()->compiled_module(), isolate());
|
||||
Handle<FixedArray> code_table = compiled_module->code_table();
|
||||
code_table = FixedArray::SetAndGrow(code_table, function_index(), code);
|
||||
compiled_module->set_code_table(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->set_code_table(code_table);
|
||||
}
|
||||
DCHECK(code_table->get(static_cast<int>(function_index()))
|
||||
->IsUndefined(isolate()));
|
||||
code_table->set(static_cast<int>(function_index()), *code);
|
||||
}
|
||||
|
||||
byte AllocateLocal(ValueType type) {
|
||||
|
Loading…
Reference in New Issue
Block a user