Commit 41daf8a5 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

Revert "Start migration of try/throw/catch to match proposal."

This reverts commit 470a1001.

Reason for revert: GC stress bot failures.
https://uberchromegw.corp.google.com/i/client.v8/builders/V8%20Mac%20GC%20Stress/builds/14522


Original change's description:
> Start migration of try/throw/catch to match proposal.
> 
> This CL does the first baby steps on moving the current (experimental)
> exception handling to match that of the WebAssembly proposal.
> 
> It does the following:
> 
> 1) Use exception tags instead of integers.
> 
> 2) Only handle empty exception signatures (i.e. no values associated
>    with the exception tag.
> 
> 3) Only handle one catch clause.
> 
> 4) Be sure to rethrow the exception if the exception tag does not match.
> 
> Note: There are many things that need to be fixed, and are too
> numerous to list here. However, the code should have TODO's on each
> missing parts of the implementation.
> 
> Also note that the code currently doesn't handle nested catch blocks,
> nor does it change the throw value being an integer. Rather, the
> integer value is still being thrown, and currently is the exception
> tag. Therefore, we don't build an exception object. This is the reason
> why this CL doesn't handle exceptions that pass values.
> 
> Also, the current implementation still can't handle multiple modules
> because tag resolution (between) modules has not be implemented yet.
> 
> Bug: v8:6577
> Change-Id: Id6d08b641b3c42d1eec7d4db582f2dab35406114
> Reviewed-on: https://chromium-review.googlesource.com/591910
> Reviewed-by: Brad Nelson <bradnelson@chromium.org>
> Commit-Queue: Karl Schimpf <kschimpf@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#47087}

TBR=bradnelson@chromium.org,eholk@chromium.org,kschimpf@chromium.org

