Commit 2d914c4c authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

[wasm] add wasm atomic wait callback test

Bug=v8:8075

Change-Id: I0c66acd329d0d6b67d34ad31c8ca401db38e0e5b
Reviewed-on: https://chromium-review.googlesource.com/c/1377995Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59709}
parent 27f5c101
...@@ -1696,6 +1696,15 @@ Object Isolate::UnwindAndFindHandler() { ...@@ -1696,6 +1696,15 @@ Object Isolate::UnwindAndFindHandler() {
// Some stubs are able to handle exceptions. // Some stubs are able to handle exceptions.
if (!catchable_by_js) break; if (!catchable_by_js) break;
StubFrame* stub_frame = static_cast<StubFrame*>(frame); 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(); Code code = stub_frame->LookupCode();
if (!code->IsCode() || code->kind() != Code::BUILTIN || if (!code->IsCode() || code->kind() != Code::BUILTIN ||
!code->has_handler_table() || !code->is_turbofanned()) { !code->has_handler_table() || !code->is_turbofanned()) {
......
...@@ -528,6 +528,8 @@ ...@@ -528,6 +528,8 @@
'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP], 'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP],
# TODO(v8:7777): Re-enable once wasm is supported in jitless mode. # 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-api/WasmStreaming*': [SKIP],
'test-c-wasm-entry/*': [SKIP], 'test-c-wasm-entry/*': [SKIP],
'test-jump-table-assembler/*': [SKIP], 'test-jump-table-assembler/*': [SKIP],
......
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
#include "src/wasm/wasm-js.h" #include "src/wasm/wasm-js.h"
#include "test/cctest/heap/heap-tester.h" #include "test/cctest/heap/heap-tester.h"
#include "test/cctest/heap/heap-utils.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; static const bool kLogThreading = false;
...@@ -27558,15 +27560,8 @@ void AtomicsWaitCallbackForTesting( ...@@ -27558,15 +27560,8 @@ void AtomicsWaitCallbackForTesting(
} }
} }
TEST(AtomicsWaitCallback) { // Must be called from within HandleScope
LocalContext env; void AtomicsWaitCallbackCommon(v8::Isolate* isolate, Local<Value> sab) {
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
Local<Value> sab = CompileRun(
"sab = new SharedArrayBuffer(12);"
"int32arr = new Int32Array(sab, 4);"
"sab");
CHECK(sab->IsSharedArrayBuffer()); CHECK(sab->IsSharedArrayBuffer());
AtomicsWaitCallbackInfo info; AtomicsWaitCallbackInfo info;
...@@ -27582,7 +27577,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27582,7 +27577,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution; info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
info.action = AtomicsWaitCallbackAction::Interrupt; info.action = AtomicsWaitCallbackAction::Interrupt;
info.ncalls = 0; info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 0, 0);"); CompileRun("wait(0, 0);");
CHECK_EQ(info.ncalls, 2); CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasTerminated()); CHECK(try_catch.HasTerminated());
} }
...@@ -27595,7 +27590,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27595,7 +27590,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual; info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
info.action = AtomicsWaitCallbackAction::KeepWaiting; info.action = AtomicsWaitCallbackAction::KeepWaiting;
info.ncalls = 0; 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_EQ(info.ncalls, 2);
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
} }
...@@ -27608,7 +27603,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27608,7 +27603,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut; info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
info.action = AtomicsWaitCallbackAction::KeepWaiting; info.action = AtomicsWaitCallbackAction::KeepWaiting;
info.ncalls = 0; 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_EQ(info.ncalls, 2);
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
} }
...@@ -27621,7 +27616,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27621,7 +27616,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped; info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall; info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
info.ncalls = 0; info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 0);"); CompileRun("wait(1, 0);");
CHECK_EQ(info.ncalls, 1); // Only one extra call CHECK_EQ(info.ncalls, 1); // Only one extra call
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32()); CHECK(try_catch.Exception()->IsInt32());
...@@ -27636,7 +27631,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27636,7 +27631,7 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped; info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall; info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
info.ncalls = 0; info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 1, 0);"); CompileRun("wait(1, 0);");
CHECK_EQ(info.ncalls, 2); CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32()); CHECK(try_catch.Exception()->IsInt32());
...@@ -27654,7 +27649,7 @@ TEST(AtomicsWaitCallback) { ...@@ -27654,7 +27649,7 @@ TEST(AtomicsWaitCallback) {
info.ncalls = 0; info.ncalls = 0;
CompileRun( CompileRun(
"int32arr[1] = 200;" "int32arr[1] = 200;"
"Atomics.wait(int32arr, 1, 200);"); "wait(1, 200);");
CHECK_EQ(info.ncalls, 2); CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32()); CHECK(try_catch.Exception()->IsInt32());
...@@ -27670,7 +27665,9 @@ TEST(AtomicsWaitCallback) { ...@@ -27670,7 +27665,9 @@ TEST(AtomicsWaitCallback) {
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped; info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow; info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
info.ncalls = 0; info.ncalls = 0;
CompileRun("Atomics.wait(int32arr, 0, 0);"); CompileRun(
"int32arr[1] = 0;"
"wait(0, 0);");
CHECK_EQ(info.ncalls, 2); CHECK_EQ(info.ncalls, 2);
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
CHECK(try_catch.Exception()->IsInt32()); CHECK(try_catch.Exception()->IsInt32());
...@@ -27678,6 +27675,96 @@ TEST(AtomicsWaitCallback) { ...@@ -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) { TEST(BigIntAPI) {
LocalContext env; LocalContext env;
v8::Isolate* isolate = env->GetIsolate(); v8::Isolate* isolate = env->GetIsolate();
......
...@@ -58,7 +58,7 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -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(!test_module_->has_memory);
CHECK_NULL(mem_start_); CHECK_NULL(mem_start_);
CHECK_EQ(0, mem_size_); CHECK_EQ(0, mem_size_);
...@@ -68,7 +68,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) { ...@@ -68,7 +68,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
test_module_->has_memory = true; test_module_->has_memory = true;
uint32_t alloc_size = RoundUp(size, kWasmPageSize); uint32_t alloc_size = RoundUp(size, kWasmPageSize);
Handle<JSArrayBuffer> new_buffer; 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()); CHECK(!new_buffer.is_null());
mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store()); mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
mem_size_ = size; mem_size_ = size;
......
...@@ -88,7 +88,7 @@ class TestingModuleBuilder { ...@@ -88,7 +88,7 @@ class TestingModuleBuilder {
void ChangeOriginToAsmjs() { test_module_->origin = kAsmJsOrigin; } 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(); } size_t CodeTableLength() const { return native_module_->num_functions(); }
......
...@@ -670,6 +670,8 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) { ...@@ -670,6 +670,8 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_ATOMICS_STORE_OP(op, x, y, representation) \ #define WASM_ATOMICS_STORE_OP(op, x, y, representation) \
x, y, WASM_ATOMICS_OP(op), \ x, y, WASM_ATOMICS_OP(op), \
static_cast<byte>(ElementSizeLog2Of(representation)), ZERO_OFFSET 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. // Sign Externsion Operations.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment