[wasm][interpreter] Remove threads support
The wasm interpreter was always single-threaded, and there are no plans to change this. Still, there was a concept of threads, but with the hard-coded constraint that there is always exactly one of them. In order to clean up the code, and as a preparation to remove more unneeded functionality before moving the interpreter over to the test directory, this CL removes the concept of threads and merges the {ThreadImpl} class into {WasmInterpreterInternals}. Drive-by: Remove the dead {GetFrameCount} method. R=ahaas@chromium.org Bug: v8:10389 Change-Id: If65cdd21b34ce8debf8ba0f24dbeacec15e0a1d7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2231354 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#68204}
This commit is contained in:
parent
b644fac5a9
commit
47e501e169
@ -191,13 +191,12 @@ class InterpreterHandle {
|
|||||||
DCHECK_EQ(sig->return_count(), return_values.size());
|
DCHECK_EQ(sig->return_count(), return_values.size());
|
||||||
|
|
||||||
WasmCodeRefScope code_ref_scope;
|
WasmCodeRefScope code_ref_scope;
|
||||||
WasmInterpreter::Thread* thread = interpreter_.GetThread(0);
|
interpreter_.InitFrame(&module()->functions[func_index],
|
||||||
thread->InitFrame(&module()->functions[func_index],
|
argument_values.begin());
|
||||||
argument_values.begin());
|
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
while (!finished) {
|
while (!finished) {
|
||||||
// TODO(clemensb): Add occasional StackChecks.
|
// TODO(clemensb): Add occasional StackChecks.
|
||||||
WasmInterpreter::State state = thread->Run();
|
WasmInterpreter::State state = interpreter_.Run();
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case WasmInterpreter::State::PAUSED:
|
case WasmInterpreter::State::PAUSED:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -207,16 +206,16 @@ class InterpreterHandle {
|
|||||||
break;
|
break;
|
||||||
case WasmInterpreter::State::TRAPPED: {
|
case WasmInterpreter::State::TRAPPED: {
|
||||||
MessageTemplate message_id =
|
MessageTemplate message_id =
|
||||||
WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
|
WasmOpcodes::TrapReasonToMessageId(interpreter_.GetTrapReason());
|
||||||
Handle<JSObject> exception =
|
Handle<JSObject> exception =
|
||||||
isolate_->factory()->NewWasmRuntimeError(message_id);
|
isolate_->factory()->NewWasmRuntimeError(message_id);
|
||||||
JSObject::AddProperty(isolate_, exception,
|
JSObject::AddProperty(isolate_, exception,
|
||||||
isolate_->factory()->wasm_uncatchable_symbol(),
|
isolate_->factory()->wasm_uncatchable_symbol(),
|
||||||
isolate_->factory()->true_value(), NONE);
|
isolate_->factory()->true_value(), NONE);
|
||||||
auto result = thread->RaiseException(isolate_, exception);
|
auto result = interpreter_.RaiseException(isolate_, exception);
|
||||||
if (result == WasmInterpreter::Thread::HANDLED) break;
|
if (result == WasmInterpreter::HANDLED) break;
|
||||||
// If no local handler was found, we fall-thru to {STOPPED}.
|
// If no local handler was found, we fall-thru to {STOPPED}.
|
||||||
DCHECK_EQ(WasmInterpreter::State::STOPPED, thread->state());
|
DCHECK_EQ(WasmInterpreter::State::STOPPED, interpreter_.state());
|
||||||
V8_FALLTHROUGH;
|
V8_FALLTHROUGH;
|
||||||
}
|
}
|
||||||
case WasmInterpreter::State::STOPPED:
|
case WasmInterpreter::State::STOPPED:
|
||||||
@ -239,7 +238,7 @@ class InterpreterHandle {
|
|||||||
#endif
|
#endif
|
||||||
DCHECK_GE(max_count, sig->return_count());
|
DCHECK_GE(max_count, sig->return_count());
|
||||||
for (unsigned i = 0; i < sig->return_count(); ++i) {
|
for (unsigned i = 0; i < sig->return_count(); ++i) {
|
||||||
return_values[i] = thread->GetReturnValue(i);
|
return_values[i] = interpreter_.GetReturnValue(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1102,9 +1102,20 @@ V8_INLINE bool has_nondeterminism<double>(double val) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Responsible for executing code directly.
|
//============================================================================
|
||||||
class ThreadImpl {
|
// The implementation details of the interpreter.
|
||||||
|
//============================================================================
|
||||||
|
class WasmInterpreterInternals {
|
||||||
public:
|
public:
|
||||||
|
WasmInterpreterInternals(Zone* zone, const WasmModule* module,
|
||||||
|
const ModuleWireBytes& wire_bytes,
|
||||||
|
Handle<WasmInstanceObject> instance_object)
|
||||||
|
: module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
|
||||||
|
codemap_(module, module_bytes_.data(), zone),
|
||||||
|
isolate_(instance_object->GetIsolate()),
|
||||||
|
instance_object_(instance_object),
|
||||||
|
frames_(zone) {}
|
||||||
|
|
||||||
// The {ReferenceStackScope} sets up the reference stack in the interpreter.
|
// The {ReferenceStackScope} sets up the reference stack in the interpreter.
|
||||||
// The handle to the reference stack has to be re-initialized everytime we
|
// The handle to the reference stack has to be re-initialized everytime we
|
||||||
// call into the interpreter because there is no HandleScope that could
|
// call into the interpreter because there is no HandleScope that could
|
||||||
@ -1113,7 +1124,7 @@ class ThreadImpl {
|
|||||||
// reference stack and thereby transitively keeps the interpreter alive.
|
// reference stack and thereby transitively keeps the interpreter alive.
|
||||||
class ReferenceStackScope {
|
class ReferenceStackScope {
|
||||||
public:
|
public:
|
||||||
explicit ReferenceStackScope(ThreadImpl* impl) : impl_(impl) {
|
explicit ReferenceStackScope(WasmInterpreterInternals* impl) : impl_(impl) {
|
||||||
// The reference stack is already initialized, we don't have to do
|
// The reference stack is already initialized, we don't have to do
|
||||||
// anything.
|
// anything.
|
||||||
if (!impl_->reference_stack_cell_.is_null()) return;
|
if (!impl_->reference_stack_cell_.is_null()) return;
|
||||||
@ -1131,26 +1142,16 @@ class ThreadImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThreadImpl* impl_;
|
WasmInterpreterInternals* impl_;
|
||||||
bool do_reset_stack_ = false;
|
bool do_reset_stack_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadImpl(Zone* zone, CodeMap* codemap,
|
|
||||||
Handle<WasmInstanceObject> instance_object)
|
|
||||||
: codemap_(codemap),
|
|
||||||
isolate_(instance_object->GetIsolate()),
|
|
||||||
instance_object_(instance_object),
|
|
||||||
frames_(zone) {}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
// Implementation of public interface for WasmInterpreter::Thread.
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
WasmInterpreter::State state() { return state_; }
|
WasmInterpreter::State state() { return state_; }
|
||||||
|
|
||||||
void InitFrame(const WasmFunction* function, WasmValue* args) {
|
void InitFrame(const WasmFunction* function, WasmValue* args) {
|
||||||
|
ReferenceStackScope stack_scope(this);
|
||||||
DCHECK(frames_.empty());
|
DCHECK(frames_.empty());
|
||||||
InterpreterCode* code = codemap()->GetCode(function);
|
InterpreterCode* code = codemap_.GetCode(function);
|
||||||
size_t num_params = function->sig->parameter_count();
|
size_t num_params = function->sig->parameter_count();
|
||||||
EnsureStackSpace(num_params);
|
EnsureStackSpace(num_params);
|
||||||
Push(args, num_params);
|
Push(args, num_params);
|
||||||
@ -1158,6 +1159,7 @@ class ThreadImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WasmInterpreter::State Run(int num_steps = -1) {
|
WasmInterpreter::State Run(int num_steps = -1) {
|
||||||
|
ReferenceStackScope stack_scope(this);
|
||||||
DCHECK(state_ == WasmInterpreter::STOPPED ||
|
DCHECK(state_ == WasmInterpreter::STOPPED ||
|
||||||
state_ == WasmInterpreter::PAUSED);
|
state_ == WasmInterpreter::PAUSED);
|
||||||
DCHECK(num_steps == -1 || num_steps > 0);
|
DCHECK(num_steps == -1 || num_steps > 0);
|
||||||
@ -1178,6 +1180,7 @@ class ThreadImpl {
|
|||||||
void Pause() { UNIMPLEMENTED(); }
|
void Pause() { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
|
ReferenceStackScope stack_scope(this);
|
||||||
TRACE("----- RESET -----\n");
|
TRACE("----- RESET -----\n");
|
||||||
ResetStack(0);
|
ResetStack(0);
|
||||||
frames_.clear();
|
frames_.clear();
|
||||||
@ -1186,12 +1189,8 @@ class ThreadImpl {
|
|||||||
possible_nondeterminism_ = false;
|
possible_nondeterminism_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetFrameCount() {
|
|
||||||
DCHECK_GE(kMaxInt, frames_.size());
|
|
||||||
return static_cast<int>(frames_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmValue GetReturnValue(uint32_t index) {
|
WasmValue GetReturnValue(uint32_t index) {
|
||||||
|
ReferenceStackScope stack_scope(this);
|
||||||
if (state_ == WasmInterpreter::TRAPPED) return WasmValue(0xDEADBEEF);
|
if (state_ == WasmInterpreter::TRAPPED) return WasmValue(0xDEADBEEF);
|
||||||
DCHECK_EQ(WasmInterpreter::FINISHED, state_);
|
DCHECK_EQ(WasmInterpreter::FINISHED, state_);
|
||||||
return GetStackValue(index);
|
return GetStackValue(index);
|
||||||
@ -1215,23 +1214,27 @@ class ThreadImpl {
|
|||||||
|
|
||||||
Handle<Cell> reference_stack_cell() const { return reference_stack_cell_; }
|
Handle<Cell> reference_stack_cell() const { return reference_stack_cell_; }
|
||||||
|
|
||||||
WasmInterpreter::Thread::ExceptionHandlingResult RaiseException(
|
WasmInterpreter::ExceptionHandlingResult RaiseException(
|
||||||
Isolate* isolate, Handle<Object> exception) {
|
Isolate* isolate, Handle<Object> exception) {
|
||||||
|
ReferenceStackScope stack_scope(this);
|
||||||
DCHECK_EQ(WasmInterpreter::TRAPPED, state_);
|
DCHECK_EQ(WasmInterpreter::TRAPPED, state_);
|
||||||
isolate->Throw(*exception); // Will check that none is pending.
|
isolate->Throw(*exception); // Will check that none is pending.
|
||||||
if (HandleException(isolate) == WasmInterpreter::Thread::UNWOUND) {
|
if (HandleException(isolate) == WasmInterpreter::UNWOUND) {
|
||||||
DCHECK_EQ(WasmInterpreter::STOPPED, state_);
|
DCHECK_EQ(WasmInterpreter::STOPPED, state_);
|
||||||
return WasmInterpreter::Thread::UNWOUND;
|
return WasmInterpreter::UNWOUND;
|
||||||
}
|
}
|
||||||
state_ = WasmInterpreter::PAUSED;
|
state_ = WasmInterpreter::PAUSED;
|
||||||
return WasmInterpreter::Thread::HANDLED;
|
return WasmInterpreter::HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeMap* codemap() { return &codemap_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class ReferenceStackScope;
|
||||||
|
|
||||||
// Handle a thrown exception. Returns whether the exception was handled inside
|
// Handle a thrown exception. Returns whether the exception was handled inside
|
||||||
// of wasm. Unwinds the interpreted stack accordingly.
|
// of wasm. Unwinds the interpreted stack accordingly.
|
||||||
WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
|
WasmInterpreter::ExceptionHandlingResult HandleException(Isolate* isolate) {
|
||||||
Isolate* isolate) {
|
|
||||||
DCHECK(isolate->has_pending_exception());
|
DCHECK(isolate->has_pending_exception());
|
||||||
bool catchable =
|
bool catchable =
|
||||||
isolate->is_catchable_by_wasm(isolate->pending_exception());
|
isolate->is_catchable_by_wasm(isolate->pending_exception());
|
||||||
@ -1245,7 +1248,7 @@ class ThreadImpl {
|
|||||||
frame.pc += JumpToHandlerDelta(code, frame.pc);
|
frame.pc += JumpToHandlerDelta(code, frame.pc);
|
||||||
TRACE(" => handler #%zu (#%u @%zu)\n", frames_.size() - 1,
|
TRACE(" => handler #%zu (#%u @%zu)\n", frames_.size() - 1,
|
||||||
code->function->func_index, frame.pc);
|
code->function->func_index, frame.pc);
|
||||||
return WasmInterpreter::Thread::HANDLED;
|
return WasmInterpreter::HANDLED;
|
||||||
}
|
}
|
||||||
TRACE(" => drop frame #%zu (#%u @%zu)\n", frames_.size() - 1,
|
TRACE(" => drop frame #%zu (#%u @%zu)\n", frames_.size() - 1,
|
||||||
code->function->func_index, frame.pc);
|
code->function->func_index, frame.pc);
|
||||||
@ -1256,7 +1259,7 @@ class ThreadImpl {
|
|||||||
DCHECK(frames_.empty());
|
DCHECK(frames_.empty());
|
||||||
DCHECK_EQ(sp_, stack_.get());
|
DCHECK_EQ(sp_, stack_.get());
|
||||||
state_ = WasmInterpreter::STOPPED;
|
state_ = WasmInterpreter::STOPPED;
|
||||||
return WasmInterpreter::Thread::UNWOUND;
|
return WasmInterpreter::UNWOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entries on the stack of functions being evaluated.
|
// Entries on the stack of functions being evaluated.
|
||||||
@ -1279,68 +1282,51 @@ class ThreadImpl {
|
|||||||
class StackValue {
|
class StackValue {
|
||||||
public:
|
public:
|
||||||
StackValue() = default; // Only needed for resizing the stack.
|
StackValue() = default; // Only needed for resizing the stack.
|
||||||
StackValue(WasmValue v, ThreadImpl* thread, sp_t index) : value_(v) {
|
StackValue(WasmValue v, WasmInterpreterInternals* impl, sp_t index)
|
||||||
|
: value_(v) {
|
||||||
if (IsReferenceValue()) {
|
if (IsReferenceValue()) {
|
||||||
value_ = WasmValue(Handle<Object>::null());
|
value_ = WasmValue(Handle<Object>::null());
|
||||||
int ref_index = static_cast<int>(index);
|
int ref_index = static_cast<int>(index);
|
||||||
thread->reference_stack().set(ref_index, *v.to_anyref());
|
impl->reference_stack().set(ref_index, *v.to_anyref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmValue ExtractValue(ThreadImpl* thread, sp_t index) {
|
WasmValue ExtractValue(WasmInterpreterInternals* impl, sp_t index) {
|
||||||
if (!IsReferenceValue()) return value_;
|
if (!IsReferenceValue()) return value_;
|
||||||
DCHECK(value_.to_anyref().is_null());
|
DCHECK(value_.to_anyref().is_null());
|
||||||
int ref_index = static_cast<int>(index);
|
int ref_index = static_cast<int>(index);
|
||||||
Isolate* isolate = thread->isolate_;
|
Isolate* isolate = impl->isolate_;
|
||||||
Handle<Object> ref(thread->reference_stack().get(ref_index), isolate);
|
Handle<Object> ref(impl->reference_stack().get(ref_index), isolate);
|
||||||
DCHECK(!ref->IsTheHole(isolate));
|
DCHECK(!ref->IsTheHole(isolate));
|
||||||
return WasmValue(ref);
|
return WasmValue(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsReferenceValue() const { return value_.type() == kWasmAnyRef; }
|
bool IsReferenceValue() const { return value_.type() == kWasmAnyRef; }
|
||||||
|
|
||||||
void ClearValue(ThreadImpl* thread, sp_t index) {
|
void ClearValue(WasmInterpreterInternals* impl, sp_t index) {
|
||||||
if (!IsReferenceValue()) return;
|
if (!IsReferenceValue()) return;
|
||||||
int ref_index = static_cast<int>(index);
|
int ref_index = static_cast<int>(index);
|
||||||
Isolate* isolate = thread->isolate_;
|
Isolate* isolate = impl->isolate_;
|
||||||
thread->reference_stack().set_the_hole(isolate, ref_index);
|
impl->reference_stack().set_the_hole(isolate, ref_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ClearValues(ThreadImpl* thread, sp_t index, int count) {
|
static void ClearValues(WasmInterpreterInternals* impl, sp_t index,
|
||||||
|
int count) {
|
||||||
int ref_index = static_cast<int>(index);
|
int ref_index = static_cast<int>(index);
|
||||||
thread->reference_stack().FillWithHoles(ref_index, ref_index + count);
|
impl->reference_stack().FillWithHoles(ref_index, ref_index + count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsClearedValue(ThreadImpl* thread, sp_t index) {
|
static bool IsClearedValue(WasmInterpreterInternals* impl, sp_t index) {
|
||||||
int ref_index = static_cast<int>(index);
|
int ref_index = static_cast<int>(index);
|
||||||
Isolate* isolate = thread->isolate_;
|
Isolate* isolate = impl->isolate_;
|
||||||
return thread->reference_stack().is_the_hole(isolate, ref_index);
|
return impl->reference_stack().is_the_hole(isolate, ref_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WasmValue value_;
|
WasmValue value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend class ReferenceStackScope;
|
const WasmModule* module() const { return codemap_.module(); }
|
||||||
|
|
||||||
CodeMap* codemap_;
|
|
||||||
Isolate* isolate_;
|
|
||||||
Handle<WasmInstanceObject> instance_object_;
|
|
||||||
std::unique_ptr<StackValue[]> stack_;
|
|
||||||
StackValue* stack_limit_ = nullptr; // End of allocated stack space.
|
|
||||||
StackValue* sp_ = nullptr; // Current stack pointer.
|
|
||||||
// The reference stack is pointed to by a {Cell} to be able to replace the
|
|
||||||
// underlying {FixedArray} when growing the stack. This avoids having to
|
|
||||||
// recreate or update the global handle keeping this object alive.
|
|
||||||
Handle<Cell> reference_stack_cell_; // References are on an on-heap stack.
|
|
||||||
ZoneVector<Frame> frames_;
|
|
||||||
WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
|
|
||||||
TrapReason trap_reason_ = kTrapCount;
|
|
||||||
bool possible_nondeterminism_ = false;
|
|
||||||
uint64_t num_interpreted_calls_ = 0;
|
|
||||||
|
|
||||||
CodeMap* codemap() const { return codemap_; }
|
|
||||||
const WasmModule* module() const { return codemap_->module(); }
|
|
||||||
FixedArray reference_stack() const {
|
FixedArray reference_stack() const {
|
||||||
return FixedArray::cast(reference_stack_cell_->value());
|
return FixedArray::cast(reference_stack_cell_->value());
|
||||||
}
|
}
|
||||||
@ -2770,7 +2756,7 @@ class ThreadImpl {
|
|||||||
// it to 0 here such that we report the same position as in compiled code.
|
// it to 0 here such that we report the same position as in compiled code.
|
||||||
frames_.back().pc = 0;
|
frames_.back().pc = 0;
|
||||||
isolate_->StackOverflow();
|
isolate_->StackOverflow();
|
||||||
return HandleException(isolate_) == WasmInterpreter::Thread::HANDLED;
|
return HandleException(isolate_) == WasmInterpreter::HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeI32ExceptionValue(Handle<FixedArray> encoded_values,
|
void EncodeI32ExceptionValue(Handle<FixedArray> encoded_values,
|
||||||
@ -2863,14 +2849,14 @@ class ThreadImpl {
|
|||||||
Drop(static_cast<int>(sig->parameter_count()));
|
Drop(static_cast<int>(sig->parameter_count()));
|
||||||
// Now that the exception is ready, set it as pending.
|
// Now that the exception is ready, set it as pending.
|
||||||
isolate_->Throw(*exception_object);
|
isolate_->Throw(*exception_object);
|
||||||
return HandleException(isolate_) == WasmInterpreter::Thread::HANDLED;
|
return HandleException(isolate_) == WasmInterpreter::HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw a given existing exception. Returns true if the exception is being
|
// Throw a given existing exception. Returns true if the exception is being
|
||||||
// handled locally by the interpreter, false otherwise (interpreter exits).
|
// handled locally by the interpreter, false otherwise (interpreter exits).
|
||||||
bool DoRethrowException(WasmValue exception) {
|
bool DoRethrowException(WasmValue exception) {
|
||||||
isolate_->ReThrow(*exception.to_anyref());
|
isolate_->ReThrow(*exception.to_anyref());
|
||||||
return HandleException(isolate_) == WasmInterpreter::Thread::HANDLED;
|
return HandleException(isolate_) == WasmInterpreter::HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines whether the given exception has a tag matching the expected tag
|
// Determines whether the given exception has a tag matching the expected tag
|
||||||
@ -3022,7 +3008,7 @@ class ThreadImpl {
|
|||||||
// Compute the stack effect of this opcode, and verify later that the
|
// Compute the stack effect of this opcode, and verify later that the
|
||||||
// stack was modified accordingly.
|
// stack was modified accordingly.
|
||||||
std::pair<uint32_t, uint32_t> stack_effect =
|
std::pair<uint32_t, uint32_t> stack_effect =
|
||||||
StackEffect(codemap_->module(), frames_.back().code->function->sig,
|
StackEffect(codemap_.module(), frames_.back().code->function->sig,
|
||||||
code->start + pc, code->end);
|
code->start + pc, code->end);
|
||||||
sp_t expected_new_stack_height =
|
sp_t expected_new_stack_height =
|
||||||
StackHeight() - stack_effect.first + stack_effect.second;
|
StackHeight() - stack_effect.first + stack_effect.second;
|
||||||
@ -3232,7 +3218,7 @@ class ThreadImpl {
|
|||||||
case kExprCallFunction: {
|
case kExprCallFunction: {
|
||||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||||
code->at(pc));
|
code->at(pc));
|
||||||
InterpreterCode* target = codemap()->GetCode(imm.index);
|
InterpreterCode* target = codemap_.GetCode(imm.index);
|
||||||
CHECK(!target->function->imported);
|
CHECK(!target->function->imported);
|
||||||
// Execute an internal call.
|
// Execute an internal call.
|
||||||
if (!DoCall(&decoder, target, &pc, &limit)) return;
|
if (!DoCall(&decoder, target, &pc, &limit)) return;
|
||||||
@ -3264,7 +3250,7 @@ class ThreadImpl {
|
|||||||
case kExprReturnCall: {
|
case kExprReturnCall: {
|
||||||
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
|
||||||
code->at(pc));
|
code->at(pc));
|
||||||
InterpreterCode* target = codemap()->GetCode(imm.index);
|
InterpreterCode* target = codemap_.GetCode(imm.index);
|
||||||
|
|
||||||
CHECK(!target->function->imported);
|
CHECK(!target->function->imported);
|
||||||
// Enter internal found function.
|
// Enter internal found function.
|
||||||
@ -3815,96 +3801,27 @@ class ThreadImpl {
|
|||||||
instance_object_.is_identical_to(object_ref));
|
instance_object_.is_identical_to(object_ref));
|
||||||
|
|
||||||
DCHECK_EQ(WasmCode::kFunction, code->kind());
|
DCHECK_EQ(WasmCode::kFunction, code->kind());
|
||||||
return {CallResult::INTERNAL, codemap()->GetCode(code->index())};
|
return {CallResult::INTERNAL, codemap_.GetCode(code->index())};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl.
|
|
||||||
// Thread* is the public interface, without knowledge of the object layout.
|
|
||||||
// This cast is potentially risky, but as long as we always cast it back before
|
|
||||||
// accessing any data, it should be fine. UBSan is not complaining.
|
|
||||||
WasmInterpreter::Thread* ToThread(ThreadImpl* impl) {
|
|
||||||
return reinterpret_cast<WasmInterpreter::Thread*>(impl);
|
|
||||||
}
|
|
||||||
ThreadImpl* ToImpl(WasmInterpreter::Thread* thread) {
|
|
||||||
return reinterpret_cast<ThreadImpl*>(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// Implementation of the pimpl idiom for WasmInterpreter::Thread.
|
|
||||||
// Instead of placing a pointer to the ThreadImpl inside of the Thread object,
|
|
||||||
// we just reinterpret_cast them. ThreadImpls are only allocated inside this
|
|
||||||
// translation unit anyway.
|
|
||||||
//============================================================================
|
|
||||||
WasmInterpreter::State WasmInterpreter::Thread::state() {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
return impl->state();
|
|
||||||
}
|
|
||||||
void WasmInterpreter::Thread::InitFrame(const WasmFunction* function,
|
|
||||||
WasmValue* args) {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
impl->InitFrame(function, args);
|
|
||||||
}
|
|
||||||
WasmInterpreter::State WasmInterpreter::Thread::Run(int num_steps) {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
return impl->Run(num_steps);
|
|
||||||
}
|
|
||||||
void WasmInterpreter::Thread::Pause() { return ToImpl(this)->Pause(); }
|
|
||||||
void WasmInterpreter::Thread::Reset() {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
return impl->Reset();
|
|
||||||
}
|
|
||||||
WasmInterpreter::Thread::ExceptionHandlingResult
|
|
||||||
WasmInterpreter::Thread::RaiseException(Isolate* isolate,
|
|
||||||
Handle<Object> exception) {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
return impl->RaiseException(isolate, exception);
|
|
||||||
}
|
|
||||||
int WasmInterpreter::Thread::GetFrameCount() {
|
|
||||||
return ToImpl(this)->GetFrameCount();
|
|
||||||
}
|
|
||||||
WasmValue WasmInterpreter::Thread::GetReturnValue(int index) {
|
|
||||||
ThreadImpl* impl = ToImpl(this);
|
|
||||||
ThreadImpl::ReferenceStackScope stack_scope(impl);
|
|
||||||
return impl->GetReturnValue(index);
|
|
||||||
}
|
|
||||||
TrapReason WasmInterpreter::Thread::GetTrapReason() {
|
|
||||||
return ToImpl(this)->GetTrapReason();
|
|
||||||
}
|
|
||||||
bool WasmInterpreter::Thread::PossibleNondeterminism() {
|
|
||||||
return ToImpl(this)->PossibleNondeterminism();
|
|
||||||
}
|
|
||||||
uint64_t WasmInterpreter::Thread::NumInterpretedCalls() {
|
|
||||||
return ToImpl(this)->NumInterpretedCalls();
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// The implementation details of the interpreter.
|
|
||||||
//============================================================================
|
|
||||||
class WasmInterpreterInternals {
|
|
||||||
public:
|
|
||||||
// Create a copy of the module bytes for the interpreter, since the passed
|
// Create a copy of the module bytes for the interpreter, since the passed
|
||||||
// pointer might be invalidated after constructing the interpreter.
|
// pointer might be invalidated after constructing the interpreter.
|
||||||
const ZoneVector<uint8_t> module_bytes_;
|
const ZoneVector<uint8_t> module_bytes_;
|
||||||
CodeMap codemap_;
|
CodeMap codemap_;
|
||||||
std::vector<ThreadImpl> threads_;
|
Isolate* isolate_;
|
||||||
|
Handle<WasmInstanceObject> instance_object_;
|
||||||
WasmInterpreterInternals(Zone* zone, const WasmModule* module,
|
std::unique_ptr<StackValue[]> stack_;
|
||||||
const ModuleWireBytes& wire_bytes,
|
StackValue* stack_limit_ = nullptr; // End of allocated stack space.
|
||||||
Handle<WasmInstanceObject> instance_object)
|
StackValue* sp_ = nullptr; // Current stack pointer.
|
||||||
: module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
|
// The reference stack is pointed to by a {Cell} to be able to replace the
|
||||||
codemap_(module, module_bytes_.data(), zone) {
|
// underlying {FixedArray} when growing the stack. This avoids having to
|
||||||
threads_.emplace_back(zone, &codemap_, instance_object);
|
// recreate or update the global handle keeping this object alive.
|
||||||
}
|
Handle<Cell> reference_stack_cell_; // References are on an on-heap stack.
|
||||||
|
ZoneVector<Frame> frames_;
|
||||||
|
WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
|
||||||
|
TrapReason trap_reason_ = kTrapCount;
|
||||||
|
bool possible_nondeterminism_ = false;
|
||||||
|
uint64_t num_interpreted_calls_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -3939,27 +3856,44 @@ WasmInterpreter::WasmInterpreter(Isolate* isolate, const WasmModule* module,
|
|||||||
// used in the {unique_ptr} in the header.
|
// used in the {unique_ptr} in the header.
|
||||||
WasmInterpreter::~WasmInterpreter() = default;
|
WasmInterpreter::~WasmInterpreter() = default;
|
||||||
|
|
||||||
void WasmInterpreter::Run() { internals_->threads_[0].Run(); }
|
WasmInterpreter::State WasmInterpreter::state() { return internals_->state(); }
|
||||||
|
|
||||||
void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); }
|
void WasmInterpreter::InitFrame(const WasmFunction* function, WasmValue* args) {
|
||||||
|
internals_->InitFrame(function, args);
|
||||||
int WasmInterpreter::GetThreadCount() {
|
|
||||||
return 1; // only one thread for now.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
|
WasmInterpreter::State WasmInterpreter::Run(int num_steps) {
|
||||||
CHECK_EQ(0, id); // only one thread for now.
|
return internals_->Run(num_steps);
|
||||||
return ToThread(&internals_->threads_[id]);
|
}
|
||||||
|
|
||||||
|
void WasmInterpreter::Pause() { internals_->Pause(); }
|
||||||
|
|
||||||
|
void WasmInterpreter::Reset() { internals_->Reset(); }
|
||||||
|
|
||||||
|
WasmValue WasmInterpreter::GetReturnValue(int index) {
|
||||||
|
return internals_->GetReturnValue(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
TrapReason WasmInterpreter::GetTrapReason() {
|
||||||
|
return internals_->GetTrapReason();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WasmInterpreter::PossibleNondeterminism() {
|
||||||
|
return internals_->PossibleNondeterminism();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t WasmInterpreter::NumInterpretedCalls() {
|
||||||
|
return internals_->NumInterpretedCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
|
void WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
|
||||||
internals_->codemap_.AddFunction(function, nullptr, nullptr);
|
internals_->codemap()->AddFunction(function, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
|
void WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
|
||||||
const byte* start,
|
const byte* start,
|
||||||
const byte* end) {
|
const byte* end) {
|
||||||
internals_->codemap_.SetFunctionCode(function, start, end);
|
internals_->codemap()->SetFunctionCode(function, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
|
ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
|
||||||
|
@ -44,7 +44,7 @@ using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;
|
|||||||
// An interpreter capable of executing WebAssembly.
|
// An interpreter capable of executing WebAssembly.
|
||||||
class V8_EXPORT_PRIVATE WasmInterpreter {
|
class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||||
public:
|
public:
|
||||||
// State machine for a Thread:
|
// State machine for the interpreter:
|
||||||
// +----------------------------------------------------------+
|
// +----------------------------------------------------------+
|
||||||
// | +--------Run()/Step()---------+ |
|
// | +--------Run()/Step()---------+ |
|
||||||
// V V | |
|
// V V | |
|
||||||
@ -56,49 +56,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
|||||||
// +----------- Finish -------------> FINISHED
|
// +----------- Finish -------------> FINISHED
|
||||||
enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
|
enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
|
||||||
|
|
||||||
// Tells a thread to pause after certain instructions.
|
enum ExceptionHandlingResult { HANDLED, UNWOUND };
|
||||||
enum BreakFlag : uint8_t {
|
|
||||||
None = 0,
|
|
||||||
AfterReturn = 1 << 0,
|
|
||||||
AfterCall = 1 << 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// Representation of a thread in the interpreter.
|
|
||||||
class V8_EXPORT_PRIVATE Thread {
|
|
||||||
public:
|
|
||||||
// Don't instante Threads; they will be allocated as ThreadImpl in the
|
|
||||||
// interpreter implementation.
|
|
||||||
Thread() = delete;
|
|
||||||
enum ExceptionHandlingResult { HANDLED, UNWOUND };
|
|
||||||
|
|
||||||
// Execution control.
|
|
||||||
State state();
|
|
||||||
void InitFrame(const WasmFunction* function, WasmValue* args);
|
|
||||||
// Pass -1 as num_steps to run till completion, pause or breakpoint.
|
|
||||||
State Run(int num_steps = -1);
|
|
||||||
State Step() { return Run(1); }
|
|
||||||
void Pause();
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
// Raise an exception in the current activation and unwind the stack
|
|
||||||
// accordingly. Return whether the exception was handled inside wasm:
|
|
||||||
// - HANDLED: Activation at handler position and in {PAUSED} state.
|
|
||||||
// - UNWOUND: Frames unwound, exception pending, and in {STOPPED} state.
|
|
||||||
ExceptionHandlingResult RaiseException(Isolate*, Handle<Object> exception);
|
|
||||||
|
|
||||||
// Stack inspection and modification.
|
|
||||||
int GetFrameCount();
|
|
||||||
WasmValue GetReturnValue(int index = 0);
|
|
||||||
TrapReason GetTrapReason();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
};
|
|
||||||
|
|
||||||
WasmInterpreter(Isolate* isolate, const WasmModule* module,
|
WasmInterpreter(Isolate* isolate, const WasmModule* module,
|
||||||
const ModuleWireBytes& wire_bytes,
|
const ModuleWireBytes& wire_bytes,
|
||||||
@ -109,14 +67,31 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
|||||||
//==========================================================================
|
//==========================================================================
|
||||||
// Execution controls.
|
// Execution controls.
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
void Run();
|
State state();
|
||||||
|
void InitFrame(const WasmFunction* function, WasmValue* args);
|
||||||
|
// Pass -1 as num_steps to run till completion, pause or breakpoint.
|
||||||
|
State Run(int num_steps = -1);
|
||||||
|
State Step() { return Run(1); }
|
||||||
void Pause();
|
void Pause();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
//==========================================================================
|
// Raise an exception in the current activation and unwind the stack
|
||||||
// Thread iteration and inspection.
|
// accordingly. Return whether the exception was handled inside wasm:
|
||||||
//==========================================================================
|
// - HANDLED: Activation at handler position and in {PAUSED} state.
|
||||||
int GetThreadCount();
|
// - UNWOUND: Frames unwound, exception pending, and in {STOPPED} state.
|
||||||
Thread* GetThread(int id);
|
ExceptionHandlingResult RaiseException(Isolate*, Handle<Object> exception);
|
||||||
|
|
||||||
|
// Stack inspection and modification.
|
||||||
|
WasmValue GetReturnValue(int index = 0);
|
||||||
|
TrapReason GetTrapReason();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
// Testing functionality.
|
// Testing functionality.
|
||||||
|
@ -282,28 +282,27 @@ TEST(Step_I32Mul) {
|
|||||||
r.Build(code, code + arraysize(code));
|
r.Build(code, code + arraysize(code));
|
||||||
|
|
||||||
WasmInterpreter* interpreter = r.interpreter();
|
WasmInterpreter* interpreter = r.interpreter();
|
||||||
WasmInterpreter::Thread* thread = interpreter->GetThread(0);
|
|
||||||
|
|
||||||
FOR_UINT32_INPUTS(a) {
|
FOR_UINT32_INPUTS(a) {
|
||||||
for (uint32_t b = 33; b < 3000000000u; b += 1000000000u) {
|
for (uint32_t b = 33; b < 3000000000u; b += 1000000000u) {
|
||||||
thread->Reset();
|
interpreter->Reset();
|
||||||
WasmValue args[] = {WasmValue(a), WasmValue(b)};
|
WasmValue args[] = {WasmValue(a), WasmValue(b)};
|
||||||
thread->InitFrame(r.function(), args);
|
interpreter->InitFrame(r.function(), args);
|
||||||
|
|
||||||
// Run instructions one by one.
|
// Run instructions one by one.
|
||||||
for (int i = 0; i < kTraceLength - 1; i++) {
|
for (int i = 0; i < kTraceLength - 1; i++) {
|
||||||
thread->Step();
|
interpreter->Step();
|
||||||
// Check the thread stopped.
|
// Check the interpreter stopped.
|
||||||
CHECK_EQ(WasmInterpreter::PAUSED, thread->state());
|
CHECK_EQ(WasmInterpreter::PAUSED, interpreter->state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run last instruction.
|
// Run last instruction.
|
||||||
thread->Step();
|
interpreter->Step();
|
||||||
|
|
||||||
// Check the thread finished with the right value.
|
// Check the interpreter finished with the right value.
|
||||||
CHECK_EQ(WasmInterpreter::FINISHED, thread->state());
|
CHECK_EQ(WasmInterpreter::FINISHED, interpreter->state());
|
||||||
uint32_t expected = (a) * (b);
|
uint32_t expected = (a) * (b);
|
||||||
CHECK_EQ(expected, thread->GetReturnValue().to<uint32_t>());
|
CHECK_EQ(expected, interpreter->GetReturnValue().to<uint32_t>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,17 +510,16 @@ class WasmRunner : public WasmRunnerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnType CallInterpreter(ParamTypes... p) {
|
ReturnType CallInterpreter(ParamTypes... p) {
|
||||||
WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
|
interpreter()->Reset();
|
||||||
thread->Reset();
|
|
||||||
std::array<WasmValue, sizeof...(p)> args{{WasmValue(p)...}};
|
std::array<WasmValue, sizeof...(p)> args{{WasmValue(p)...}};
|
||||||
thread->InitFrame(function(), args.data());
|
interpreter()->InitFrame(function(), args.data());
|
||||||
thread->Run();
|
interpreter()->Run();
|
||||||
CHECK_GT(thread->NumInterpretedCalls(), 0);
|
CHECK_GT(interpreter()->NumInterpretedCalls(), 0);
|
||||||
if (thread->state() == WasmInterpreter::FINISHED) {
|
if (interpreter()->state() == WasmInterpreter::FINISHED) {
|
||||||
WasmValue val = thread->GetReturnValue();
|
WasmValue val = interpreter()->GetReturnValue();
|
||||||
possible_nondeterminism_ |= thread->PossibleNondeterminism();
|
possible_nondeterminism_ |= interpreter()->PossibleNondeterminism();
|
||||||
return val.to<ReturnType>();
|
return val.to<ReturnType>();
|
||||||
} else if (thread->state() == WasmInterpreter::TRAPPED) {
|
} else if (interpreter()->state() == WasmInterpreter::TRAPPED) {
|
||||||
// TODO(titzer): return the correct trap code
|
// TODO(titzer): return the correct trap code
|
||||||
int64_t result = 0xDEADBEEFDEADBEEF;
|
int64_t result = 0xDEADBEEFDEADBEEF;
|
||||||
return static_cast<ReturnType>(result);
|
return static_cast<ReturnType>(result);
|
||||||
@ -559,7 +558,7 @@ class WasmRunner : public WasmRunnerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (builder_.interpret()) {
|
if (builder_.interpret()) {
|
||||||
CHECK_GT(builder_.interpreter()->GetThread(0)->NumInterpretedCalls(), 0);
|
CHECK_GT(builder_.interpreter()->NumInterpretedCalls(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +127,11 @@ bool InterpretWasmModuleForTesting(Isolate* isolate,
|
|||||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||||
|
|
||||||
WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
|
WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
|
||||||
WasmInterpreter::Thread* thread = interpreter->GetThread(0);
|
interpreter->Reset();
|
||||||
thread->Reset();
|
|
||||||
|
|
||||||
thread->InitFrame(&instance->module()->functions[function_index],
|
interpreter->InitFrame(&instance->module()->functions[function_index],
|
||||||
arguments.get());
|
arguments.get());
|
||||||
WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
|
WasmInterpreter::State interpreter_result = interpreter->Run(kMaxNumSteps);
|
||||||
|
|
||||||
if (isolate->has_pending_exception()) {
|
if (isolate->has_pending_exception()) {
|
||||||
// Stack overflow during interpretation.
|
// Stack overflow during interpretation.
|
||||||
@ -199,25 +198,25 @@ WasmInterpretationResult InterpretWasmModule(
|
|||||||
v8::internal::HandleScope scope(isolate);
|
v8::internal::HandleScope scope(isolate);
|
||||||
|
|
||||||
WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
|
WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
|
||||||
WasmInterpreter::Thread* thread = interpreter->GetThread(0);
|
interpreter->Reset();
|
||||||
thread->Reset();
|
|
||||||
|
|
||||||
thread->InitFrame(&(instance->module()->functions[function_index]), args);
|
interpreter->InitFrame(&instance->module()->functions[function_index], args);
|
||||||
WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
|
WasmInterpreter::State interpreter_result = interpreter->Run(kMaxNumSteps);
|
||||||
|
|
||||||
bool stack_overflow = isolate->has_pending_exception();
|
bool stack_overflow = isolate->has_pending_exception();
|
||||||
isolate->clear_pending_exception();
|
isolate->clear_pending_exception();
|
||||||
|
|
||||||
if (stack_overflow) return WasmInterpretationResult::Stopped();
|
if (stack_overflow) return WasmInterpretationResult::Stopped();
|
||||||
|
|
||||||
if (thread->state() == WasmInterpreter::TRAPPED) {
|
if (interpreter->state() == WasmInterpreter::TRAPPED) {
|
||||||
return WasmInterpretationResult::Trapped(thread->PossibleNondeterminism());
|
return WasmInterpretationResult::Trapped(
|
||||||
|
interpreter->PossibleNondeterminism());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interpreter_result == WasmInterpreter::FINISHED) {
|
if (interpreter_result == WasmInterpreter::FINISHED) {
|
||||||
return WasmInterpretationResult::Finished(
|
return WasmInterpretationResult::Finished(
|
||||||
thread->GetReturnValue().to<int32_t>(),
|
interpreter->GetReturnValue().to<int32_t>(),
|
||||||
thread->PossibleNondeterminism());
|
interpreter->PossibleNondeterminism());
|
||||||
}
|
}
|
||||||
|
|
||||||
return WasmInterpretationResult::Stopped();
|
return WasmInterpretationResult::Stopped();
|
||||||
|
Loading…
Reference in New Issue
Block a user