Change-Id: I01dc8c40cc1057333a988c1d275ce5f457b0cb64
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6577
Reviewed-on: https://chromium-review.googlesource.com/598847Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47090}
parent 65265429
...@@ -1830,18 +1830,12 @@ Node* WasmGraphBuilder::Throw(Node* input) { ...@@ -1830,18 +1830,12 @@ Node* WasmGraphBuilder::Throw(Node* input) {
arraysize(parameters)); arraysize(parameters));
} }
Node* WasmGraphBuilder::Rethrow() {
SetNeedsStackCheck();
Node* result = BuildCallToRuntime(Runtime::kWasmRethrow, nullptr, 0);
return result;
}
Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) { Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) {
SetNeedsStackCheck(); SetNeedsStackCheck();
CommonOperatorBuilder* common = jsgraph()->common(); CommonOperatorBuilder* common = jsgraph()->common();
Node* parameters[] = {input}; // caught value Node* parameters[] = {input}; // caught value
Node* value = BuildCallToRuntime(Runtime::kWasmSetCaughtExceptionValue, Node* value = BuildCallToRuntime(Runtime::kWasmGetCaughtExceptionValue,
parameters, arraysize(parameters)); parameters, arraysize(parameters));
Node* is_smi; Node* is_smi;
......
...@@ -168,7 +168,6 @@ class WasmGraphBuilder { ...@@ -168,7 +168,6 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position = wasm::kNoCodePosition); wasm::WasmCodePosition position = wasm::kNoCodePosition);
Node* GrowMemory(Node* input); Node* GrowMemory(Node* input);
Node* Throw(Node* input); Node* Throw(Node* input);
Node* Rethrow();
Node* Catch(Node* input, wasm::WasmCodePosition position); Node* Catch(Node* input, wasm::WasmCodePosition position);
unsigned InputCount(Node* node); unsigned InputCount(Node* node);
bool IsPhiWithMerge(Node* phi, Node* merge); bool IsPhiWithMerge(Node* phi, Node* merge);
......
...@@ -47,17 +47,6 @@ bool Isolate::has_pending_exception() { ...@@ -47,17 +47,6 @@ bool Isolate::has_pending_exception() {
return !thread_local_top_.pending_exception_->IsTheHole(this); return !thread_local_top_.pending_exception_->IsTheHole(this);
} }
Object* Isolate::get_wasm_caught_exception() const {
return thread_local_top_.wasm_caught_exception_;
}
void Isolate::set_wasm_caught_exception(Object* exception_obj) {
thread_local_top_.wasm_caught_exception_ = exception_obj;
}
void Isolate::clear_wasm_caught_exception() {
thread_local_top_.wasm_caught_exception_ = nullptr;
}
void Isolate::clear_pending_message() { void Isolate::clear_pending_message() {
thread_local_top_.pending_message_obj_ = heap_.the_hole_value(); thread_local_top_.pending_message_obj_ = heap_.the_hole_value();
......
...@@ -103,7 +103,6 @@ void ThreadLocalTop::InitializeInternal() { ...@@ -103,7 +103,6 @@ void ThreadLocalTop::InitializeInternal() {
// These members are re-initialized later after deserialization // These members are re-initialized later after deserialization
// is complete. // is complete.
pending_exception_ = NULL; pending_exception_ = NULL;
wasm_caught_exception_ = NULL;
rethrowing_message_ = false; rethrowing_message_ = false;
pending_message_obj_ = NULL; pending_message_obj_ = NULL;
scheduled_exception_ = NULL; scheduled_exception_ = NULL;
...@@ -216,7 +215,6 @@ void Isolate::IterateThread(ThreadVisitor* v, char* t) { ...@@ -216,7 +215,6 @@ void Isolate::IterateThread(ThreadVisitor* v, char* t) {
void Isolate::Iterate(RootVisitor* v, ThreadLocalTop* thread) { void Isolate::Iterate(RootVisitor* v, ThreadLocalTop* thread) {
// Visit the roots from the top for a given thread. // Visit the roots from the top for a given thread.
v->VisitRootPointer(Root::kTop, &thread->pending_exception_); v->VisitRootPointer(Root::kTop, &thread->pending_exception_);
v->VisitRootPointer(Root::kTop, &thread->wasm_caught_exception_);
v->VisitRootPointer(Root::kTop, &thread->pending_message_obj_); v->VisitRootPointer(Root::kTop, &thread->pending_message_obj_);
v->VisitRootPointer(Root::kTop, bit_cast<Object**>(&(thread->context_))); v->VisitRootPointer(Root::kTop, bit_cast<Object**>(&(thread->context_)));
v->VisitRootPointer(Root::kTop, &thread->scheduled_exception_); v->VisitRootPointer(Root::kTop, &thread->scheduled_exception_);
......
...@@ -326,9 +326,6 @@ class ThreadLocalTop BASE_EMBEDDED { ...@@ -326,9 +326,6 @@ class ThreadLocalTop BASE_EMBEDDED {
Context* context_; Context* context_;
ThreadId thread_id_; ThreadId thread_id_;
Object* pending_exception_; Object* pending_exception_;
// TODO(kschimpf): Change this to a stack of caught exceptions (rather than
// just innermost catching try block).
Object* wasm_caught_exception_;
// Communication channel between Isolate::FindHandler and the CEntryStub. // Communication channel between Isolate::FindHandler and the CEntryStub.
Context* pending_handler_context_; Context* pending_handler_context_;
...@@ -605,11 +602,6 @@ class Isolate { ...@@ -605,11 +602,6 @@ class Isolate {
inline void set_pending_exception(Object* exception_obj); inline void set_pending_exception(Object* exception_obj);
inline void clear_pending_exception(); inline void clear_pending_exception();
// Interface to wasm caught exception.
inline Object* get_wasm_caught_exception() const;
inline void set_wasm_caught_exception(Object* exception_obj);
inline void clear_wasm_caught_exception();
THREAD_LOCAL_TOP_ADDRESS(Object*, pending_exception) THREAD_LOCAL_TOP_ADDRESS(Object*, pending_exception)
inline bool has_pending_exception(); inline bool has_pending_exception();
......
...@@ -142,8 +142,6 @@ RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) { ...@@ -142,8 +142,6 @@ RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
} }
RUNTIME_FUNCTION(Runtime_WasmThrow) { RUNTIME_FUNCTION(Runtime_WasmThrow) {
// TODO(kschimpf): Change this to build a runtime exception with
// wasm properties, instead of just an integer.
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_SMI_ARG_CHECKED(lower, 0); CONVERT_SMI_ARG_CHECKED(lower, 0);
...@@ -158,15 +156,7 @@ RUNTIME_FUNCTION(Runtime_WasmThrow) { ...@@ -158,15 +156,7 @@ RUNTIME_FUNCTION(Runtime_WasmThrow) {
return isolate->Throw(*isolate->factory()->NewNumberFromInt(thrown_value)); return isolate->Throw(*isolate->factory()->NewNumberFromInt(thrown_value));
} }
RUNTIME_FUNCTION(Runtime_WasmRethrow) { RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
Object* exception = isolate->get_wasm_caught_exception();
isolate->clear_wasm_caught_exception();
return isolate->Throw(exception);
}
RUNTIME_FUNCTION(Runtime_WasmSetCaughtExceptionValue) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
Object* exception = args[0]; Object* exception = args[0];
...@@ -174,7 +164,6 @@ RUNTIME_FUNCTION(Runtime_WasmSetCaughtExceptionValue) { ...@@ -174,7 +164,6 @@ RUNTIME_FUNCTION(Runtime_WasmSetCaughtExceptionValue) {
// Number or a Smi (which we have just converted to a Number.) This logic // Number or a Smi (which we have just converted to a Number.) This logic
// lives in Isolate::is_catchable_by_wasm(Object*). // lives in Isolate::is_catchable_by_wasm(Object*).
CHECK(exception->IsNumber()); CHECK(exception->IsNumber());
isolate->set_wasm_caught_exception(exception);
return exception; return exception;
} }
......
...@@ -634,8 +634,7 @@ namespace internal { ...@@ -634,8 +634,7 @@ namespace internal {
F(ThrowWasmStackOverflow, 0, 1) \ F(ThrowWasmStackOverflow, 0, 1) \
F(WasmThrowTypeError, 0, 1) \ F(WasmThrowTypeError, 0, 1) \
F(WasmThrow, 2, 1) \ F(WasmThrow, 2, 1) \
F(WasmRethrow, 0, 1) \ F(WasmGetCaughtExceptionValue, 1, 1) \
F(WasmSetCaughtExceptionValue, 1, 1) \
F(WasmRunInterpreter, 3, 1) \ F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1) \ F(WasmStackGuard, 0, 1) \
F(SetThreadInWasm, 0, 1) \ F(SetThreadInWasm, 0, 1) \
......
...@@ -13,7 +13,6 @@ namespace internal { ...@@ -13,7 +13,6 @@ namespace internal {
namespace wasm { namespace wasm {
struct WasmGlobal; struct WasmGlobal;
struct WasmException;
// Use this macro to check a condition if checked == true, and DCHECK the // Use this macro to check a condition if checked == true, and DCHECK the
// condition otherwise. // condition otherwise.
...@@ -35,17 +34,6 @@ struct LocalIndexOperand { ...@@ -35,17 +34,6 @@ struct LocalIndexOperand {
} }
}; };
template <bool checked>
struct ExceptionIndexOperand {
uint32_t index;
const WasmException* exception = nullptr;
unsigned length;
inline ExceptionIndexOperand(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<checked>(pc + 1, &length, "exception index");
}
};
template <bool checked> template <bool checked>
struct ImmI32Operand { struct ImmI32Operand {
int32_t value; int32_t value;
......
...@@ -44,8 +44,9 @@ namespace wasm { ...@@ -44,8 +44,9 @@ namespace wasm {
break; \ break; \
} }
#define OPCODE_ERROR(opcode, message) \ #define PROTOTYPE_NOT_FUNCTIONAL(opcode) \
(errorf(pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), (message))) errorf(pc_, "Prototype still not functional: %s", \
WasmOpcodes::OpcodeName(opcode));
// An SsaEnv environment carries the current local variable renaming // An SsaEnv environment carries the current local variable renaming
// as well as the current effect and control dependency in the TF graph. // as well as the current effect and control dependency in the TF graph.
...@@ -81,10 +82,8 @@ struct Value { ...@@ -81,10 +82,8 @@ struct Value {
struct TryInfo : public ZoneObject { struct TryInfo : public ZoneObject {
SsaEnv* catch_env; SsaEnv* catch_env;
TFNode* exception; TFNode* exception;
size_t catch_count; // Number of catch blocks associated with the try.
explicit TryInfo(SsaEnv* c) explicit TryInfo(SsaEnv* c) : catch_env(c), exception(nullptr) {}
: catch_env(c), exception(nullptr), catch_count(0) {}
}; };
struct MergeValues { struct MergeValues {
...@@ -284,15 +283,6 @@ class WasmDecoder : public Decoder { ...@@ -284,15 +283,6 @@ class WasmDecoder : public Decoder {
return false; return false;
} }
inline bool Validate(const byte* pc, ExceptionIndexOperand<true>& operand) {
if (module_ != nullptr && operand.index < module_->exceptions.size()) {
operand.exception = &module_->exceptions[operand.index];
return true;
}
errorf(pc + 1, "Invalid exception index: %u", operand.index);
return false;
}
inline bool Validate(const byte* pc, GlobalIndexOperand<true>& operand) { inline bool Validate(const byte* pc, GlobalIndexOperand<true>& operand) {
if (module_ != nullptr && operand.index < module_->globals.size()) { if (module_ != nullptr && operand.index < module_->globals.size()) {
operand.global = &module_->globals[operand.index]; operand.global = &module_->globals[operand.index];
...@@ -472,15 +462,10 @@ class WasmDecoder : public Decoder { ...@@ -472,15 +462,10 @@ class WasmDecoder : public Decoder {
return 1 + operand.length; return 1 + operand.length;
} }
case kExprThrow:
case kExprCatch: {
ExceptionIndexOperand<true> operand(decoder, pc);
return 1 + operand.length;
}
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: case kExprTeeLocal:
case kExprGetLocal: { case kExprGetLocal:
case kExprCatch: {
LocalIndexOperand<true> operand(decoder, pc); LocalIndexOperand<true> operand(decoder, pc);
return 1 + operand.length; return 1 + operand.length;
} }
...@@ -767,13 +752,6 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -767,13 +752,6 @@ class WasmFullDecoder : public WasmDecoder {
return module_->has_memory; return module_->has_memory;
} }
template <bool check>
inline TFNode* GetExceptionTag(ExceptionIndexOperand<check>& operand) {
// TODO(kschimpf): Need to get runtime exception tag values. This
// code only handles non-imported/exported exceptions.
return BUILD(Int32Constant, operand.index);
}
// Decodes the body of a function. // Decodes the body of a function.
void DecodeFunctionBody() { void DecodeFunctionBody() {
TRACE("wasm-decode %p...%p (module+%u, %d bytes) %s\n", TRACE("wasm-decode %p...%p (module+%u, %d bytes) %s\n",
...@@ -830,20 +808,15 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -830,20 +808,15 @@ class WasmFullDecoder : public WasmDecoder {
case kExprRethrow: { case kExprRethrow: {
// TODO(kschimpf): Implement. // TODO(kschimpf): Implement.
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
OPCODE_ERROR(opcode, "not implemented yet"); PROTOTYPE_NOT_FUNCTIONAL(opcode);
break; break;
} }
case kExprThrow: { case kExprThrow: {
// TODO(kschimpf): Fix to use type signature of exception.
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
ExceptionIndexOperand<true> operand(this, pc_); PROTOTYPE_NOT_FUNCTIONAL(opcode);
len = 1 + operand.length; Value value = Pop(0, kWasmI32);
if (!Validate(pc_, operand)) break; BUILD(Throw, value.node);
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;
}
BUILD(Throw, GetExceptionTag(operand));
// TODO(titzer): Throw should end control, but currently we build a // TODO(titzer): Throw should end control, but currently we build a
// (reachable) runtime call instead of connecting it directly to // (reachable) runtime call instead of connecting it directly to
// end. // end.
...@@ -865,62 +838,49 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -865,62 +838,49 @@ class WasmFullDecoder : public WasmDecoder {
case kExprCatch: { case kExprCatch: {
// TODO(kschimpf): Fix to use type signature of exception. // TODO(kschimpf): Fix to use type signature of exception.
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
ExceptionIndexOperand<true> operand(this, pc_); PROTOTYPE_NOT_FUNCTIONAL(opcode);
LocalIndexOperand<true> operand(this, pc_);
len = 1 + operand.length; len = 1 + operand.length;
if (!Validate(pc_, operand)) break;
if (control_.empty()) { if (control_.empty()) {
error("catch does not match any try"); error("catch does not match any try");
break; break;
} }
Control* c = &control_.back(); Control* c = &control_.back();
DCHECK_NOT_NULL(c->try_info);
if (!c->is_try()) { if (!c->is_try()) {
error("catch does not match any try"); error("catch does not match any try");
break; break;
} }
if (c->try_info->catch_count > 0) { if (c->try_info->catch_env == nullptr) {
OPCODE_ERROR(opcode, "multiple catch blocks not implemented"); error(pc_, "catch already present for try with catch");
break; break;
} }
++c->try_info->catch_count;
FallThruTo(c); FallThruTo(c);
stack_.resize(c->stack_depth); stack_.resize(c->stack_depth);
DCHECK_NOT_NULL(c->try_info);
SsaEnv* catch_env = c->try_info->catch_env; SsaEnv* catch_env = c->try_info->catch_env;
c->try_info->catch_env = nullptr;
SetEnv("catch:begin", catch_env); SetEnv("catch:begin", catch_env);
current_catch_ = c->previous_catch; current_catch_ = c->previous_catch;
// Get the exception and see if wanted exception. if (Validate(pc_, operand)) {
if (ssa_env_->locals) {
TFNode* exception_as_i32 = TFNode* exception_as_i32 =
BUILD(Catch, c->try_info->exception, position()); BUILD(Catch, c->try_info->exception, position());
TFNode* exception_tag = GetExceptionTag(operand); ssa_env_->locals[operand.index] = exception_as_i32;
TFNode* compare_i32 = BUILD(Binop, kExprI32Eq, exception_as_i32, }
exception_tag, position()); }
TFNode* if_true = nullptr;
TFNode* if_false = nullptr;
BUILD(BranchNoHint, compare_i32, &if_true, &if_false);
SsaEnv* end_env = ssa_env_;
SsaEnv* false_env = Split(end_env);
false_env->control = if_false;
SsaEnv* true_env = Steal(ssa_env_);
true_env->control = if_true;
c->try_info->catch_env = false_env;
SetEnv("Try:catch", true_env);
len = 1 + operand.length;
// TODO(kschimpf): Add code to pop caught exception from isolate.
break; break;
} }
case kExprCatchAll: { case kExprCatchAll: {
// TODO(kschimpf): Implement. // TODO(kschimpf): Implement.
CHECK_PROTOTYPE_OPCODE(eh); CHECK_PROTOTYPE_OPCODE(eh);
OPCODE_ERROR(opcode, "not implemented yet"); PROTOTYPE_NOT_FUNCTIONAL(opcode);
break; break;
} }
case kExprLoop: { case kExprLoop: {
...@@ -1009,17 +969,10 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1009,17 +969,10 @@ class WasmFullDecoder : public WasmDecoder {
name = "try:end"; name = "try:end";
// validate that catch was seen. // validate that catch was seen.
if (c->try_info->catch_count == 0) { if (c->try_info->catch_env != nullptr) {
error(pc_, "missing catch in try"); error(pc_, "missing catch in try");
break; break;
} }
SsaEnv* fallthru_ssa_env = ssa_env_;
DCHECK_NOT_NULL(c->try_info->catch_env);
SetEnv("Catch fail", c->try_info->catch_env);
BUILD0(Rethrow);
// TODO(karlschimpf): Why not use EndControl ()? (currently fails)
FallThruTo(c);
SetEnv("Catch fallthru", fallthru_ssa_env);
} }
FallThruTo(c); FallThruTo(c);
SetEnv(name, c->end_env); SetEnv(name, c->end_env);
......
...@@ -31,9 +31,9 @@ namespace wasm { ...@@ -31,9 +31,9 @@ namespace wasm {
#endif #endif
namespace { namespace {
constexpr char kNameString[] = "name"; const char kNameString[] = "name";
constexpr char kExceptionString[] = "exception";
constexpr char kUnknownString[] = "<unknown>"; const char kExceptionString[] = "exception";
template <size_t N> template <size_t N>
constexpr size_t num_chars(const char (&)[N]) { constexpr size_t num_chars(const char (&)[N]) {
...@@ -71,10 +71,9 @@ const char* SectionName(SectionCode code) { ...@@ -71,10 +71,9 @@ const char* SectionName(SectionCode code) {
case kNameSectionCode: case kNameSectionCode:
return kNameString; return kNameString;
case kExceptionSectionCode: case kExceptionSectionCode:
if (FLAG_experimental_wasm_eh) return kExceptionString; return kExceptionString;
return kUnknownString;
default: default:
return kUnknownString; return "<unknown>";
} }
} }
...@@ -219,6 +218,11 @@ class WasmSectionIterator { ...@@ -219,6 +218,11 @@ class WasmSectionIterator {
strncmp(reinterpret_cast<const char*>(section_name_start), strncmp(reinterpret_cast<const char*>(section_name_start),
kNameString, num_chars(kNameString)) == 0) { kNameString, num_chars(kNameString)) == 0) {
section_code = kNameSectionCode; section_code = kNameSectionCode;
} else if (FLAG_experimental_wasm_eh &&
string.length() == num_chars(kExceptionString) &&
strncmp(reinterpret_cast<const char*>(section_name_start),
kExceptionString, num_chars(kExceptionString)) == 0) {
section_code = kExceptionSectionCode;
} }
} else if (!IsValidSectionCode(section_code)) { } else if (!IsValidSectionCode(section_code)) {
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x", decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
...@@ -328,25 +332,9 @@ class ModuleDecoder : public Decoder { ...@@ -328,25 +332,9 @@ class ModuleDecoder : public Decoder {
errorf(pc(), "unexpected section: %s", SectionName(section_code)); errorf(pc(), "unexpected section: %s", SectionName(section_code));
return; return;
} }
if (section_code != kUnknownSectionCode) {
switch (section_code) {
case kUnknownSectionCode:
break;
case kExceptionSectionCode:
// Note: kExceptionSectionCode > kCodeSectionCode, but must appear
// before the code section. Hence, treat it as a special case.
if (++number_of_exception_sections > 1) {
errorf(pc(), "Multiple exception sections not allowed");
return;
} else if (next_section_ >= kCodeSectionCode) {
errorf(pc(), "Exception section must appear before the code section");
return;
}
break;
default:
next_section_ = section_code; next_section_ = section_code;
++next_section_; ++next_section_;
break;
} }
switch (section_code) { switch (section_code) {
...@@ -389,11 +377,7 @@ class ModuleDecoder : public Decoder { ...@@ -389,11 +377,7 @@ class ModuleDecoder : public Decoder {
DecodeNameSection(); DecodeNameSection();
break; break;
case kExceptionSectionCode: case kExceptionSectionCode:
if (FLAG_experimental_wasm_eh) {
DecodeExceptionSection(); DecodeExceptionSection();
} else {
errorf(pc(), "unexpected section: %s", SectionName(section_code));
}
break; break;
default: default:
errorf(pc(), "unexpected section: %s", SectionName(section_code)); errorf(pc(), "unexpected section: %s", SectionName(section_code));
...@@ -893,7 +877,6 @@ class ModuleDecoder : public Decoder { ...@@ -893,7 +877,6 @@ class ModuleDecoder : public Decoder {
Counters* counters_ = nullptr; Counters* counters_ = nullptr;
// The type section is the first section in a module. // The type section is the first section in a module.
uint8_t next_section_ = kFirstSectionInModule; uint8_t next_section_ = kFirstSectionInModule;
uint32_t number_of_exception_sections = 0;
// We store next_section_ as uint8_t instead of SectionCode so that we can // We store next_section_ as uint8_t instead of SectionCode so that we can
// increment it. This static_assert should make sure that SectionCode does not // increment it. This static_assert should make sure that SectionCode does not
// get bigger than uint8_t accidentially. // get bigger than uint8_t accidentially.
......
...@@ -34,17 +34,16 @@ enum SectionCode : int8_t { ...@@ -34,17 +34,16 @@ enum SectionCode : int8_t {
kCodeSectionCode = 10, // Function code kCodeSectionCode = 10, // Function code
kDataSectionCode = 11, // Data segments kDataSectionCode = 11, // Data segments
kNameSectionCode = 12, // Name section (encoded as a string) kNameSectionCode = 12, // Name section (encoded as a string)
kExceptionSectionCode = 13, // Exception section kExceptionSectionCode = 13, // Exception section (encoded as a string)
// Helper values // Helper values
kFirstSectionInModule = kTypeSectionCode, kFirstSectionInModule = kTypeSectionCode,
kLastKnownModuleSection = kExceptionSectionCode,
}; };
enum NameSectionType : uint8_t { kModule = 0, kFunction = 1, kLocal = 2 }; enum NameSectionType : uint8_t { kModule = 0, kFunction = 1, kLocal = 2 };
inline bool IsValidSectionCode(uint8_t byte) { inline bool IsValidSectionCode(uint8_t byte) {
return kTypeSectionCode <= byte && byte <= kLastKnownModuleSection; return kTypeSectionCode <= byte && byte <= kDataSectionCode;
} }
const char* SectionName(SectionCode code); const char* SectionName(SectionCode code);
......
...@@ -143,14 +143,9 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -143,14 +143,9 @@ void wasm::PrintWasmText(const WasmModule *module,
} }
case kExprGetLocal: case kExprGetLocal:
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: { case kExprTeeLocal:
LocalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break;
}
case kExprThrow:
case kExprCatch: { case kExprCatch: {
ExceptionIndexOperand<false> operand(&i, i.pc()); LocalIndexOperand<false> operand(&i, i.pc());
os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index; os << WasmOpcodes::OpcodeName(opcode) << ' ' << operand.index;
break; break;
} }
...@@ -188,6 +183,7 @@ void wasm::PrintWasmText(const WasmModule *module, ...@@ -188,6 +183,7 @@ void wasm::PrintWasmText(const WasmModule *module,
case kExprGrowMemory: case kExprGrowMemory:
case kExprDrop: case kExprDrop:
case kExprSelect: case kExprSelect:
case kExprThrow:
os << WasmOpcodes::OpcodeName(opcode); os << WasmOpcodes::OpcodeName(opcode);
break; break;
......
...@@ -177,6 +177,9 @@ ...@@ -177,6 +177,9 @@
# BUG(v8:6306). # BUG(v8:6306).
'wasm/huge-memory': [SKIP], 'wasm/huge-memory': [SKIP],
# BUG(v8:6577).
'wasm/exceptions': [SKIP],
}], # ALWAYS }], # ALWAYS
['novfp3 == True', { ['novfp3 == True', {
......
...@@ -7,73 +7,6 @@ ...@@ -7,73 +7,6 @@
load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
// The following method doesn't attempt to catch an raised exception.
var test_throw = (function () {
var builder = new WasmModuleBuilder();
builder.addException(kSig_v_v);
builder.addFunction("throw_if_param_not_zero", kSig_i_i)
.addBody([
kExprGetLocal, 0,
kExprI32Const, 0,
kExprI32Ne,
kExprIf, kWasmStmt,
kExprThrow, 0,
kExprEnd,
kExprI32Const, 1
]).exportFunc();
return builder.instantiate();
})();
// Check the test_throw exists.
assertFalse(test_throw === undefined);
assertFalse(test_throw === null);
assertFalse(test_throw === 0);
assertEquals("object", typeof test_throw.exports);
assertEquals("function", typeof test_throw.exports.throw_if_param_not_zero);
// Test expected behavior of throws
assertEquals(1, test_throw.exports.throw_if_param_not_zero(0));
assertWasmThrows([], function() { test_throw.exports.throw_if_param_not_zero(10) });
assertWasmThrows([], function() { test_throw.exports.throw_if_param_not_zero(-1) });
// Now that we know throwing works, we test catching the exceptions we raise.
var test_catch = (function () {
var builder = new WasmModuleBuilder();
builder.addException(kSig_v_v);
builder.addFunction("simple_throw_catch_to_0_1", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprI32Eqz,
kExprIf, kWasmStmt,
kExprThrow, 0,
kExprEnd,
kExprI32Const, 1,
kExprCatch, 0,
kExprI32Const, 0,
kExprEnd
]).exportFunc();
return builder.instantiate();
})();
// Check the test_catch exists.
assertFalse(test_catch === undefined);
assertFalse(test_catch === null);
assertFalse(test_catch === 0);
assertEquals("object", typeof test_catch.exports);
assertEquals("function", typeof test_catch.exports.simple_throw_catch_to_0_1);
// Test expected behavior of simple catch.
assertEquals(0, test_catch.exports.simple_throw_catch_to_0_1(0));
assertEquals(1, test_catch.exports.simple_throw_catch_to_0_1(1));
/* TODO(kschimpf) Convert these tests to work for the proposed exceptions.
// The following methods do not attempt to catch the exception they raise. // The following methods do not attempt to catch the exception they raise.
var test_throw = (function () { var test_throw = (function () {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
...@@ -296,16 +229,16 @@ var test_catch = (function () { ...@@ -296,16 +229,16 @@ var test_catch = (function () {
kExprI32Eq, kExprI32Eq,
kExprIf, kWasmStmt, kExprIf, kWasmStmt,
kExprGetLocal, 2, kExprGetLocal, 2,
kExprI32Const, / *64=* / 192, 0, kExprI32Const, /*64=*/ 192, 0,
kExprI32Ior, kExprI32Ior,
kExprThrow, kExprThrow,
kExprUnreachable, kExprUnreachable,
kExprEnd, kExprEnd,
kExprI32Const, / *128=* / 128, 1, kExprI32Const, /*128=*/ 128, 1,
kExprI32Ior, kExprI32Ior,
kExprCatch, 1, kExprCatch, 1,
kExprGetLocal, 1, kExprGetLocal, 1,
kExprI32Const, / *256=* / 128, 2, kExprI32Const, /*256=*/ 128, 2,
kExprI32Ior, kExprI32Ior,
kExprEnd, kExprEnd,
]) ])
...@@ -319,7 +252,7 @@ var test_catch = (function () { ...@@ -319,7 +252,7 @@ var test_catch = (function () {
kExprTry, kWasmI32, kExprTry, kWasmI32,
kExprGetLocal, 0, kExprGetLocal, 0,
kExprCallFunction, kWasmThrowFunction, kExprCallFunction, kWasmThrowFunction,
kExprI32Const, / *-1=* / 127, kExprI32Const, /*-1=*/ 127,
kExprCatch, 1, kExprCatch, 1,
kExprGetLocal, 1, kExprGetLocal, 1,
kExprEnd kExprEnd
...@@ -354,7 +287,7 @@ var test_catch = (function () { ...@@ -354,7 +287,7 @@ var test_catch = (function () {
kExprGetLocal, 0, kExprGetLocal, 0,
kExprI32Const, 0, kExprI32Const, 0,
kExprCallFunction, kFromIndirectCalleeHelper, kExprCallFunction, kFromIndirectCalleeHelper,
kExprI32Const, / *-1=* / 127, kExprI32Const, /*-1=*/ 127,
kExprCatch, 1, kExprCatch, 1,
kExprGetLocal, 1, kExprGetLocal, 1,
kExprEnd kExprEnd
...@@ -368,7 +301,7 @@ var test_catch = (function () { ...@@ -368,7 +301,7 @@ var test_catch = (function () {
kExprTry, kWasmI32, kExprTry, kWasmI32,
kExprGetLocal, 0, kExprGetLocal, 0,
kExprCallFunction, kJSThrowI, kExprCallFunction, kJSThrowI,
kExprI32Const, / *-1=* / 127, kExprI32Const, /*-1=*/ 127,
kExprCatch, 1, kExprCatch, 1,
kExprGetLocal, 1, kExprGetLocal, 1,
kExprEnd, kExprEnd,
...@@ -448,4 +381,3 @@ assertEquals(-10, test_catch.exports.from_js(-10)); ...@@ -448,4 +381,3 @@ assertEquals(-10, test_catch.exports.from_js(-10));
assertThrowsEquals(test_catch.exports.string_from_js, "use wasm;"); assertThrowsEquals(test_catch.exports.string_from_js, "use wasm;");
assertThrowsEquals(test_catch.exports.large_from_js, 1e+28); assertThrowsEquals(test_catch.exports.large_from_js, 1e+28);
assertThrowsEquals(test_catch.exports.undefined_from_js, undefined); assertThrowsEquals(test_catch.exports.undefined_from_js, undefined);
*/
...@@ -64,7 +64,6 @@ let kElementSectionCode = 9; // Elements section ...@@ -64,7 +64,6 @@ let kElementSectionCode = 9; // Elements section
let kCodeSectionCode = 10; // Function code let kCodeSectionCode = 10; // Function code
let kDataSectionCode = 11; // Data segments let kDataSectionCode = 11; // Data segments
let kNameSectionCode = 12; // Name section (encoded as string) let kNameSectionCode = 12; // Name section (encoded as string)
let kExceptionSectionCode = 13; // Exception section (must appear before code section)
// Name section types // Name section types
let kModuleNameCode = 0; let kModuleNameCode = 0;
...@@ -358,7 +357,8 @@ function assertTraps(trap, code) { ...@@ -358,7 +357,8 @@ function assertTraps(trap, code) {
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]); throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
} }
function assertWasmThrows(values, code) { function assertWasmThrows(value, code) {
assertEquals('number', typeof value);
try { try {
if (typeof code === 'function') { if (typeof code === 'function') {
code(); code();
...@@ -366,11 +366,10 @@ function assertWasmThrows(values, code) { ...@@ -366,11 +366,10 @@ function assertWasmThrows(values, code) {
eval(code); eval(code);
} }
} catch (e) { } catch (e) {
// TODO(kschimpf): Extract values from the exception. assertEquals('number', typeof e);
let e_values = []; assertEquals(value, e);
assertEquals(values, e_values);
// Success. // Success.
return; return;
} }
throw new MjsUnitAssertionError('Did not throw, expected: ' + values); throw new MjsUnitAssertionError('Did not throw, expected: ' + value);
} }
...@@ -153,7 +153,6 @@ class WasmModuleBuilder { ...@@ -153,7 +153,6 @@ class WasmModuleBuilder {
this.imports = []; this.imports = [];
this.exports = []; this.exports = [];
this.globals = []; this.globals = [];
this.exceptions = [];
this.functions = []; this.functions = [];
this.function_table = []; this.function_table = [];
this.function_table_length = 0; this.function_table_length = 0;
...@@ -209,13 +208,6 @@ class WasmModuleBuilder { ...@@ -209,13 +208,6 @@ class WasmModuleBuilder {
return glob; return glob;
} }
addException(type) {
if (type.results.length != 0)
throw new Error('Invalid exception signature: ' + type);
this.exceptions.push(type);
return this.exceptions.length - 1;
}
addFunction(name, type) { addFunction(name, type) {
let type_index = (typeof type) == "number" ? type : this.addType(type); let type_index = (typeof type) == "number" ? type : this.addType(type);
let func = new WasmFunctionBuilder(this, name, type_index); let func = new WasmFunctionBuilder(this, name, type_index);
...@@ -495,20 +487,6 @@ class WasmModuleBuilder { ...@@ -495,20 +487,6 @@ class WasmModuleBuilder {
}); });
} }
// Add exceptions.
if (wasm.exceptions.length > 0) {
if (debug) print("emitting exceptions @ " + binary.length);
binary.emit_section(kExceptionSectionCode, section => {
section.emit_u32v(wasm.exceptions.length);
for (let type of wasm.exceptions) {
section.emit_u32v(type.params.length);
for (let param of type.params) {
section.enit_u8(param);
}
}
});
}
// Add function bodies. // Add function bodies.
if (wasm.functions.length > 0) { if (wasm.functions.length > 0) {
// emit function bodies // emit function bodies
......
...@@ -186,9 +186,6 @@ class FunctionBodyDecoderTest : public TestWithZone { ...@@ -186,9 +186,6 @@ class FunctionBodyDecoderTest : public TestWithZone {
}; };
namespace { namespace {
constexpr size_t kMaxByteSizedLeb128 = 127;
// A helper for tests that require a module environment for functions, // A helper for tests that require a module environment for functions,
// globals, or memories. // globals, or memories.
class TestModuleEnv : public ModuleEnv { class TestModuleEnv : public ModuleEnv {
...@@ -199,12 +196,12 @@ class TestModuleEnv : public ModuleEnv { ...@@ -199,12 +196,12 @@ class TestModuleEnv : public ModuleEnv {
} }
byte AddGlobal(ValueType type, bool mutability = true) { byte AddGlobal(ValueType type, bool mutability = true) {
mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false}); mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
CHECK(mod.globals.size() <= kMaxByteSizedLeb128); CHECK(mod.globals.size() <= 127);
return static_cast<byte>(mod.globals.size() - 1); return static_cast<byte>(mod.globals.size() - 1);
} }
byte AddSignature(FunctionSig* sig) { byte AddSignature(FunctionSig* sig) {
mod.signatures.push_back(sig); mod.signatures.push_back(sig);
CHECK(mod.signatures.size() <= kMaxByteSizedLeb128); CHECK(mod.signatures.size() <= 127);
return static_cast<byte>(mod.signatures.size() - 1); return static_cast<byte>(mod.signatures.size() - 1);
} }
byte AddFunction(FunctionSig* sig) { byte AddFunction(FunctionSig* sig) {
...@@ -215,7 +212,7 @@ class TestModuleEnv : public ModuleEnv { ...@@ -215,7 +212,7 @@ class TestModuleEnv : public ModuleEnv {
{0, 0}, // code {0, 0}, // code
false, // import false, // import
false}); // export false}); // export
CHECK(mod.functions.size() <= kMaxByteSizedLeb128); CHECK(mod.functions.size() <= 127);
return static_cast<byte>(mod.functions.size() - 1); return static_cast<byte>(mod.functions.size() - 1);
} }
byte AddImport(FunctionSig* sig) { byte AddImport(FunctionSig* sig) {
...@@ -223,11 +220,6 @@ class TestModuleEnv : public ModuleEnv { ...@@ -223,11 +220,6 @@ class TestModuleEnv : public ModuleEnv {
mod.functions[result].imported = true; mod.functions[result].imported = true;
return result; return result;
} }
byte AddException(WasmExceptionSig* sig) {
mod.exceptions.emplace_back(sig);
CHECK(mod.signatures.size() <= kMaxByteSizedLeb128);
return static_cast<byte>(mod.exceptions.size() - 1);
}
void InitializeMemory() { void InitializeMemory() {
mod.has_memory = true; mod.has_memory = true;
...@@ -2241,53 +2233,28 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) { ...@@ -2241,53 +2233,28 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
TEST_F(FunctionBodyDecoderTest, Throw) { TEST_F(FunctionBodyDecoderTest, Throw) {
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
TestModuleEnv module_env; // TODO(kschimpf): Need to fix throw to use declared exception.
module = &module_env; EXPECT_FAILURE(v_i, WASM_GET_LOCAL(0), kExprThrow);
module_env.AddException(sigs.v_v());
module_env.AddException(sigs.v_i());
AddLocals(kWasmI32, 1);
EXPECT_VERIFIES(v_v, kExprThrow, 0);
// exception index out of range.
EXPECT_FAILURE(v_v, kExprThrow, 2);
// TODO(kschimpf): Fix when we can create exceptions with values.
EXPECT_FAILURE(v_v, WASM_I32V(0), kExprThrow, 1);
// TODO(kschimpf): Add more tests. EXPECT_FAILURE(i_d, WASM_GET_LOCAL(0), kExprThrow, WASM_I32V(0));
EXPECT_FAILURE(i_f, WASM_GET_LOCAL(0), kExprThrow, WASM_I32V(0));
EXPECT_FAILURE(l_l, WASM_GET_LOCAL(0), kExprThrow, WASM_I64V(0));
} }
TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) { TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
// TODO(titzer): unreachable code after throw should validate. // TODO(titzer): unreachable code after throw should validate.
EXPERIMENTAL_FLAG_SCOPE(eh); // EXPERIMENTAL_FLAG_SCOPE(eh);
TestModuleEnv module_env; // EXPECT_VERIFIES(v_i, WASM_GET_LOCAL(0), kExprThrow, kExprSetLocal, 0);
module = &module_env;
module_env.AddException(sigs.v_v());
module_env.AddException(sigs.v_i());
AddLocals(kWasmI32, 1);
EXPECT_VERIFIES(i_i, kExprThrow, 0, WASM_GET_LOCAL(0));
// TODO(kschimpf): Add more (block-level) tests of unreachable to see
// if they validate.
} }
#define WASM_TRY_OP kExprTry, kLocalVoid #define WASM_TRY_OP kExprTry, kLocalVoid
#define WASM_CATCH(index) kExprCatch, static_cast<byte>(index) #define WASM_CATCH(local) kExprCatch, static_cast<byte>(local)
TEST_F(FunctionBodyDecoderTest, TryCatch) { TEST_F(FunctionBodyDecoderTest, TryCatch) {
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
TestModuleEnv module_env;
module = &module_env;
module_env.AddException(sigs.v_v());
module_env.AddException(sigs.v_v());
// TODO(kschimpf): Need to fix catch to use declared exception. // TODO(kschimpf): Need to fix catch to use declared exception.
EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(0), kExprEnd); EXPECT_FAILURE(v_i, WASM_TRY_OP, WASM_CATCH(0), kExprEnd);
// Missing catch. // Missing catch.
EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprEnd); EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprEnd);
...@@ -2296,8 +2263,7 @@ TEST_F(FunctionBodyDecoderTest, TryCatch) { ...@@ -2296,8 +2263,7 @@ TEST_F(FunctionBodyDecoderTest, TryCatch) {
EXPECT_FAILURE(v_i, WASM_TRY_OP, WASM_CATCH(0)); EXPECT_FAILURE(v_i, WASM_TRY_OP, WASM_CATCH(0));
// Double catch. // Double catch.
// TODO(kschimpf): Fix this to verify. EXPECT_FAILURE(v_i, WASM_TRY_OP, WASM_CATCH(0), WASM_CATCH(0), kExprEnd);
EXPECT_FAILURE(v_i, WASM_TRY_OP, WASM_CATCH(0), WASM_CATCH(1), kExprEnd);
} }
TEST_F(FunctionBodyDecoderTest, MultiValBlock1) { TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
...@@ -2450,7 +2416,7 @@ TEST_F(WasmOpcodeLengthTest, Statements) { ...@@ -2450,7 +2416,7 @@ TEST_F(WasmOpcodeLengthTest, Statements) {
EXPECT_LENGTH(1, kExprSelect); EXPECT_LENGTH(1, kExprSelect);
EXPECT_LENGTH(2, kExprBr); EXPECT_LENGTH(2, kExprBr);
EXPECT_LENGTH(2, kExprBrIf); EXPECT_LENGTH(2, kExprBrIf);
EXPECT_LENGTH(2, kExprThrow); EXPECT_LENGTH(1, kExprThrow);
EXPECT_LENGTH(2, kExprTry); EXPECT_LENGTH(2, kExprTry);
EXPECT_LENGTH(2, kExprCatch); EXPECT_LENGTH(2, kExprCatch);
} }
......
...@@ -50,16 +50,10 @@ namespace wasm { ...@@ -50,16 +50,10 @@ namespace wasm {
#define EMPTY_FUNCTION_SIGNATURES_SECTION SECTION(Function, 1), 0 #define EMPTY_FUNCTION_SIGNATURES_SECTION SECTION(Function, 1), 0
#define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, 1), 0 #define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, 1), 0
#define SECTION_NAMES(size) SECTION(Unknown, size + 5), 4, 'n', 'a', 'm', 'e' #define SECTION_NAMES(size) SECTION(Unknown, size + 5), 4, 'n', 'a', 'm', 'e'
#define SECTION_EXCEPTIONS(size) SECTION(Exception, size) #define SECTION_EXCEPTIONS(size) \
SECTION(Unknown, size + 10), 9, 'e', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n'
#define EMPTY_NAMES_SECTION SECTION_NAMES(1), 0 #define EMPTY_NAMES_SECTION SECTION_NAMES(1), 0
#define FAIL_IF_NO_EXPERIMENTAL_EH(data) \
do { \
ModuleResult result = DecodeModule((data), (data) + sizeof((data))); \
EXPECT_FALSE(result.ok()); \
EXPECT_EQ(0u, result.val->exceptions.size()); \
} while (0)
#define X1(...) __VA_ARGS__ #define X1(...) __VA_ARGS__
#define X2(...) __VA_ARGS__, __VA_ARGS__ #define X2(...) __VA_ARGS__, __VA_ARGS__
#define X3(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__ #define X3(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__
...@@ -375,22 +369,31 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) { ...@@ -375,22 +369,31 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
static const byte data[] = { static const byte data[] = {
SECTION_EXCEPTIONS(1), 0, SECTION_EXCEPTIONS(1), 0,
}; };
FAIL_IF_NO_EXPERIMENTAL_EH(data);
{
// Should decode exception section with no exceptions
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data)); ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result); EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size()); EXPECT_EQ(0u, result.val->exceptions.size());
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
} }
TEST_F(WasmModuleVerifyTest, OneI32Exception) { TEST_F(WasmModuleVerifyTest, OneI32Exception) {
static const byte data[] = { static const byte data[] = {
SECTION_EXCEPTIONS(3), 1, SECTION_EXCEPTIONS(3), 1,
// except[0] (i32) 1, // except[0] (i32)
1, kLocalI32, kLocalI32,
}; };
FAIL_IF_NO_EXPERIMENTAL_EH(data);
{
// Should decode to exactly one exception
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data)); ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result); EXPECT_OK(result);
...@@ -399,16 +402,25 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) { ...@@ -399,16 +402,25 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) {
const WasmException& e0 = result.val->exceptions.front(); const WasmException& e0 = result.val->exceptions.front();
EXPECT_EQ(1u, e0.sig->parameter_count()); EXPECT_EQ(1u, e0.sig->parameter_count());
EXPECT_EQ(MachineRepresentation::kWord32, e0.sig->GetParam(0)); EXPECT_EQ(MachineRepresentation::kWord32, e0.sig->GetParam(0));
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
} }
TEST_F(WasmModuleVerifyTest, TwoExceptions) { TEST_F(WasmModuleVerifyTest, TwoExceptions) {
static const byte data[] = {SECTION_EXCEPTIONS(6), 2, static const byte data[] = {SECTION_EXCEPTIONS(6),
// except[0] (f32, i64) 2,
2, kLocalF32, kLocalI64, 2, // except[0] (f32, i64)
// except[1] (i32) kLocalF32,
1, kLocalI32}; kLocalI64,
FAIL_IF_NO_EXPERIMENTAL_EH(data); 1, // except[1] (i32)
kLocalI32};
{
// Should decode to exactly two exceptions
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data)); ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result); EXPECT_OK(result);
...@@ -417,20 +429,32 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) { ...@@ -417,20 +429,32 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) {
EXPECT_EQ(2u, e0.sig->parameter_count()); EXPECT_EQ(2u, e0.sig->parameter_count());
EXPECT_EQ(MachineRepresentation::kFloat32, e0.sig->GetParam(0)); EXPECT_EQ(MachineRepresentation::kFloat32, e0.sig->GetParam(0));
EXPECT_EQ(MachineRepresentation::kWord64, e0.sig->GetParam(1)); EXPECT_EQ(MachineRepresentation::kWord64, e0.sig->GetParam(1));
const WasmException& e1 = result.val->exceptions.back(); }
EXPECT_EQ(MachineRepresentation::kWord32, e1.sig->GetParam(0)); {
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
} }
TEST_F(WasmModuleVerifyTest, Exception_invalid_type) { TEST_F(WasmModuleVerifyTest, Exception_invalid_type) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1, static const byte data[] = {SECTION_EXCEPTIONS(3), 1,
// except[0] (?) 1, // except[0] (?)
1, 64}; 64};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
{
// Should fail decoding exception section. // Should fail decoding exception section.
EXPERIMENTAL_FLAG_SCOPE(eh); EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data)); ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_FALSE(result.ok()); EXPECT_FALSE(result.ok());
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
} }
TEST_F(WasmModuleVerifyTest, OneSignature) { TEST_F(WasmModuleVerifyTest, OneSignature) {
......
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