diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc index 7c9a01db7b..205e387941 100644 --- a/src/compiler/wasm-compiler.cc +++ b/src/compiler/wasm-compiler.cc @@ -3065,8 +3065,7 @@ Node* WasmGraphBuilder::CurrentMemoryPages() { Node* WasmGraphBuilder::BuildLoadBuiltinFromInstance(int builtin_index) { DCHECK(Builtins::IsBuiltinId(builtin_index)); - Node* isolate_root = - LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::TaggedPointer()); + Node* isolate_root = LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer()); return LOAD_TAGGED_POINTER(isolate_root, IsolateData::builtin_slot_offset(builtin_index)); } @@ -4540,14 +4539,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { void BuildModifyThreadInWasmFlag(bool new_value) { if (!trap_handler::IsTrapHandlerEnabled()) return; - Node* thread_in_wasm_flag_address_address = - graph()->NewNode(mcgraph()->common()->ExternalConstant( - ExternalReference::wasm_thread_in_wasm_flag_address_address( - isolate_))); - Node* thread_in_wasm_flag_address = SetEffect(graph()->NewNode( - mcgraph()->machine()->Load(LoadRepresentation(MachineType::Pointer())), - thread_in_wasm_flag_address_address, mcgraph()->Int32Constant(0), - Effect(), Control())); + Node* isolate_root = + LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer()); + + Node* thread_in_wasm_flag_address = + LOAD_RAW(isolate_root, Isolate::thread_in_wasm_flag_address_offset(), + MachineType::Pointer()); + SetEffect(graph()->NewNode( mcgraph()->machine()->Store(StoreRepresentation( MachineRepresentation::kWord32, kNoWriteBarrier)), diff --git a/src/external-reference.cc b/src/external-reference.cc index e13b204d8a..95ed54a952 100644 --- a/src/external-reference.cc +++ b/src/external-reference.cc @@ -826,12 +826,6 @@ ExternalReference ExternalReference::debug_restart_fp_address( return ExternalReference(isolate->debug()->restart_fp_address()); } -ExternalReference ExternalReference::wasm_thread_in_wasm_flag_address_address( - Isolate* isolate) { - return ExternalReference(reinterpret_cast
( - &isolate->thread_local_top()->thread_in_wasm_flag_address_)); -} - ExternalReference ExternalReference::fast_c_call_caller_fp_address( Isolate* isolate) { return ExternalReference( diff --git a/src/external-reference.h b/src/external-reference.h index 63ee1b19ad..2fef99c8b2 100644 --- a/src/external-reference.h +++ b/src/external-reference.h @@ -70,8 +70,6 @@ class StatsCounter; V(debug_suspended_generator_address, \ "Debug::step_suspended_generator_address()") \ V(debug_restart_fp_address, "Debug::restart_fp_address()") \ - V(wasm_thread_in_wasm_flag_address_address, \ - "&Isolate::thread_in_wasm_flag_address") \ V(fast_c_call_caller_fp_address, \ "IsolateData::fast_c_call_caller_fp_address") \ V(fast_c_call_caller_pc_address, \ diff --git a/src/isolate.h b/src/isolate.h index f4a64a6a9d..743ae03e54 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -1030,6 +1030,18 @@ class Isolate final : private HiddenFactory { deoptimizer_lazy_throw_ = value; } ThreadLocalTop* thread_local_top() { return &thread_local_top_; } + + static uint32_t thread_in_wasm_flag_address_offset() { + // For WebAssembly trap handlers there is a flag in thread-local storage + // which indicates that the executing thread executes WebAssembly code. To + // access this flag directly from generated code, we store a pointer to the + // flag in ThreadLocalTop in thread_in_wasm_flag_address_. This function + // here returns the offset of that member from {isolate_root()}. + return static_cast( + OFFSET_OF(Isolate, thread_local_top_.thread_in_wasm_flag_address_) - + isolate_root_bias()); + } + MaterializedObjectStore* materialized_object_store() { return materialized_object_store_; } diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc index 6cc3f9e4cf..c8432211e3 100644 --- a/src/runtime/runtime-test.cc +++ b/src/runtime/runtime-test.cc @@ -843,6 +843,12 @@ RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) { return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled()); } +RUNTIME_FUNCTION(Runtime_IsThreadInWasm) { + DisallowHeapAllocation no_gc; + DCHECK_EQ(0, args.length()); + return isolate->heap()->ToBoolean(trap_handler::IsThreadInWasm()); +} + RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index af4c143585..fc8820ec80 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -491,6 +491,7 @@ namespace internal { F(IsLiftoffFunction, 1, 1) \ F(IsWasmCode, 1, 1) \ F(IsWasmTrapHandlerEnabled, 0, 1) \ + F(IsThreadInWasm, 0, 1) \ F(NeverOptimizeFunction, 1, 1) \ F(NotifyContextDisposed, 0, 1) \ F(OptimizeFunctionOnNextCall, -1, 1) \ diff --git a/test/mjsunit/regress/wasm/regress-8533.js b/test/mjsunit/regress/wasm/regress-8533.js new file mode 100644 index 0000000000..5d782b747c --- /dev/null +++ b/test/mjsunit/regress/wasm/regress-8533.js @@ -0,0 +1,85 @@ +// Copyright 2018 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. + +// Flags: --wasm-shared-engine --no-wasm-disable-structured-cloning --allow-natives-syntax --experimental-wasm-threads + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + + +// In this test we start a worker which enters wasm and stays there in a loop. +// The main thread stays in JS and checks that its thread-in-wasm flag is not +// set. The main thread calls setTimeout after every check to give the worker a +// chance to be scheculed. +const sync_address = 12; +(function TestPostModule() { + let builder = new WasmModuleBuilder(); + let sig_index = builder.addType(kSig_v_v); + let import_id = builder.addImport('m', 'func', sig_index); + builder.addFunction('wait', kSig_v_v) + .addBody([ + // Calling the imported function sets the thread-in-wasm flag of the + // main thread. + kExprCallFunction, import_id, // -- + kExprLoop, kWasmStmt, // -- + kExprI32Const, sync_address, // -- + kExprI32LoadMem, 0, 0, // -- + kExprI32Eqz, + kExprBrIf, 0, // -- + kExprEnd, + ]) + .exportFunc(); + + builder.addFunction('signal', kSig_v_v) + .addBody([ + kExprI32Const, sync_address, // -- + kExprI32Const, 1, // -- + kExprI32StoreMem, 0, 0, // -- + ]) + .exportFunc(); + builder.addImportedMemory("m", "imported_mem", 0, 1, "shared"); + + let module = builder.toModule(); + let memory = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true}); + + let workerScript = ` + onmessage = function(msg) { + try { + let worker_instance = new WebAssembly.Instance(msg.module, + {m: {imported_mem: msg.memory, + func: _ => 5}}); + postMessage("start running"); + worker_instance.exports.wait(); + postMessage("finished"); + } catch(e) { + postMessage('ERROR: ' + e); + } + } + `; + + let worker = new Worker(workerScript, {type: 'string'}); + worker.postMessage({module: module, memory: memory}); + + let main_instance = new WebAssembly.Instance( + module, {m: {imported_mem: memory, func: _ => 7}}); + + let counter = 0; + function CheckThreadNotInWasm() { + // We check the thread-in-wasm flag many times and reschedule ourselves in + // between to increase the chance that we read the flag set by the worker. + assertFalse(%IsThreadInWasm()); + counter++; + if (counter < 100) { + setTimeout(CheckThreadNotInWasm, 0); + } else { + main_instance.exports.signal(sync_address); + assertEquals('finished', worker.getMessage()); + worker.terminate(); + } + } + + assertFalse(%IsThreadInWasm()); + assertEquals('start running', worker.getMessage()); + CheckThreadNotInWasm(); +})(); diff --git a/test/unittests/wasm/trap-handler-x64-unittest.cc b/test/unittests/wasm/trap-handler-x64-unittest.cc index f7f5d20c57..680c92fa4d 100644 --- a/test/unittests/wasm/trap-handler-x64-unittest.cc +++ b/test/unittests/wasm/trap-handler-x64-unittest.cc @@ -215,17 +215,15 @@ class TrapHandlerTest : public TestWithIsolate, void GenerateSetThreadInWasmFlagCode(MacroAssembler* masm) { masm->Move(scratch, - ExternalReference::wasm_thread_in_wasm_flag_address_address( - i_isolate())); - masm->movp(scratch, MemOperand(scratch, 0)); + i_isolate()->thread_local_top()->thread_in_wasm_flag_address_, + RelocInfo::NONE); masm->movl(MemOperand(scratch, 0), Immediate(1)); } void GenerateResetThreadInWasmFlagCode(MacroAssembler* masm) { masm->Move(scratch, - ExternalReference::wasm_thread_in_wasm_flag_address_address( - i_isolate())); - masm->movp(scratch, MemOperand(scratch, 0)); + i_isolate()->thread_local_top()->thread_in_wasm_flag_address_, + RelocInfo::NONE); masm->movl(MemOperand(scratch, 0), Immediate(0)); } @@ -240,13 +238,17 @@ class TrapHandlerTest : public TestWithIsolate, GeneratedCode::FromAddress(i_isolate(), reinterpret_cast
(buffer.start())) .Call(); + CHECK(!g_test_handler_executed); } // Execute the code in buffer. We expect a crash which we recover from in the // test handler. void ExecuteExpectCrash(Vector buffer, bool check_wasm_flag = true) { CHECK(!g_test_handler_executed); - ExecuteBuffer(buffer); + MakeAssemblerBufferExecutable(buffer.start(), buffer.size()); + GeneratedCode::FromAddress(i_isolate(), + reinterpret_cast
(buffer.start())) + .Call(); CHECK(g_test_handler_executed); g_test_handler_executed = false; if (check_wasm_flag) CHECK(!GetThreadInWasmFlag());