Commit 234fa8cf authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

Reland "[wasm] add wasm atomic wait callback test"

This is a reland of 2d914c4c

Original change's description:
> [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}

Change-Id: Ic95a99f73844a7243a9c4eaadecda8c1c6686798
Reviewed-on: https://chromium-review.googlesource.com/c/1478217Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59716}
parent 0a069d94
......@@ -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()) {
......
......@@ -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],
......
......@@ -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,10 @@ 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,
size_t initial_offset,
size_t offset_multiplier) {
CHECK(sab->IsSharedArrayBuffer());
AtomicsWaitCallbackInfo info;
......@@ -27576,52 +27573,52 @@ TEST(AtomicsWaitCallback) {
{
v8::TryCatch try_catch(isolate);
info.expected_offset = 4;
info.expected_offset = initial_offset;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 0;
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());
}
{
v8::TryCatch try_catch(isolate);
info.expected_offset = 8;
info.expected_offset = initial_offset + offset_multiplier;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 1;
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());
}
{
v8::TryCatch try_catch(isolate);
info.expected_offset = 8;
info.expected_offset = initial_offset + offset_multiplier;
info.expected_timeout = 0.125;
info.expected_value = 0;
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());
}
{
v8::TryCatch try_catch(isolate);
info.expected_offset = 8;
info.expected_offset = initial_offset + offset_multiplier;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 0;
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());
......@@ -27630,13 +27627,13 @@ TEST(AtomicsWaitCallback) {
{
v8::TryCatch try_catch(isolate);
info.expected_offset = 8;
info.expected_offset = initial_offset + offset_multiplier;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 0;
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());
......@@ -27646,7 +27643,7 @@ TEST(AtomicsWaitCallback) {
{
// Same test as before, but with a different `expected_value`.
v8::TryCatch try_catch(isolate);
info.expected_offset = 8;
info.expected_offset = initial_offset + offset_multiplier;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 200;
info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
......@@ -27654,7 +27651,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());
......@@ -27664,13 +27661,15 @@ TEST(AtomicsWaitCallback) {
{
// Wake the `Atomics.wait()` call from a thread.
v8::TryCatch try_catch(isolate);
info.expected_offset = 4;
info.expected_offset = initial_offset;
info.expected_timeout = std::numeric_limits<double>::infinity();
info.expected_value = 0;
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 +27677,98 @@ 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), 4, 4);
}
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), 4, 4);
}
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)), 8));
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"(
// offset 12 below ensures that int32arr[1] and wait(1..) point to the
// same address.
let int32arr = new Int32Array(sab, 12);
let wait = function(id, val, timeout) {
if(arguments.length === 2)
return func(id << 3, val, -1);
return func(id << 3, val, timeout*1000000);
};
sab;)";
AtomicsWaitCallbackCommon(isolate, CompileRun(init), 8, 8);
}
} // namespace wasm
} // namespace internal
} // namespace v8
TEST(BigIntAPI) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
......
......@@ -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;
......
......@@ -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(); }
......
......@@ -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.
......
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