[wasm] add wasm atomic wait callback test

Bug=v8:8075

Change-Id: I0c66acd329d0d6b67d34ad31c8ca401db38e0e5b
Reviewed-on: https://chromium-review.googlesource.com/c/1377995
Reviewed-by: Ben Smith <binji@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59709}
This commit is contained in:
Aseem Garg 2019-02-18 16:52:07 -08:00 committed by Commit Bot
parent 27f5c10140
commit 2d914c4ce6
6 changed files with 119 additions and 19 deletions

View File

@ -1696,6 +1696,15 @@ Object Isolate::UnwindAndFindHandler() {
// Some stubs are able to handle exceptions.
if (!catchable_by_js) break;
StubFrame* stub_frame = static_cast<StubFrame*>(frame);
wasm::WasmCode* wasm_code =
wasm_engine()->code_manager()->LookupCode(frame->pc());
if (wasm_code != nullptr) {
// It is safe to skip Wasm runtime stubs as none of them contain local
// exception handlers.
CHECK_EQ(wasm::WasmCode::kRuntimeStub, wasm_code->kind());
CHECK_EQ(0, wasm_code->handler_table_offset());
break;
}
Code code = stub_frame->LookupCode();
if (!code->IsCode() || code->kind() != Code::BUILTIN ||
!code->has_handler_table() || !code->is_turbofanned()) {

View File

@ -528,6 +528,8 @@
'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP],
# TODO(v8:7777): Re-enable once wasm is supported in jitless mode.
'test-api/WasmI32AtomicWaitCallback': [SKIP],
'test-api/WasmI64AtomicWaitCallback': [SKIP],
'test-api/WasmStreaming*': [SKIP],
'test-c-wasm-entry/*': [SKIP],
'test-jump-table-assembler/*': [SKIP],

View File

@ -65,6 +65,8 @@
#include "src/wasm/wasm-js.h"
#include "test/cctest/heap/heap-tester.h"
#include "test/cctest/heap/heap-utils.h"
#include "test/cctest/wasm/wasm-run-utils.h"
#include "test/common/wasm/wasm-macro-gen.h"
static const bool kLogThreading = false;
@ -27558,15 +27560,8 @@ void AtomicsWaitCallbackForTesting(
}
}
TEST(AtomicsWaitCallback) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
Local<Value> sab = CompileRun(
"sab = new SharedArrayBuffer(12);"
"int32arr = new Int32Array(sab, 4);"
"sab");
// Must be called from within HandleScope
void AtomicsWaitCallbackCommon(v8::Isolate* isolate, Local<Value> sab) {
CHECK(sab->IsSharedArrayBuffer());
AtomicsWaitCallbackInfo info;
@ -27582,7 +27577,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
info.action = AtomicsWaitCallbackAction::Interrupt;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 0, 0);");
CompileRun("wait(0, 0);");
CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasTerminated());
}
@ -27595,7 +27590,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
info.action = AtomicsWaitCallbackAction::KeepWaiting;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 1);"); // real value is 0 != 1
CompileRun("wait(1, 1);"); // real value is 0 != 1
CHECK_EQ(info.ncalls, 2);
CHECK(!try_catch.HasCaught());
}
@ -27608,7 +27603,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
info.action = AtomicsWaitCallbackAction::KeepWaiting;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 0, 0.125);"); // timeout
CompileRun("wait(1, 0, 0.125);"); // timeout
CHECK_EQ(info.ncalls, 2);
CHECK(!try_catch.HasCaught());
}
@ -27621,7 +27616,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 0);");
CompileRun("wait(1, 0);");
CHECK_EQ(info.ncalls, 1); // Only one extra call
CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32());
@ -27636,7 +27631,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 0);");
CompileRun("wait(1, 0);");
CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32());
@ -27654,7 +27649,7 @@ TEST(AtomicsWaitCallback) {
info.ncalls = 0;
CompileRun(
"int32arr[1] = 200;"
"Atomics.wait(int32arr, 1, 200);");
"wait(1, 200);");
CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32());
@ -27670,7 +27665,9 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 0, 0);");
CompileRun(
"int32arr[1] = 0;"
"wait(0, 0);");
CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32());
@ -27678,6 +27675,96 @@ TEST(AtomicsWaitCallback) {
}
}
TEST(AtomicsWaitCallback) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
const char* init = R"(
let sab = new SharedArrayBuffer(16);
let int32arr = new Int32Array(sab, 4);
let wait = function(id, val, timeout) {
if(arguments.length == 2) return Atomics.wait(int32arr, id, val);
return Atomics.wait(int32arr, id, val, timeout);
};
sab;)";
AtomicsWaitCallbackCommon(isolate, CompileRun(init));
}
namespace v8 {
namespace internal {
namespace wasm {
TEST(WasmI32AtomicWaitCallback) {
FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
WasmRunner<int32_t, int32_t, int32_t, double> r(ExecutionTier::kOptimized);
r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
r.builder().SetHasSharedMemory();
BUILD(r, WASM_ATOMICS_WAIT(kExprI32AtomicWait, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1),
WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 4));
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
Handle<JSFunction> func = r.builder().WrapCode(0);
CHECK(env->Global()
->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
.FromJust());
Handle<JSArrayBuffer> memory(
r.builder().instance_object()->memory_object()->array_buffer(),
i_isolate);
CHECK(env->Global()
->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
.FromJust());
const char* init = R"(
let int32arr = new Int32Array(sab, 4);
let wait = function(id, val, timeout) {
if(arguments.length === 2)
return func(id << 2, val, -1);
return func(id << 2, val, timeout*1000000);
};
sab;)";
AtomicsWaitCallbackCommon(isolate, CompileRun(init));
}
TEST(WasmI64AtomicWaitCallback) {
FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
WasmRunner<int32_t, int32_t, double, double> r(ExecutionTier::kOptimized);
r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
r.builder().SetHasSharedMemory();
BUILD(r, WASM_ATOMICS_WAIT(kExprI64AtomicWait, WASM_GET_LOCAL(0),
WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(1)),
WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 4));
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
Handle<JSFunction> func = r.builder().WrapCode(0);
CHECK(env->Global()
->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
.FromJust());
Handle<JSArrayBuffer> memory(
r.builder().instance_object()->memory_object()->array_buffer(),
i_isolate);
CHECK(env->Global()
->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
.FromJust());
const char* init = R"(
let int32arr = new Int32Array(sab, 4);
let wait = function(id, val, timeout) {
if(arguments.length === 2)
return func(id << 2, val, -1);
return func(id << 2, val, timeout*1000000);
};
sab;)";
AtomicsWaitCallbackCommon(isolate, CompileRun(init));
}
} // namespace wasm
} // namespace internal
} // namespace v8
TEST(BigIntAPI) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();

