Commit 28620d19 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

Revert "Add capability of throwing values in WASM"

This reverts commit 7b5a4022.

Reason for revert: GC stress-test failures exposed by 7742e534
https://build.chromium.org/p/client.v8/builders/V8%20Linux64%20GC%20Stress%20-%20custom%20snapshot/builds/15110/steps/Mjsunit/logs/exceptions


Original change's description:
> Add capability of throwing values in WASM
> 
> Extends the current implementation of WASM exceptions to be able to
> throw exceptions with values (not just tags).
> 
> An JS typed array (uint_16) is used to hold thrown values, so that the
> thrown values can be inspected in JS.
> 
> Bug: v8:6577
> Change-Id: I1007e79ceaffd64386b62562919cfbb920fc10c5
> Reviewed-on: https://chromium-review.googlesource.com/633866
> Commit-Queue: Karl Schimpf <kschimpf@chromium.org>
> Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
> Reviewed-by: Eric Holk <eholk@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#48001}

TBR=bbudge@chromium.org,mtrofin@chromium.org,eholk@chromium.org,clemensh@chromium.org,kschimpf@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: v8:6577
Change-Id: I8f545183c2d2abb1bf4a0b3ee23379f3754ffd55
Reviewed-on: https://chromium-review.googlesource.com/667019Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarMircea Trofin <mtrofin@chromium.org>
Commit-Queue: Bill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48050}
parent 483e353d
......@@ -55,8 +55,6 @@ namespace compiler {
namespace {
constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2;
void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
Graph* g = jsgraph->graph();
if (g->end()) {
......@@ -1810,97 +1808,11 @@ Node* WasmGraphBuilder::GrowMemory(Node* input) {
return result;
}
uint32_t WasmGraphBuilder::GetExceptionEncodedSize(
const wasm::WasmException* exception) const {
const wasm::WasmExceptionSig* sig = exception->sig;
uint32_t encoded_size = 0;
for (size_t i = 0; i < sig->parameter_count(); ++i) {
size_t byte_size = size_t(1) << ElementSizeLog2Of(sig->GetParam(i));
DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0);
DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement);
encoded_size += byte_size / kBytesPerExceptionValuesArrayElement;
}
return encoded_size;
}
Node* WasmGraphBuilder::Throw(uint32_t tag,
const wasm::WasmException* exception,
const Vector<Node*> values) {
Node* WasmGraphBuilder::Throw(Node* input) {
SetNeedsStackCheck();
uint32_t encoded_size = GetExceptionEncodedSize(exception);
Node* create_parameters[] = {
BuildChangeUint32ToSmi(ConvertExceptionTagToRuntimeId(tag)),
BuildChangeUint32ToSmi(Uint32Constant(encoded_size))};
Node* except =
BuildCallToRuntime(Runtime::kWasmThrowCreate, create_parameters,
arraysize(create_parameters));
uint32_t index = 0;
const wasm::WasmExceptionSig* sig = exception->sig;
MachineOperatorBuilder* m = jsgraph()->machine();
for (size_t i = 0; i < sig->parameter_count(); ++i) {
Node* value = values[i];
switch (sig->GetParam(i)) {
case wasm::kWasmF32:
value = graph()->NewNode(m->BitcastFloat32ToInt32(), value);
// Intentionally fall to next case.
case wasm::kWasmI32:
except = BuildEncodeException32BitValue(except, &index, value);
break;
case wasm::kWasmF64:
value = graph()->NewNode(m->BitcastFloat64ToInt64(), value);
// Intentionally fall to next case.
case wasm::kWasmI64: {
Node* upper32 = graph()->NewNode(
m->TruncateInt64ToInt32(),
Binop(wasm::kExprI64ShrU, value, Int64Constant(32)));
except = BuildEncodeException32BitValue(except, &index, upper32);
Node* lower32 = graph()->NewNode(m->TruncateInt64ToInt32(), value);
except = BuildEncodeException32BitValue(except, &index, lower32);
break;
}
default:
CHECK(false);
break;
}
}
DCHECK_EQ(encoded_size, index);
Node* throw_parameters[] = {except};
return BuildCallToRuntime(Runtime::kWasmThrow, throw_parameters,
arraysize(throw_parameters));
}
Node* WasmGraphBuilder::BuildEncodeException32BitValue(Node* except,
uint32_t* index,
Node* value) {
MachineOperatorBuilder* machine = jsgraph()->machine();
Node* upper_parameters[] = {
except, BuildChangeUint32ToSmi(Int32Constant(*index)),
BuildChangeUint32ToSmi(
graph()->NewNode(machine->Word32Shr(), value, Int32Constant(16))),
};
(*index)++;
except = BuildCallToRuntime(Runtime::kWasmExceptionSetElement,
upper_parameters, arraysize(upper_parameters));
Node* lower_parameters[] = {
except, BuildChangeUint32ToSmi(Int32Constant(*index)),
BuildChangeUint32ToSmi(graph()->NewNode(machine->Word32And(), value,
Int32Constant(0xFFFFu))),
};
(*index)++;
return BuildCallToRuntime(Runtime::kWasmExceptionSetElement, lower_parameters,
arraysize(lower_parameters));
}
Node* WasmGraphBuilder::BuildDecodeException32BitValue(Node* const* values,
uint32_t* index) {
MachineOperatorBuilder* machine = jsgraph()->machine();
Node* upper = BuildChangeSmiToInt32(values[*index]);
(*index)++;
upper = graph()->NewNode(machine->Word32Shl(), upper, Int32Constant(16));
Node* lower = BuildChangeSmiToInt32(values[*index]);
(*index)++;
Node* value = graph()->NewNode(machine->Word32Or(), upper, lower);
return value;
Node* parameters[] = {BuildChangeInt32ToSmi(input)};
return BuildCallToRuntime(Runtime::kWasmThrow, parameters,
arraysize(parameters));
}
Node* WasmGraphBuilder::Rethrow() {
......@@ -1909,80 +1821,15 @@ Node* WasmGraphBuilder::Rethrow() {
return result;
}
Node* WasmGraphBuilder::Catch(Node* input) {
Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) {
SetNeedsStackCheck();
Node* parameters[] = {input};
return BuildCallToRuntime(Runtime::kWasmSetCaughtExceptionValue, parameters,
arraysize(parameters));
}
Node* WasmGraphBuilder::ConvertExceptionTagToRuntimeId(uint32_t tag) {
// TODO(kschimpf): Handle exceptions from different modules, when they are
// linked at runtime.
return Uint32Constant(tag);
}
Node* WasmGraphBuilder::GetExceptionRuntimeId(Node* exception) {
SetNeedsStackCheck();
Node* parameters[] = {exception};
return BuildChangeSmiToInt32(BuildCallToRuntime(
Runtime::kWasmGetExceptionRuntimeId, parameters, arraysize(parameters)));
}
Node** WasmGraphBuilder::GetExceptionValues(
const wasm::WasmException* except_decl, Node* exception,
wasm::WasmCodePosition position) {
// TODO(kschimpf): We need to move this code to the function-body-decoder.cc
// in order to build landing-pad (exception) edges in case the runtime
// call causes an exception.
// Start by getting the encoded values from the exception.
Node* parameters[] = {exception};
Node* enc_values = BuildCallToRuntime(Runtime::kWasmGetExceptionValuesArray,
parameters, arraysize(parameters));
uint32_t encoded_size = GetExceptionEncodedSize(except_decl);
Node** values = Buffer(encoded_size);
for (uint32_t i = 0; i < encoded_size; ++i) {
Node* parameters[] = {enc_values,
BuildChangeUint32ToSmi(Uint32Constant(i))};
values[i] = BuildCallToRuntime(Runtime::kWasmExceptionGetElement,
Node* parameters[] = {input}; // caught value
Node* value = BuildCallToRuntime(Runtime::kWasmSetCaughtExceptionValue,
parameters, arraysize(parameters));
}
// Now convert the leading entries to the corresponding parameter values.
uint32_t index = 0;
const wasm::WasmExceptionSig* sig = except_decl->sig;
for (size_t i = 0; i < sig->parameter_count(); ++i) {
Node* value = BuildDecodeException32BitValue(values, &index);
switch (wasm::ValueType type = sig->GetParam(i)) {
case wasm::kWasmF32: {
value = Unop(wasm::kExprF32ReinterpretI32, value);
break;
}
case wasm::kWasmI32:
break;
case wasm::kWasmF64:
case wasm::kWasmI64: {
Node* upper = Binop(wasm::kExprI64Shl,
Unop(wasm::kExprI64UConvertI32, value, position),
Int64Constant(32), position);
Node* lower =
Unop(wasm::kExprI64UConvertI32,
BuildDecodeException32BitValue(values, &index), position);
value = Binop(wasm::kExprI64Ior, upper, lower);
if (type == wasm::kWasmF64) {
value = Unop(wasm::kExprF64ReinterpretI64, value);
}
break;
}
default:
CHECK(false);
break;
}
values[i] = value;
}
DCHECK_EQ(index, encoded_size);
return values;
parameters[0] = value;
value = BuildCallToRuntime(Runtime::kWasmGetExceptionTag, parameters,
arraysize(parameters));
return BuildChangeSmiToInt32(value);
}
Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
......@@ -3256,7 +3103,7 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f,
inputs[count++] = jsgraph()->ExternalConstant(
ExternalReference(f, jsgraph()->isolate())); // ref
inputs[count++] = jsgraph()->Int32Constant(fun->nargs); // arity
inputs[count++] = context;
inputs[count++] = context; // context
inputs[count++] = *effect_;
inputs[count++] = *control_;
......
......@@ -212,15 +212,9 @@ class WasmGraphBuilder {
Node* Unop(wasm::WasmOpcode opcode, Node* input,
wasm::WasmCodePosition position = wasm::kNoCodePosition);
Node* GrowMemory(Node* input);
Node* Throw(uint32_t tag, const wasm::WasmException* exception,
const Vector<Node*> values);
Node* Throw(Node* input);
Node* Rethrow();
Node* Catch(Node* input);
Node* ConvertExceptionTagToRuntimeId(uint32_t tag);
Node* GetExceptionRuntimeId(Node* exception);
Node** GetExceptionValues(
const wasm::WasmException* except_decl, Node* exception,
wasm::WasmCodePosition position = wasm::kNoCodePosition);
Node* Catch(Node* input, wasm::WasmCodePosition position);
unsigned InputCount(Node* node);
bool IsPhiWithMerge(Node* phi, Node* merge);
bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
......@@ -475,11 +469,6 @@ class WasmGraphBuilder {
Node* BuildAsmjsLoadMem(MachineType type, Node* index);
Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val);
uint32_t GetExceptionEncodedSize(const wasm::WasmException* exception) const;
Node* BuildEncodeException32BitValue(Node* except, uint32_t* index,
Node* value);
Node* BuildDecodeException32BitValue(Node* const* values, uint32_t* index);
Node** Realloc(Node** buffer, size_t old_count, size_t new_count) {
Node** buf = Buffer(new_count);
if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
......
......@@ -202,7 +202,8 @@
V(will_handle_string, "willHandle") \
V(writable_string, "writable") \
V(year_string, "year") \
V(zero_string, "0")
V(zero_string, "0") \
V(WasmExceptionTag_string, "WasmExceptionTag")
#define PRIVATE_SYMBOL_LIST(V) \
V(array_iteration_kind_symbol) \
......
......@@ -92,9 +92,8 @@ bool Isolate::is_catchable_by_wasm(Object* exception) {
return false;
HandleScope scope(this);
Handle<Object> exception_handle(exception, this);
return JSReceiver::HasProperty(
Handle<JSReceiver>::cast(exception_handle),
factory()->InternalizeUtf8String("WasmExceptionRuntimeId"))
return JSReceiver::HasProperty(Handle<JSReceiver>::cast(exception_handle),
factory()->WasmExceptionTag_string())
.IsJust();
}
......
......@@ -26,9 +26,6 @@ namespace {
constexpr int kInvalidExceptionTag = -1;
constexpr const char* WasmExceptionRuntimeIdStr = "WasmExceptionRuntimeId";
constexpr const char* WasmExceptionValuesStr = "WasmExceptionValues";
WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
DisallowHeapAllocation no_allocation;
const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
......@@ -147,134 +144,55 @@ RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
}
RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
RUNTIME_FUNCTION(Runtime_WasmThrow) {
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(2, args.length());
Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
DCHECK_EQ(1, args.length());
Handle<Object> tag = args.at(0);
Handle<Object> except = isolate->factory()->NewWasmRuntimeError(
static_cast<MessageTemplate::Template>(
MessageTemplate::kWasmExceptionError));
CONVERT_ARG_HANDLE_CHECKED(Smi, id, 0);
CHECK(!JSReceiver::SetProperty(exception,
isolate->factory()->InternalizeUtf8String(
WasmExceptionRuntimeIdStr),
id, STRICT)
.is_null());
CONVERT_SMI_ARG_CHECKED(size, 1);
Handle<JSTypedArray> values =
isolate->factory()->NewJSTypedArray(ElementsKind::UINT16_ELEMENTS, size);
DCHECK(tag->IsSmi());
CHECK(!JSReceiver::SetProperty(
exception,
isolate->factory()->InternalizeUtf8String(WasmExceptionValuesStr),
values, STRICT)
except, isolate->factory()->WasmExceptionTag_string(), tag, STRICT)
.is_null());
return *exception;
}
RUNTIME_FUNCTION(Runtime_WasmThrow) {
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception, 0);
return isolate->Throw(*exception);
return isolate->Throw(*except);
}
RUNTIME_FUNCTION(Runtime_WasmRethrow) {
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(0, args.length());
Handle<Object> exception(isolate->get_wasm_caught_exception(), isolate);
Object* exception = isolate->get_wasm_caught_exception();
isolate->clear_wasm_caught_exception();
return isolate->Throw(*exception);
return isolate->Throw(exception);
}
RUNTIME_FUNCTION(Runtime_WasmGetExceptionRuntimeId) {
RUNTIME_FUNCTION(Runtime_WasmGetExceptionTag) {
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception, 0);
DCHECK(isolate->is_catchable_by_wasm(*exception));
Handle<Object> tag;
if (JSReceiver::GetProperty(
exception,
isolate->factory()->InternalizeUtf8String(WasmExceptionRuntimeIdStr))
.ToHandle(&tag)) {
if (tag->IsSmi()) {
return *tag;
}
Object* exception = args[0];
DCHECK(isolate->is_catchable_by_wasm(exception));
Handle<Object> exception_handle(exception, isolate);
Handle<Object> tag_handle;
if (JSReceiver::GetProperty(Handle<JSReceiver>::cast(exception_handle),
isolate->factory()->WasmExceptionTag_string())
.ToHandle(&tag_handle)) {
if (tag_handle->IsSmi()) return *tag_handle;
}
return Smi::FromInt(kInvalidExceptionTag);
}
RUNTIME_FUNCTION(Runtime_WasmGetExceptionValuesArray) {
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception, 0);
Handle<Object> values;
if (JSReceiver::GetProperty(
exception,
isolate->factory()->InternalizeUtf8String(WasmExceptionValuesStr))
.ToHandle(&values)) {
return *values;
}
return *isolate->factory()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmExceptionGetElement) {
// TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(JSTypedArray, values, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CHECK_LT(index, Smi::ToInt(values->length()));
CHECK_EQ(values->type(), kExternalUint16Array);
auto* vals =
reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
return Smi::FromInt(vals[index]);
}
RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
// TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_SMI_ARG_CHECKED(value, 2);
Handle<Object> values_obj;
CHECK(JSReceiver::GetProperty(
exception,
isolate->factory()->InternalizeUtf8String(WasmExceptionValuesStr))
.ToHandle(&values_obj));
Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
CHECK_LT(index, Smi::ToInt(values->length()));
CHECK_EQ(values->type(), kExternalUint16Array);
auto* vals =
reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
vals[index] = static_cast<uint16_t>(value);
return *exception;
}
RUNTIME_FUNCTION(Runtime_WasmSetCaughtExceptionValue) {
// TODO(kschimpf): Implement stack of caught exceptions, rather than
// just innermost.
HandleScope scope(isolate);
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, exception, 0);
DCHECK(isolate->is_catchable_by_wasm(*exception));
isolate->set_wasm_caught_exception(*exception);
return *exception;
Object* exception = args[0];
DCHECK(isolate->is_catchable_by_wasm(exception));
isolate->set_wasm_caught_exception(exception);
return exception;
}
RUNTIME_FUNCTION(Runtime_SetThreadInWasm) {
......
......@@ -643,14 +643,10 @@ namespace internal {
F(ThrowWasmErrorFromTrapIf, 1, 1) \
F(ThrowWasmStackOverflow, 0, 1) \
F(WasmThrowTypeError, 0, 1) \
F(WasmThrowCreate, 2, 1) \
F(WasmThrow, 1, 1) \
F(WasmRethrow, 0, 1) \
F(WasmGetExceptionRuntimeId, 1, 1) \
F(WasmGetExceptionValuesArray, 1, 1) \
F(WasmGetExceptionTag, 1, 1) \
F(WasmSetCaughtExceptionValue, 1, 1) \
F(WasmExceptionSetElement, 3, 1) \
F(WasmExceptionGetElement, 2, 1) \
F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1) \
F(SetThreadInWasm, 0, 1) \
......
......@@ -539,11 +539,8 @@ struct ControlWithNamedConstructors : public ControlBase<Value> {
const Value& input, Value* result) \
F(Simd8x16ShuffleOp, const Simd8x16ShuffleOperand<validate>& operand, \
const Value& input0, const Value& input1, Value* result) \
F(Throw, const ExceptionIndexOperand<validate>&, Control* block, \
const Vector<Value>& args) \
F(CatchException, const ExceptionIndexOperand<validate>& operand, \
Control* block) \
F(SetCaughtValue, Value* value, size_t index) \
F(Throw, const ExceptionIndexOperand<validate>&) \
F(Catch, const ExceptionIndexOperand<validate>& operand, Control* block) \
F(AtomicOp, WasmOpcode opcode, Vector<Value> args, Value* result)
// Generic Wasm bytecode decoder with utilities for decoding operands,
......@@ -1224,9 +1221,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ExceptionIndexOperand<true> operand(this, this->pc_);
len = 1 + operand.length;
if (!this->Validate(this->pc_, operand)) break;
std::vector<Value> args;
PopArgs(operand.exception->ToFunctionSig(), &args);
interface_.Throw(this, operand, &control_.back(), vec2vec(args));
if (operand.exception->sig->parameter_count() > 0) {
// TODO(kschimpf): Fix to pull values off stack and build throw.
OPCODE_ERROR(opcode, "can't handle exceptions with values yet");
break;
}
interface_.Throw(this, operand);
// TODO(titzer): Throw should end control, but currently we build a
// (reachable) runtime call instead of connecting it directly to
// end.
// EndControl();
break;
}
case kExprTry: {
......@@ -1264,12 +1268,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
c->kind = kControlTryCatch;
FallThruTo(c);
stack_.resize(c->stack_depth);
interface_.CatchException(this, operand, c);
const WasmExceptionSig* sig = operand.exception->sig;
for (size_t i = 0, e = sig->parameter_count(); i < e; ++i) {
auto* value = Push(sig->GetParam(i));
interface_.SetCaughtValue(this, value, i);
}
interface_.Catch(this, operand, c);
break;
}
case kExprCatchAll: {
......
......@@ -27,11 +27,6 @@ namespace wasm {
namespace {
template <typename T>
Vector<T> vec2vec(ZoneVector<T>& vec) {
return Vector<T>(vec.data(), vec.size());
}
// An SsaEnv environment carries the current local variable renaming
// as well as the current effect and control dependency in the TF graph.
// It maintains a control state that tracks whether the environment
......@@ -145,11 +140,8 @@ class WasmGraphBuildingInterface {
void Try(Decoder* decoder, Control* block) {
SsaEnv* outer_env = ssa_env_;
SsaEnv* catch_env = Split(decoder, outer_env);
// Mark catch environment as unreachable, since only accessable
// through catch unwinding (i.e. landing pads).
catch_env->state = SsaEnv::kUnreachable;
SsaEnv* try_env = Steal(decoder->zone(), outer_env);
SsaEnv* catch_env = UnreachableEnv(decoder->zone());
SetEnv(try_env);
TryInfo* try_info = new (decoder->zone()) TryInfo(catch_env);
block->end_env = outer_env;
......@@ -377,92 +369,40 @@ class WasmGraphBuildingInterface {
return BUILD(Int32Constant, operand.index);
}
void Throw(Decoder* decoder, const ExceptionIndexOperand<true>& operand,
Control* block, const Vector<Value>& value_args) {
int count = value_args.length();
ZoneVector<TFNode*> args(count, decoder->zone());
for (int i = 0; i < count; ++i) {
args[i] = value_args[i].node;
}
BUILD(Throw, operand.index, operand.exception, vec2vec(args));
Unreachable(decoder);
EndControl(decoder, block);
void Throw(Decoder* decoder, const ExceptionIndexOperand<true>& operand) {
BUILD(Throw, GetExceptionTag(decoder, operand));
}
void CatchException(Decoder* decoder,
const ExceptionIndexOperand<true>& operand,
Control* block) {
void Catch(Decoder* decoder, const ExceptionIndexOperand<true>& operand,
Control* block) {
DCHECK(block->is_try_catch());
current_catch_ = block->previous_catch;
SsaEnv* catch_env = block->try_info->catch_env;
SetEnv(catch_env);
TFNode* exception = nullptr;
TFNode* compare_i32 = nullptr;
if (block->try_info->exception == nullptr) {
// Catch not applicable, no possible throws in the try
// block. Create dummy code so that body of catch still
// compiles. Note: This only happens because the current
// implementation only builds a landing pad if some node in the
// try block can (possibly) throw.
//
// TODO(kschimpf): Always generate a landing pad for a try block.
compare_i32 = exception = BUILD(Int32Constant, 0);
caught_values_ = nullptr;
} else {
// Get the exception and see if wanted exception.
exception = BUILD(Catch, block->try_info->exception);
TFNode* caught_tag = BUILD(GetExceptionRuntimeId, exception);
TFNode* exception_tag =
BUILD(ConvertExceptionTagToRuntimeId, operand.index);
compare_i32 = BUILD(Binop, kExprI32Eq, caught_tag, exception_tag);
// TODO(kschimpf): Can't use BUILD() here, GetExceptionValues() returns
// TFNode** rather than TFNode*. Fix to add landing pads.
caught_values_ =
builder_->GetExceptionValues(operand.exception, exception);
}
TFNode* if_catch = nullptr;
TFNode* if_no_catch = nullptr;
BUILD(BranchNoHint, compare_i32, &if_catch, &if_no_catch);
SsaEnv* if_no_catch_env = Split(decoder, ssa_env_);
if_no_catch_env->control = if_no_catch;
SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_);
if_catch_env->control = if_catch;
// Get the exception and see if wanted exception.
TFNode* exception_as_i32 =
BUILD(Catch, block->try_info->exception, decoder->position());
TFNode* exception_tag = GetExceptionTag(decoder, operand);
TFNode* compare_i32 = BUILD(Binop, kExprI32Eq, exception_as_i32,
exception_tag, decoder->position());
TFNode* if_true = nullptr;
TFNode* if_false = nullptr;
BUILD(BranchNoHint, compare_i32, &if_true, &if_false);
SsaEnv* false_env = Split(decoder, catch_env);
false_env->control = if_false;
SsaEnv* true_env = Steal(decoder->zone(), catch_env);
true_env->control = if_true;
block->try_info->catch_env = false_env;
// TODO(kschimpf): Generalize to allow more catches. Will force
// moving no_catch code to END opcode.
SetEnv(if_no_catch_env);
// Generate code to re-throw the exception.
DCHECK_NOT_NULL(block->try_info->catch_env);
SetEnv(false_env);
BUILD(Rethrow);
Unreachable(decoder);
EndControl(decoder, block);
SetEnv(if_catch_env);
}
FallThruTo(decoder, block);
void SetCaughtValue(Decoder* decoder, Value* value, size_t index) {
if (caught_values_) {
value->node = caught_values_[index];
return;
}
// No caught value, make up filler node so that catch block still compiles.
switch (value->type) {
case kWasmI32:
I32Const(decoder, value, 0);
break;
case kWasmI64:
I64Const(decoder, value, 0);
break;
case kWasmF32:
F32Const(decoder, value, 0.0);
break;
case kWasmF64:
F64Const(decoder, value, 0.0);
break;
default:
CHECK(false); // Should not happen.
}
SetEnv(true_env);
// TODO(kschimpf): Add code to pop caught exception from isolate.
}
void AtomicOp(Decoder* decoder, WasmOpcode opcode, Vector<Value> args,
......@@ -476,7 +416,6 @@ class WasmGraphBuildingInterface {
SsaEnv* ssa_env_;
TFBuilder* builder_;
uint32_t current_catch_ = kNullCatch;
TFNode** caught_values_ = nullptr;
bool build(Decoder* decoder) { return ssa_env_->go() && decoder->ok(); }
......
......@@ -89,7 +89,6 @@ typedef FunctionSig WasmExceptionSig;
struct WasmException {
explicit WasmException(const WasmExceptionSig* sig = &empty_sig_)
: sig(sig) {}
FunctionSig* ToFunctionSig() const { return const_cast<FunctionSig*>(sig); }
const WasmExceptionSig* sig; // type signature of the exception.
......
......@@ -21,10 +21,8 @@ class FlagScope {
T previous_value_;
};
#define FLAG_SCOPE(flag) \
FlagScope<bool> __scope_##flag##__LINE__(&FLAG_##flag, true)
#define EXPERIMENTAL_FLAG_SCOPE(flag) FLAG_SCOPE(experimental_wasm_##flag)
#define EXPERIMENTAL_FLAG_SCOPE(flag) \
FlagScope<bool> __scope_##__LINE__(&FLAG_experimental_wasm_##flag, true)
} // namespace internal
} // namespace v8
......
This diff is collapsed.
......@@ -124,10 +124,6 @@ let kSig_v_d = makeSig([kWasmF64], []);
let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []);
let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
let kSig_v_f = makeSig([kWasmF32], []);
let kSig_f_f = makeSig([kWasmF32], [kWasmF32]);
let kSig_d_d = makeSig([kWasmF64], [kWasmF64]);
function makeSig(params, results) {
return {params: params, results: results};
}
......@@ -392,7 +388,7 @@ function assertTraps(trap, code) {
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
}
function assertWasmThrows(runtime_id, values, code) {
function assertWasmThrows(values, code) {
try {
if (typeof code === 'function') {
code();
......@@ -401,16 +397,13 @@ function assertWasmThrows(runtime_id, values, code) {
}
} catch (e) {
assertTrue(e instanceof WebAssembly.RuntimeError);
var e_runtime_id = e['WasmExceptionRuntimeId'];
assertEquals(e_runtime_id, runtime_id);
assertTrue(Number.isInteger(e_runtime_id));
var e_values = e['WasmExceptionValues'];
assertEquals(values.length, e_values.length);
for (i = 0; i < values.length; ++i) {
assertEquals(values[i], e_values[i]);
}
assertNotEquals(e['WasmExceptionTag'], undefined);
assertTrue(Number.isInteger(e['WasmExceptionTag']));
// TODO(kschimpf): Extract values from the exception.
let e_values = [];
assertEquals(values, e_values);
// Success.
return;
}
throw new MjsUnitAssertionError('Did not throw expected: ' + runtime_id + values);
throw new MjsUnitAssertionError('Did not throw, expected: ' + values);
}
......@@ -523,7 +523,7 @@ class WasmModuleBuilder {
for (let type of wasm.exceptions) {
section.emit_u32v(type.params.length);
for (let param of type.params) {
section.emit_u8(param);
section.enit_u8(param);
}
}
});
......
......@@ -2273,7 +2273,8 @@ TEST_F(FunctionBodyDecoderTest, Throw) {
// exception index out of range.
EXPECT_FAILURE(v_v, kExprThrow, 2);
EXPECT_VERIFIES(v_v, WASM_I32V(0), kExprThrow, 1);
// TODO(kschimpf): Fix when we can create exceptions with values.
EXPECT_FAILURE(v_v, WASM_I32V(0), kExprThrow, 1);
// TODO(kschimpf): Add more tests.
}
......
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