View File

@ -58,7 +58,7 @@ TestingModuleBuilder::TestingModuleBuilder(
}
}
byte* TestingModuleBuilder::AddMemory(uint32_t size) {
byte* TestingModuleBuilder::AddMemory(uint32_t size, SharedFlag shared) {
CHECK(!test_module_->has_memory);
CHECK_NULL(mem_start_);
CHECK_EQ(0, mem_size_);
@ -68,7 +68,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
test_module_->has_memory = true;
uint32_t alloc_size = RoundUp(size, kWasmPageSize);
Handle<JSArrayBuffer> new_buffer;
CHECK(NewArrayBuffer(isolate_, alloc_size).ToHandle(&new_buffer));
CHECK(NewArrayBuffer(isolate_, alloc_size, shared).ToHandle(&new_buffer));
CHECK(!new_buffer.is_null());
mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
mem_size_ = size;

View File

@ -88,7 +88,7 @@ class TestingModuleBuilder {
void ChangeOriginToAsmjs() { test_module_->origin = kAsmJsOrigin; }
byte* AddMemory(uint32_t size);
byte* AddMemory(uint32_t size, SharedFlag shared = SharedFlag::kNotShared);
size_t CodeTableLength() const { return native_module_->num_functions(); }

View File

@ -670,6 +670,8 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_ATOMICS_STORE_OP(op, x, y, representation) \
x, y, WASM_ATOMICS_OP(op), \
static_cast<byte>(ElementSizeLog2Of(representation)), ZERO_OFFSET
#define WASM_ATOMICS_WAIT(op, index, value, timeout, offset) \
index, value, timeout, WASM_ATOMICS_OP(op), ZERO_ALIGNMENT, offset
//------------------------------------------------------------------------------
// Sign Externsion Operations.