summaryrefslogtreecommitdiff
path: root/deps/v8/test/common/wasm
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2021-03-12 08:24:20 +0100
committerMichaël Zasso <targos@protonmail.com>2021-03-15 15:54:50 +0100
commit732ad99e47bae5deffa3a22d2ebe5500284106f0 (patch)
tree759a6b072accf188f03c74a84e8256fe92f1925c /deps/v8/test/common/wasm
parent802b3e7cf9a5074a72bec75cf1c46758b81e04b1 (diff)
downloadnode-new-732ad99e47bae5deffa3a22d2ebe5500284106f0.tar.gz
deps: update V8 to 9.0.257.11
PR-URL: https://github.com/nodejs/node/pull/37587 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/test/common/wasm')
-rw-r--r--deps/v8/test/common/wasm/test-signatures.h3
-rw-r--r--deps/v8/test/common/wasm/wasm-interpreter.cc677
-rw-r--r--deps/v8/test/common/wasm/wasm-interpreter.h12
-rw-r--r--deps/v8/test/common/wasm/wasm-macro-gen.h41
-rw-r--r--deps/v8/test/common/wasm/wasm-module-runner.cc58
5 files changed, 526 insertions, 265 deletions
diff --git a/deps/v8/test/common/wasm/test-signatures.h b/deps/v8/test/common/wasm/test-signatures.h
index c7429c23e2..fb1a1fcddf 100644
--- a/deps/v8/test/common/wasm/test-signatures.h
+++ b/deps/v8/test/common/wasm/test-signatures.h
@@ -47,6 +47,7 @@ class TestSignatures {
sig_v_iii(0, 3, kIntTypes4),
sig_v_e(0, 1, kExternRefTypes4),
sig_v_c(0, 1, kFuncTypes4),
+ sig_v_d(0, 1, kDoubleTypes4),
sig_s_i(1, 1, kSimd128IntTypes4),
sig_s_s(1, 1, kSimd128Types4),
sig_s_ss(1, 2, kSimd128Types4),
@@ -111,6 +112,7 @@ class TestSignatures {
FunctionSig* v_iii() { return &sig_v_iii; }
FunctionSig* v_e() { return &sig_v_e; }
FunctionSig* v_c() { return &sig_v_c; }
+ FunctionSig* v_d() { return &sig_v_d; }
FunctionSig* s_i() { return &sig_s_i; }
FunctionSig* s_s() { return &sig_s_s; }
FunctionSig* s_ss() { return &sig_s_ss; }
@@ -178,6 +180,7 @@ class TestSignatures {
FunctionSig sig_v_iii;
FunctionSig sig_v_e;
FunctionSig sig_v_c;
+ FunctionSig sig_v_d;
FunctionSig sig_s_i;
FunctionSig sig_s_s;
FunctionSig sig_s_ss;
diff --git a/deps/v8/test/common/wasm/wasm-interpreter.cc b/deps/v8/test/common/wasm/wasm-interpreter.cc
index e58e518e8d..4a4d08524a 100644
--- a/deps/v8/test/common/wasm/wasm-interpreter.cc
+++ b/deps/v8/test/common/wasm/wasm-interpreter.cc
@@ -8,6 +8,7 @@
#include <type_traits>
#include "src/base/overflowing-math.h"
+#include "src/base/safe_conversions.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/globals.h"
#include "src/compiler/wasm-compiler.h"
@@ -449,19 +450,6 @@ int_type ExecuteConvert(float_type a, TrapReason* trap) {
return 0;
}
-template <typename int_type, typename float_type>
-int_type ExecuteConvertSaturate(float_type a) {
- TrapReason base_trap = kTrapCount;
- int32_t val = ExecuteConvert<int_type>(a, &base_trap);
- if (base_trap == kTrapCount) {
- return val;
- }
- return std::isnan(a) ? 0
- : (a < static_cast<float_type>(0.0)
- ? std::numeric_limits<int_type>::min()
- : std::numeric_limits<int_type>::max());
-}
-
template <typename dst_type, typename src_type, void (*fn)(Address)>
dst_type CallExternalIntToFloatFunction(src_type input) {
uint8_t data[std::max(sizeof(dst_type), sizeof(src_type))];
@@ -471,13 +459,14 @@ dst_type CallExternalIntToFloatFunction(src_type input) {
return ReadUnalignedValue<dst_type>(data_addr);
}
-template <typename dst_type, typename src_type, int32_t (*fn)(Address)>
-dst_type CallExternalFloatToIntFunction(src_type input, TrapReason* trap) {
- uint8_t data[std::max(sizeof(dst_type), sizeof(src_type))];
- Address data_addr = reinterpret_cast<Address>(data);
- WriteUnalignedValue<src_type>(data_addr, input);
- if (!fn(data_addr)) *trap = kTrapFloatUnrepresentable;
- return ReadUnalignedValue<dst_type>(data_addr);
+template <typename dst_type, typename src_type>
+dst_type ConvertFloatToIntOrTrap(src_type input, TrapReason* trap) {
+ if (base::IsValueInRangeForNumericType<dst_type>(input)) {
+ return static_cast<dst_type>(input);
+ } else {
+ *trap = kTrapFloatUnrepresentable;
+ return 0;
+ }
}
uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
@@ -485,67 +474,19 @@ uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
}
int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
- return CallExternalFloatToIntFunction<int64_t, float,
- float32_to_int64_wrapper>(a, trap);
-}
-
-int64_t ExecuteI64SConvertSatF32(float a) {
- TrapReason base_trap = kTrapCount;
- int64_t val = ExecuteI64SConvertF32(a, &base_trap);
- if (base_trap == kTrapCount) {
- return val;
- }
- return std::isnan(a) ? 0
- : (a < 0.0 ? std::numeric_limits<int64_t>::min()
- : std::numeric_limits<int64_t>::max());
+ return ConvertFloatToIntOrTrap<int64_t, float>(a, trap);
}
int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
- return CallExternalFloatToIntFunction<int64_t, double,
- float64_to_int64_wrapper>(a, trap);
-}
-
-int64_t ExecuteI64SConvertSatF64(double a) {
- TrapReason base_trap = kTrapCount;
- int64_t val = ExecuteI64SConvertF64(a, &base_trap);
- if (base_trap == kTrapCount) {
- return val;
- }
- return std::isnan(a) ? 0
- : (a < 0.0 ? std::numeric_limits<int64_t>::min()
- : std::numeric_limits<int64_t>::max());
+ return ConvertFloatToIntOrTrap<int64_t, double>(a, trap);
}
uint64_t ExecuteI64UConvertF32(float a, TrapReason* trap) {
- return CallExternalFloatToIntFunction<uint64_t, float,
- float32_to_uint64_wrapper>(a, trap);
-}
-
-uint64_t ExecuteI64UConvertSatF32(float a) {
- TrapReason base_trap = kTrapCount;
- uint64_t val = ExecuteI64UConvertF32(a, &base_trap);
- if (base_trap == kTrapCount) {
- return val;
- }
- return std::isnan(a) ? 0
- : (a < 0.0 ? std::numeric_limits<uint64_t>::min()
- : std::numeric_limits<uint64_t>::max());
+ return ConvertFloatToIntOrTrap<uint64_t, float>(a, trap);
}
uint64_t ExecuteI64UConvertF64(double a, TrapReason* trap) {
- return CallExternalFloatToIntFunction<uint64_t, double,
- float64_to_uint64_wrapper>(a, trap);
-}
-
-uint64_t ExecuteI64UConvertSatF64(double a) {
- TrapReason base_trap = kTrapCount;
- int64_t val = ExecuteI64UConvertF64(a, &base_trap);
- if (base_trap == kTrapCount) {
- return val;
- }
- return std::isnan(a) ? 0
- : (a < 0.0 ? std::numeric_limits<uint64_t>::min()
- : std::numeric_limits<uint64_t>::max());
+ return ConvertFloatToIntOrTrap<uint64_t, double>(a, trap);
}
int64_t ExecuteI64SConvertI32(int32_t a, TrapReason* trap) {
@@ -614,7 +555,8 @@ int64_t ExecuteI64ReinterpretF64(WasmValue a) {
return a.to_f64_boxed().get_bits();
}
-constexpr int32_t kCatchInArity = 1;
+constexpr int32_t kCatchAllExceptionIndex = -1;
+constexpr int32_t kRethrowOrDelegateExceptionIndex = -2;
} // namespace
@@ -637,10 +579,13 @@ struct InterpreterCode {
class SideTable : public ZoneObject {
public:
ControlTransferMap map_;
+ // Map rethrow instructions to the catch block index they target.
+ ZoneMap<pc_t, int> rethrow_map_;
int32_t max_stack_height_ = 0;
+ int32_t max_control_stack_height = 0;
SideTable(Zone* zone, const WasmModule* module, InterpreterCode* code)
- : map_(zone) {
+ : map_(zone), rethrow_map_(zone) {
// Create a zone for all temporary objects.
Zone control_transfer_zone(zone->allocator(), ZONE_NAME);
@@ -649,7 +594,10 @@ class SideTable : public ZoneObject {
friend Zone;
explicit CLabel(Zone* zone, int32_t target_stack_height, uint32_t arity)
- : target_stack_height(target_stack_height), arity(arity), refs(zone) {
+ : catch_targets(zone),
+ target_stack_height(target_stack_height),
+ arity(arity),
+ refs(zone) {
DCHECK_LE(0, target_stack_height);
}
@@ -658,7 +606,13 @@ class SideTable : public ZoneObject {
const byte* from_pc;
const int32_t stack_height;
};
+ struct CatchTarget {
+ int exception_index;
+ int target_control_index;
+ const byte* pc;
+ };
const byte* target = nullptr;
+ ZoneVector<CatchTarget> catch_targets;
int32_t target_stack_height;
// Arity when branching to this label.
const uint32_t arity;
@@ -674,6 +628,10 @@ class SideTable : public ZoneObject {
target = pc;
}
+ void Bind(const byte* pc, int exception_index, int target_control_index) {
+ catch_targets.push_back({exception_index, target_control_index, pc});
+ }
+
// Reference this label from the given location.
void Ref(const byte* from_pc, int32_t stack_height) {
// Target being bound before a reference means this is a loop.
@@ -682,19 +640,41 @@ class SideTable : public ZoneObject {
}
void Finish(ControlTransferMap* map, const byte* start) {
- DCHECK_NOT_NULL(target);
+ DCHECK_EQ(!!target, catch_targets.empty());
for (auto ref : refs) {
size_t offset = static_cast<size_t>(ref.from_pc - start);
- auto pcdiff = static_cast<pcdiff_t>(target - ref.from_pc);
DCHECK_GE(ref.stack_height, target_stack_height);
spdiff_t spdiff =
static_cast<spdiff_t>(ref.stack_height - target_stack_height);
- TRACE("control transfer @%zu: Δpc %d, stack %u->%u = -%u\n", offset,
- pcdiff, ref.stack_height, target_stack_height, spdiff);
- ControlTransferEntry& entry = (*map)[offset];
- entry.pc_diff = pcdiff;
- entry.sp_diff = spdiff;
- entry.target_arity = arity;
+ if (target) {
+ auto pcdiff = static_cast<pcdiff_t>(target - ref.from_pc);
+ TRACE("control transfer @%zu: Δpc %d, stack %u->%u = -%u\n", offset,
+ pcdiff, ref.stack_height, target_stack_height, spdiff);
+ ControlTransferEntry& entry = (map->map)[offset];
+ entry.pc_diff = pcdiff;
+ entry.sp_diff = spdiff;
+ entry.target_arity = arity;
+ } else {
+ Zone* zone = map->catch_map.get_allocator().zone();
+ auto p = map->catch_map.emplace(
+ offset, ZoneVector<CatchControlTransferEntry>(zone));
+ auto& catch_entries = p.first->second;
+ for (auto& p : catch_targets) {
+ auto pcdiff = static_cast<pcdiff_t>(p.pc - ref.from_pc);
+ TRACE(
+ "control transfer @%zu: Δpc %d, stack %u->%u, exn: %d = "
+ "-%u\n",
+ offset, pcdiff, ref.stack_height, target_stack_height,
+ p.exception_index, spdiff);
+ CatchControlTransferEntry entry;
+ entry.pc_diff = pcdiff;
+ entry.sp_diff = spdiff;
+ entry.target_arity = arity;
+ entry.exception_index = p.exception_index;
+ entry.target_control_index = p.target_control_index;
+ catch_entries.emplace_back(entry);
+ }
+ }
}
}
};
@@ -710,6 +690,9 @@ class SideTable : public ZoneObject {
// Track whether this block was already left, i.e. all further
// instructions are unreachable.
bool unreachable = false;
+ // Whether this is a try...unwind...end block. Needed to handle the
+ // implicit rethrow when we reach the end of the block.
+ bool unwind = false;
Control(const byte* pc, CLabel* end_label, CLabel* else_label,
uint32_t exit_arity)
@@ -733,9 +716,8 @@ class SideTable : public ZoneObject {
// bytecodes are within the true or false block of an else.
ZoneVector<Control> control_stack(&control_transfer_zone);
// It also maintains a stack of all nested {try} blocks to resolve local
- // handler targets for potentially throwing operations. These exceptional
- // control transfers are treated just like other branches in the resulting
- // map. This stack contains indices into the above control stack.
+ // handler targets for potentially throwing operations. This stack contains
+ // indices into the above control stack.
ZoneVector<size_t> exception_stack(zone);
int32_t stack_height = 0;
uint32_t func_arity =
@@ -750,6 +732,14 @@ class SideTable : public ZoneObject {
auto copy_unreachable = [&] {
control_stack.back().unreachable = control_parent().unreachable;
};
+ int max_exception_arity = 0;
+ if (module) {
+ for (auto& exception : module->exceptions) {
+ max_exception_arity =
+ std::max(max_exception_arity,
+ static_cast<int>(exception.sig->parameter_count()));
+ }
+ }
for (BytecodeIterator i(code->start, code->end, &code->locals);
i.has_next(); i.next()) {
WasmOpcode opcode = i.current();
@@ -779,13 +769,16 @@ class SideTable : public ZoneObject {
DCHECK_GE(control_stack.size() - 1, exception_stack.back());
const Control* c = &control_stack[exception_stack.back()];
if (!unreachable) c->else_label->Ref(i.pc(), exceptional_stack_height);
- if (exceptional_stack_height + kCatchInArity > max_stack_height_) {
- max_stack_height_ = exceptional_stack_height + kCatchInArity;
+ if (exceptional_stack_height + max_exception_arity >
+ max_stack_height_) {
+ max_stack_height_ = exceptional_stack_height + max_exception_arity;
}
TRACE("handler @%u: %s -> try @%u\n", i.pc_offset(),
WasmOpcodes::OpcodeName(opcode),
static_cast<uint32_t>(c->pc - code->start));
}
+ max_control_stack_height = std::max(
+ max_control_stack_height, static_cast<int>(control_stack.size()));
switch (opcode) {
case kExprBlock:
case kExprLoop: {
@@ -836,12 +829,11 @@ class SideTable : public ZoneObject {
break;
}
case kExprElse: {
+ TRACE("control @%u: Else\n", i.pc_offset());
Control* c = &control_stack.back();
+ DCHECK_EQ(*c->pc, kExprIf);
copy_unreachable();
- TRACE("control @%u: Else\n", i.pc_offset());
- if (!unreachable) {
- c->end_label->Ref(i.pc(), stack_height);
- }
+ if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
DCHECK_NOT_NULL(c->else_label);
c->else_label->Bind(i.pc() + 1);
c->else_label->Finish(&map_, code->start);
@@ -851,6 +843,49 @@ class SideTable : public ZoneObject {
stack_height >= c->end_label->target_stack_height);
break;
}
+ case kExprCatchAll: {
+ TRACE("control @%u: CatchAll\n", i.pc_offset());
+ Control* c = &control_stack.back();
+ DCHECK_EQ(*c->pc, kExprTry);
+ if (!exception_stack.empty() &&
+ exception_stack.back() == control_stack.size() - 1) {
+ // Only pop the exception stack if this is the only catch handler.
+ exception_stack.pop_back();
+ }
+ copy_unreachable();
+ if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
+ DCHECK_NOT_NULL(c->else_label);
+ int control_index = static_cast<int>(control_stack.size()) - 1;
+ c->else_label->Bind(i.pc() + 1, kCatchAllExceptionIndex,
+ control_index);
+ c->else_label->Finish(&map_, code->start);
+ c->else_label = nullptr;
+ DCHECK_IMPLIES(!unreachable,
+ stack_height >= c->end_label->target_stack_height);
+ stack_height = c->end_label->target_stack_height;
+ break;
+ }
+ case kExprUnwind: {
+ TRACE("control @%u: Unwind\n", i.pc_offset());
+ Control* c = &control_stack.back();
+ DCHECK_EQ(*c->pc, kExprTry);
+ DCHECK(!exception_stack.empty());
+ DCHECK_EQ(exception_stack.back(), control_stack.size() - 1);
+ exception_stack.pop_back();
+ copy_unreachable();
+ if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
+ DCHECK_NOT_NULL(c->else_label);
+ int control_index = static_cast<int>(control_stack.size()) - 1;
+ c->else_label->Bind(i.pc() + 1, kCatchAllExceptionIndex,
+ control_index);
+ c->else_label->Finish(&map_, code->start);
+ c->else_label = nullptr;
+ c->unwind = true;
+ DCHECK_IMPLIES(!unreachable,
+ stack_height >= c->end_label->target_stack_height);
+ stack_height = c->end_label->target_stack_height;
+ break;
+ }
case kExprTry: {
BlockTypeImmediate<Decoder::kNoValidation> imm(
WasmFeatures::All(), &i, i.pc() + 1, module);
@@ -862,29 +897,42 @@ class SideTable : public ZoneObject {
CLabel* end_label = CLabel::New(&control_transfer_zone, stack_height,
imm.out_arity());
CLabel* catch_label =
- CLabel::New(&control_transfer_zone, stack_height, kCatchInArity);
+ CLabel::New(&control_transfer_zone, stack_height, 0);
control_stack.emplace_back(i.pc(), end_label, catch_label,
imm.out_arity());
exception_stack.push_back(control_stack.size() - 1);
copy_unreachable();
break;
}
+ case kExprRethrow: {
+ BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
+ int index = static_cast<int>(control_stack.size()) - 1 - imm.depth;
+ rethrow_map_.emplace(i.pc() - i.start(), index);
+ break;
+ }
case kExprCatch: {
- DCHECK_EQ(control_stack.size() - 1, exception_stack.back());
+ if (!exception_stack.empty() &&
+ exception_stack.back() == control_stack.size() - 1) {
+ // Only pop the exception stack once when we enter the first catch.
+ exception_stack.pop_back();
+ }
+ ExceptionIndexImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
Control* c = &control_stack.back();
- exception_stack.pop_back();
copy_unreachable();
TRACE("control @%u: Catch\n", i.pc_offset());
- if (!unreachable) {
- c->end_label->Ref(i.pc(), stack_height);
- }
+ if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
+
DCHECK_NOT_NULL(c->else_label);
- c->else_label->Bind(i.pc() + 1);
- c->else_label->Finish(&map_, code->start);
- c->else_label = nullptr;
+ int control_index = static_cast<int>(control_stack.size()) - 1;
+ c->else_label->Bind(i.pc() + imm.length + 1, imm.index,
+ control_index);
+
DCHECK_IMPLIES(!unreachable,
stack_height >= c->end_label->target_stack_height);
- stack_height = c->end_label->target_stack_height + kCatchInArity;
+ const FunctionSig* exception_sig = module->exceptions[imm.index].sig;
+ int catch_in_arity =
+ static_cast<int>(exception_sig->parameter_count());
+ stack_height = c->end_label->target_stack_height + catch_in_arity;
break;
}
case kExprEnd: {
@@ -893,14 +941,73 @@ class SideTable : public ZoneObject {
// Only loops have bound labels.
DCHECK_IMPLIES(c->end_label->target, *c->pc == kExprLoop);
if (!c->end_label->target) {
- if (c->else_label) c->else_label->Bind(i.pc());
+ if (c->else_label) {
+ if (*c->pc == kExprIf) {
+ // Bind else label for one-armed if.
+ c->else_label->Bind(i.pc());
+ } else if (!exception_stack.empty()) {
+ // No catch_all block, prepare for implicit rethrow.
+ DCHECK_EQ(*c->pc, kExprTry);
+ Control* next_try_block =
+ &control_stack[exception_stack.back()];
+ constexpr int kUnusedControlIndex = -1;
+ c->else_label->Bind(i.pc(), kRethrowOrDelegateExceptionIndex,
+ kUnusedControlIndex);
+ if (!unreachable) {
+ next_try_block->else_label->Ref(
+ i.pc(), c->else_label->target_stack_height);
+ }
+ }
+ } else if (c->unwind) {
+ DCHECK_EQ(*c->pc, kExprTry);
+ rethrow_map_.emplace(i.pc() - i.start(),
+ static_cast<int>(control_stack.size()) - 1);
+ if (!exception_stack.empty()) {
+ Control* next_try_block =
+ &control_stack[exception_stack.back()];
+ if (!unreachable) {
+ next_try_block->else_label->Ref(i.pc(), stack_height);
+ }
+ }
+ }
c->end_label->Bind(i.pc() + 1);
}
c->Finish(&map_, code->start);
+
+ DCHECK_IMPLIES(!unreachable,
+ stack_height >= c->end_label->target_stack_height);
+ stack_height = c->end_label->target_stack_height + c->exit_arity;
+ control_stack.pop_back();
+ break;
+ }
+ case kExprDelegate: {
+ BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
+ TRACE("control @%u: Delegate[depth=%u]\n", i.pc_offset(), imm.depth);
+ Control* c = &control_stack.back();
+ const size_t new_stack_size = control_stack.size() - 1;
+ const size_t max_depth = new_stack_size - 1;
+ if (imm.depth < max_depth) {
+ constexpr int kUnusedControlIndex = -1;
+ c->else_label->Bind(i.pc(), kRethrowOrDelegateExceptionIndex,
+ kUnusedControlIndex);
+ c->else_label->Finish(&map_, code->start);
+ Control* target = &control_stack[max_depth - imm.depth];
+ DCHECK_EQ(*target->pc, kExprTry);
+ DCHECK_NOT_NULL(target->else_label);
+ if (!unreachable) {
+ target->else_label->Ref(i.pc(),
+ c->end_label->target_stack_height);
+ }
+ }
+ c->else_label = nullptr;
+ c->end_label->Bind(i.pc() + imm.length + 1);
+ c->Finish(&map_, code->start);
+
DCHECK_IMPLIES(!unreachable,
stack_height >= c->end_label->target_stack_height);
stack_height = c->end_label->target_stack_height + c->exit_arity;
control_stack.pop_back();
+ exception_stack.pop_back();
break;
}
case kExprBr: {
@@ -944,13 +1051,18 @@ class SideTable : public ZoneObject {
}
bool HasEntryAt(pc_t from) {
- auto result = map_.find(from);
- return result != map_.end();
+ auto result = map_.map.find(from);
+ return result != map_.map.end();
+ }
+
+ bool HasCatchEntryAt(pc_t from) {
+ auto result = map_.catch_map.find(from);
+ return result != map_.catch_map.end();
}
ControlTransferEntry& Lookup(pc_t from) {
- auto result = map_.find(from);
- DCHECK(result != map_.end());
+ auto result = map_.map.find(from);
+ DCHECK(result != map_.map.end());
return result->second;
}
};
@@ -1177,18 +1289,28 @@ class WasmInterpreterInternals {
while (!frames_.empty()) {
Frame& frame = frames_.back();
InterpreterCode* code = frame.code;
- if (catchable && code->side_table->HasEntryAt(frame.pc)) {
+ if (catchable && code->side_table->HasCatchEntryAt(frame.pc)) {
TRACE("----- HANDLE -----\n");
- Push(WasmValue(handle(isolate->pending_exception(), isolate)));
- isolate->clear_pending_exception();
- frame.pc += JumpToHandlerDelta(code, frame.pc);
- TRACE(" => handler #%zu (#%u @%zu)\n", frames_.size() - 1,
- code->function->func_index, frame.pc);
- return WasmInterpreter::HANDLED;
+ HandleScope scope(isolate_);
+ Handle<Object> exception =
+ handle(isolate->pending_exception(), isolate);
+ if (JumpToHandlerDelta(code, exception, &frame.pc)) {
+ isolate->clear_pending_exception();
+ TRACE(" => handler #%zu (#%u @%zu)\n", frames_.size() - 1,
+ code->function->func_index, frame.pc);
+ return WasmInterpreter::HANDLED;
+ } else {
+ TRACE(" => no handler #%zu (#%u @%zu)\n", frames_.size() - 1,
+ code->function->func_index, frame.pc);
+ }
}
TRACE(" => drop frame #%zu (#%u @%zu)\n", frames_.size() - 1,
code->function->func_index, frame.pc);
ResetStack(frame.sp);
+ if (!frame.caught_exception_stack.is_null()) {
+ isolate_->global_handles()->Destroy(
+ frame.caught_exception_stack.location());
+ }
frames_.pop_back();
}
TRACE("----- UNWIND -----\n");
@@ -1208,6 +1330,8 @@ class WasmInterpreterInternals {
sp_t plimit() { return sp + code->function->sig->parameter_count(); }
// Limit of locals.
sp_t llimit() { return plimit() + code->locals.type_list.size(); }
+
+ Handle<FixedArray> caught_exception_stack;
};
// Safety wrapper for values on the operand stack represented as {WasmValue}.
@@ -1291,7 +1415,8 @@ class WasmInterpreterInternals {
// The parameters will overlap the arguments already on the stack.
DCHECK_GE(StackHeight(), arity);
- frames_.push_back({code, 0, StackHeight() - arity});
+ frames_.push_back(
+ {code, 0, StackHeight() - arity, Handle<FixedArray>::null()});
frames_.back().pc = InitLocals(code);
TRACE(" => PushFrame #%zu (#%u @%zu)\n", frames_.size() - 1,
code->function->func_index, frames_.back().pc);
@@ -1302,21 +1427,22 @@ class WasmInterpreterInternals {
WasmValue val;
switch (p.kind()) {
#define CASE_TYPE(valuetype, ctype) \
- case ValueType::valuetype: \
+ case valuetype: \
val = WasmValue(ctype{}); \
break;
FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
#undef CASE_TYPE
- case ValueType::kOptRef: {
+ case kOptRef: {
val = WasmValue(isolate_->factory()->null_value());
break;
}
- case ValueType::kRef:
- case ValueType::kRtt: // TODO(7748): Implement.
- case ValueType::kStmt:
- case ValueType::kBottom:
- case ValueType::kI8:
- case ValueType::kI16:
+ case kRef: // TODO(7748): Implement.
+ case kRtt:
+ case kRttWithDepth:
+ case kStmt:
+ case kBottom:
+ case kI8:
+ case kI16:
UNREACHABLE();
break;
}
@@ -1343,11 +1469,51 @@ class WasmInterpreterInternals {
return static_cast<int>(code->side_table->Lookup(pc).pc_diff);
}
- int JumpToHandlerDelta(InterpreterCode* code, pc_t pc) {
- ControlTransferEntry& control_transfer_entry = code->side_table->Lookup(pc);
- DoStackTransfer(control_transfer_entry.sp_diff + kCatchInArity,
- control_transfer_entry.target_arity);
- return control_transfer_entry.pc_diff;
+ bool JumpToHandlerDelta(InterpreterCode* code,
+ Handle<Object> exception_object, pc_t* pc) {
+ auto it = code->side_table->map_.catch_map.find(*pc);
+ if (it == code->side_table->map_.catch_map.end()) {
+ // No handler in this frame means that we should rethrow to the caller.
+ return false;
+ }
+ CatchControlTransferEntry* handler = nullptr;
+ for (auto& entry : it->second) {
+ if (entry.exception_index < 0) {
+ ResetStack(StackHeight() - entry.sp_diff);
+ *pc += entry.pc_diff;
+ if (entry.exception_index == kRethrowOrDelegateExceptionIndex) {
+ // Recursively try to find a handler in the next enclosing try block
+ // (for the implicit rethrow) or in the delegate target.
+ return JumpToHandlerDelta(code, exception_object, pc);
+ }
+ handler = &entry;
+ break;
+ } else if (MatchingExceptionTag(exception_object,
+ entry.exception_index)) {
+ handler = &entry;
+ const WasmException* exception =
+ &module()->exceptions[entry.exception_index];
+ const FunctionSig* sig = exception->sig;
+ int catch_in_arity = static_cast<int>(sig->parameter_count());
+ DoUnpackException(exception, exception_object);
+ DoStackTransfer(entry.sp_diff + catch_in_arity, catch_in_arity);
+ *pc += handler->pc_diff;
+ break;
+ }
+ }
+ if (!handler) return false;
+ if (frames_.back().caught_exception_stack.is_null()) {
+ Handle<FixedArray> caught_exception_stack =
+ isolate_->factory()->NewFixedArray(
+ code->side_table->max_control_stack_height);
+ caught_exception_stack->FillWithHoles(
+ 0, code->side_table->max_control_stack_height);
+ frames_.back().caught_exception_stack =
+ isolate_->global_handles()->Create(*caught_exception_stack);
+ }
+ frames_.back().caught_exception_stack->set(handler->target_control_index,
+ *exception_object);
+ return true;
}
int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
@@ -1378,6 +1544,10 @@ class WasmInterpreterInternals {
size_t arity) {
DCHECK_GT(frames_.size(), 0);
spdiff_t sp_diff = static_cast<spdiff_t>(StackHeight() - frames_.back().sp);
+ if (!frames_.back().caught_exception_stack.is_null()) {
+ isolate_->global_handles()->Destroy(
+ frames_.back().caught_exception_stack.location());
+ }
frames_.pop_back();
if (frames_.empty()) {
// A return from the last frame terminates the execution.
@@ -1401,15 +1571,11 @@ class WasmInterpreterInternals {
// Returns true if the call was successful, false if the stack check failed
// and the stack was fully unwound.
- bool DoCall(Decoder* decoder, InterpreterCode* target, pc_t* pc,
+ bool DoCall(Decoder* decoder, InterpreterCode** target, pc_t* pc,
pc_t* limit) V8_WARN_UNUSED_RESULT {
frames_.back().pc = *pc;
- PushFrame(target);
- if (!DoStackCheck()) return false;
- *pc = frames_.back().pc;
- *limit = target->end - target->start;
- decoder->Reset(target->start, target->end);
- return true;
+ PushFrame(*target);
+ return DoStackCheck(decoder, target, pc, limit);
}
// Returns true if the tail call was successful, false if the stack check
@@ -1632,28 +1798,28 @@ class WasmInterpreterInternals {
InterpreterCode* code, pc_t pc, int* const len) {
switch (opcode) {
case kExprI32SConvertSatF32:
- Push(WasmValue(ExecuteConvertSaturate<int32_t>(Pop().to<float>())));
+ Push(WasmValue(base::saturated_cast<int32_t>(Pop().to<float>())));
return true;
case kExprI32UConvertSatF32:
- Push(WasmValue(ExecuteConvertSaturate<uint32_t>(Pop().to<float>())));
+ Push(WasmValue(base::saturated_cast<uint32_t>(Pop().to<float>())));
return true;
case kExprI32SConvertSatF64:
- Push(WasmValue(ExecuteConvertSaturate<int32_t>(Pop().to<double>())));
+ Push(WasmValue(base::saturated_cast<int32_t>(Pop().to<double>())));
return true;
case kExprI32UConvertSatF64:
- Push(WasmValue(ExecuteConvertSaturate<uint32_t>(Pop().to<double>())));
+ Push(WasmValue(base::saturated_cast<uint32_t>(Pop().to<double>())));
return true;
case kExprI64SConvertSatF32:
- Push(WasmValue(ExecuteI64SConvertSatF32(Pop().to<float>())));
+ Push(WasmValue(base::saturated_cast<int64_t>(Pop().to<float>())));
return true;
case kExprI64UConvertSatF32:
- Push(WasmValue(ExecuteI64UConvertSatF32(Pop().to<float>())));
+ Push(WasmValue(base::saturated_cast<uint64_t>(Pop().to<float>())));
return true;
case kExprI64SConvertSatF64:
- Push(WasmValue(ExecuteI64SConvertSatF64(Pop().to<double>())));
+ Push(WasmValue(base::saturated_cast<int64_t>(Pop().to<double>())));
return true;
case kExprI64UConvertSatF64:
- Push(WasmValue(ExecuteI64UConvertSatF64(Pop().to<double>())));
+ Push(WasmValue(base::saturated_cast<uint64_t>(Pop().to<double>())));
return true;
case kExprMemoryInit: {
MemoryInitImmediate<Decoder::kNoValidation> imm(decoder,
@@ -2284,6 +2450,8 @@ class WasmInterpreterInternals {
(AixFpOpWorkaround<float, &nearbyintf>(a)))
UNOP_CASE(I64x2Neg, i64x2, int2, 2, base::NegateWithWraparound(a))
UNOP_CASE(I32x4Neg, i32x4, int4, 4, base::NegateWithWraparound(a))
+ // Use llabs which will work correctly on both 64-bit and 32-bit.
+ UNOP_CASE(I64x2Abs, i64x2, int2, 2, std::llabs(a))
UNOP_CASE(I32x4Abs, i32x4, int4, 4, std::abs(a))
UNOP_CASE(S128Not, i32x4, int4, 4, ~a)
UNOP_CASE(I16x8Neg, i16x8, int8, 8, base::NegateWithWraparound(a))
@@ -2344,6 +2512,11 @@ class WasmInterpreterInternals {
CMPOP_CASE(F32x4Lt, f32x4, float4, int4, 4, a < b)
CMPOP_CASE(F32x4Le, f32x4, float4, int4, 4, a <= b)
CMPOP_CASE(I64x2Eq, i64x2, int2, int2, 2, a == b)
+ CMPOP_CASE(I64x2Ne, i64x2, int2, int2, 2, a != b)
+ CMPOP_CASE(I64x2LtS, i64x2, int2, int2, 2, a < b)
+ CMPOP_CASE(I64x2GtS, i64x2, int2, int2, 2, a > b)
+ CMPOP_CASE(I64x2LeS, i64x2, int2, int2, 2, a <= b)
+ CMPOP_CASE(I64x2GeS, i64x2, int2, int2, 2, a >= b)
CMPOP_CASE(I32x4Eq, i32x4, int4, int4, 4, a == b)
CMPOP_CASE(I32x4Ne, i32x4, int4, int4, 4, a != b)
CMPOP_CASE(I32x4GtS, i32x4, int4, int4, 4, a > b)
@@ -2489,7 +2662,7 @@ class WasmInterpreterInternals {
case kExpr##op: { \
WasmValue v = Pop(); \
src_type s = v.to_s128().to_##name(); \
- dst_type res; \
+ dst_type res = {0}; \
for (size_t i = 0; i < count; ++i) { \
ctype a = s.val[LANE(start_index + i, s)]; \
auto result = expr; \
@@ -2534,29 +2707,38 @@ class WasmInterpreterInternals {
CONVERT_CASE(I16x8SConvertI8x16Low, int16, i8x16, int8, 8, 0, int8_t, a)
CONVERT_CASE(I16x8UConvertI8x16Low, int16, i8x16, int8, 8, 0, uint8_t,
a)
+ CONVERT_CASE(F64x2ConvertLowI32x4S, int4, i32x4, float2, 2, 0, int32_t,
+ static_cast<double>(a))
+ CONVERT_CASE(F64x2ConvertLowI32x4U, int4, i32x4, float2, 2, 0, uint32_t,
+ static_cast<double>(a))
+ CONVERT_CASE(I32x4TruncSatF64x2SZero, float2, f64x2, int4, 2, 0, double,
+ base::saturated_cast<int32_t>(a))
+ CONVERT_CASE(I32x4TruncSatF64x2UZero, float2, f64x2, int4, 2, 0, double,
+ base::saturated_cast<uint32_t>(a))
+ CONVERT_CASE(F32x4DemoteF64x2Zero, float2, f64x2, float4, 2, 0, float,
+ DoubleToFloat32(a))
+ CONVERT_CASE(F64x2PromoteLowF32x4, float4, f32x4, float2, 2, 0, float,
+ static_cast<double>(a))
#undef CONVERT_CASE
-#define PACK_CASE(op, src_type, name, dst_type, count, ctype, dst_ctype) \
- case kExpr##op: { \
- WasmValue v2 = Pop(); \
- WasmValue v1 = Pop(); \
- src_type s1 = v1.to_s128().to_##name(); \
- src_type s2 = v2.to_s128().to_##name(); \
- dst_type res; \
- int64_t min = std::numeric_limits<ctype>::min(); \
- int64_t max = std::numeric_limits<ctype>::max(); \
- for (size_t i = 0; i < count; ++i) { \
- int64_t v = i < count / 2 ? s1.val[LANE(i, s1)] \
- : s2.val[LANE(i - count / 2, s2)]; \
- res.val[LANE(i, res)] = \
- static_cast<dst_ctype>(std::max(min, std::min(max, v))); \
- } \
- Push(WasmValue(Simd128(res))); \
- return true; \
+#define PACK_CASE(op, src_type, name, dst_type, count, dst_ctype) \
+ case kExpr##op: { \
+ WasmValue v2 = Pop(); \
+ WasmValue v1 = Pop(); \
+ src_type s1 = v1.to_s128().to_##name(); \
+ src_type s2 = v2.to_s128().to_##name(); \
+ dst_type res; \
+ for (size_t i = 0; i < count; ++i) { \
+ int64_t v = i < count / 2 ? s1.val[LANE(i, s1)] \
+ : s2.val[LANE(i - count / 2, s2)]; \
+ res.val[LANE(i, res)] = base::saturated_cast<dst_ctype>(v); \
+ } \
+ Push(WasmValue(Simd128(res))); \
+ return true; \
}
- PACK_CASE(I16x8SConvertI32x4, int4, i32x4, int8, 8, int16_t, int16_t)
- PACK_CASE(I16x8UConvertI32x4, int4, i32x4, int8, 8, uint16_t, int16_t)
- PACK_CASE(I8x16SConvertI16x8, int8, i16x8, int16, 16, int8_t, int8_t)
- PACK_CASE(I8x16UConvertI16x8, int8, i16x8, int16, 16, uint8_t, int8_t)
+ PACK_CASE(I16x8SConvertI32x4, int4, i32x4, int8, 8, int16_t)
+ PACK_CASE(I16x8UConvertI32x4, int4, i32x4, int8, 8, uint16_t)
+ PACK_CASE(I8x16SConvertI16x8, int8, i16x8, int16, 16, int8_t)
+ PACK_CASE(I8x16UConvertI16x8, int8, i16x8, int16, 16, uint8_t)
#undef PACK_CASE
case kExprS128Select: {
int4 bool_val = Pop().to_s128().to_i32x4();
@@ -2645,9 +2827,7 @@ class WasmInterpreterInternals {
Push(WasmValue(Simd128(res)));
return true;
}
- case kExprV32x4AnyTrue:
- case kExprV16x8AnyTrue:
- case kExprV8x16AnyTrue: {
+ case kExprV128AnyTrue: {
int4 s = Pop().to_s128().to_i32x4();
bool res = s.val[LANE(0, s)] | s.val[LANE(1, s)] | s.val[LANE(2, s)] |
s.val[LANE(3, s)];
@@ -2664,6 +2844,7 @@ class WasmInterpreterInternals {
Push(WasmValue(res)); \
return true; \
}
+ REDUCTION_CASE(V64x2AllTrue, i64x2, int2, 2, &)
REDUCTION_CASE(V32x4AllTrue, i32x4, int4, 4, &)
REDUCTION_CASE(V16x8AllTrue, i16x8, int8, 8, &)
REDUCTION_CASE(V8x16AllTrue, i8x16, int16, 16, &)
@@ -2955,7 +3136,8 @@ class WasmInterpreterInternals {
// Returns true if execution can continue, false if the stack was fully
// unwound. Do call this function immediately *after* pushing a new frame. The
// pc of the top frame will be reset to 0 if the stack check fails.
- bool DoStackCheck() V8_WARN_UNUSED_RESULT {
+ bool DoStackCheck(Decoder* decoder, InterpreterCode** target, pc_t* pc,
+ pc_t* limit) V8_WARN_UNUSED_RESULT {
// The goal of this stack check is not to prevent actual stack overflows,
// but to simulate stack overflows during the execution of compiled code.
// That is why this function uses FLAG_stack_size, even though the value
@@ -2965,13 +3147,20 @@ class WasmInterpreterInternals {
const size_t current_stack_size = (sp_ - stack_.get()) * sizeof(*sp_) +
frames_.size() * sizeof(frames_[0]);
if (V8_LIKELY(current_stack_size <= stack_size_limit)) {
+ *pc = frames_.back().pc;
+ *limit = (*target)->end - (*target)->start;
+ decoder->Reset((*target)->start, (*target)->end);
return true;
}
// The pc of the top frame is initialized to the first instruction. We reset
// it to 0 here such that we report the same position as in compiled code.
frames_.back().pc = 0;
isolate_->StackOverflow();
- return HandleException(isolate_) == WasmInterpreter::HANDLED;
+ if (HandleException(isolate_) == WasmInterpreter::HANDLED) {
+ ReloadFromFrameOnException(decoder, target, pc, limit);
+ return true;
+ }
+ return false;
}
void EncodeI32ExceptionValue(Handle<FixedArray> encoded_values,
@@ -3011,27 +3200,27 @@ class WasmInterpreterInternals {
for (size_t i = 0; i < sig->parameter_count(); ++i) {
WasmValue value = GetStackValue(base_index + i);
switch (sig->GetParam(i).kind()) {
- case ValueType::kI32: {
+ case kI32: {
uint32_t u32 = value.to_u32();
EncodeI32ExceptionValue(encoded_values, &encoded_index, u32);
break;
}
- case ValueType::kF32: {
+ case kF32: {
uint32_t f32 = value.to_f32_boxed().get_bits();
EncodeI32ExceptionValue(encoded_values, &encoded_index, f32);
break;
}
- case ValueType::kI64: {
+ case kI64: {
uint64_t u64 = value.to_u64();
EncodeI64ExceptionValue(encoded_values, &encoded_index, u64);
break;
}
- case ValueType::kF64: {
+ case kF64: {
uint64_t f64 = value.to_f64_boxed().get_bits();
EncodeI64ExceptionValue(encoded_values, &encoded_index, f64);
break;
}
- case ValueType::kS128: {
+ case kS128: {
int4 s128 = value.to_s128().to_i32x4();
EncodeI32ExceptionValue(encoded_values, &encoded_index, s128.val[0]);
EncodeI32ExceptionValue(encoded_values, &encoded_index, s128.val[1]);
@@ -3039,18 +3228,21 @@ class WasmInterpreterInternals {
EncodeI32ExceptionValue(encoded_values, &encoded_index, s128.val[3]);
break;
}
- case ValueType::kRef:
- case ValueType::kOptRef: {
+ case kRef:
+ case kOptRef: {
switch (sig->GetParam(i).heap_representation()) {
case HeapType::kExtern:
- case HeapType::kExn:
case HeapType::kFunc:
case HeapType::kAny: {
Handle<Object> externref = value.to_externref();
encoded_values->set(encoded_index++, *externref);
break;
}
+ case HeapType::kBottom:
+ UNREACHABLE();
case HeapType::kEq:
+ case HeapType::kData:
+ case HeapType::kI31:
default:
// TODO(7748): Implement these.
UNIMPLEMENTED();
@@ -3058,11 +3250,12 @@ class WasmInterpreterInternals {
}
break;
}
- case ValueType::kRtt: // TODO(7748): Implement.
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kStmt:
- case ValueType::kBottom:
+ case kRtt: // TODO(7748): Implement.
+ case kRttWithDepth:
+ case kI8:
+ case kI16:
+ case kStmt:
+ case kBottom:
UNREACHABLE();
}
}
@@ -3075,8 +3268,8 @@ class WasmInterpreterInternals {
// Throw a given existing exception. Returns true if the exception is being
// handled locally by the interpreter, false otherwise (interpreter exits).
- bool DoRethrowException(WasmValue exception) {
- isolate_->ReThrow(*exception.to_externref());
+ bool DoRethrowException(Handle<Object> exception) {
+ isolate_->ReThrow(*exception);
return HandleException(isolate_) == WasmInterpreter::HANDLED;
}
@@ -3123,31 +3316,31 @@ class WasmInterpreterInternals {
for (size_t i = 0; i < sig->parameter_count(); ++i) {
WasmValue value;
switch (sig->GetParam(i).kind()) {
- case ValueType::kI32: {
+ case kI32: {
uint32_t u32 = 0;
DecodeI32ExceptionValue(encoded_values, &encoded_index, &u32);
value = WasmValue(u32);
break;
}
- case ValueType::kF32: {
+ case kF32: {
uint32_t f32_bits = 0;
DecodeI32ExceptionValue(encoded_values, &encoded_index, &f32_bits);
value = WasmValue(Float32::FromBits(f32_bits));
break;
}
- case ValueType::kI64: {
+ case kI64: {
uint64_t u64 = 0;
DecodeI64ExceptionValue(encoded_values, &encoded_index, &u64);
value = WasmValue(u64);
break;
}
- case ValueType::kF64: {
+ case kF64: {
uint64_t f64_bits = 0;
DecodeI64ExceptionValue(encoded_values, &encoded_index, &f64_bits);
value = WasmValue(Float64::FromBits(f64_bits));
break;
}
- case ValueType::kS128: {
+ case kS128: {
int4 s128 = {0, 0, 0, 0};
uint32_t* vals = reinterpret_cast<uint32_t*>(s128.val);
DecodeI32ExceptionValue(encoded_values, &encoded_index, &vals[0]);
@@ -3157,11 +3350,10 @@ class WasmInterpreterInternals {
value = WasmValue(Simd128(s128));
break;
}
- case ValueType::kRef:
- case ValueType::kOptRef: {
+ case kRef:
+ case kOptRef: {
switch (sig->GetParam(i).heap_representation()) {
case HeapType::kExtern:
- case HeapType::kExn:
case HeapType::kFunc:
case HeapType::kAny: {
Handle<Object> externref(encoded_values->get(encoded_index++),
@@ -3176,11 +3368,12 @@ class WasmInterpreterInternals {
}
break;
}
- case ValueType::kRtt: // TODO(7748): Implement.
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kStmt:
- case ValueType::kBottom:
+ case kRtt: // TODO(7748): Implement.
+ case kRttWithDepth:
+ case kI8:
+ case kI16:
+ case kStmt:
+ case kBottom:
UNREACHABLE();
}
Push(value);
@@ -3258,7 +3451,7 @@ class WasmInterpreterInternals {
WasmValue cond = Pop();
bool is_true = cond.to<uint32_t>() != 0;
if (is_true) {
- // fall through to the true block.
+ // Fall through to the true block.
len = 1 + imm.length;
TRACE(" true => fallthrough\n");
} else {
@@ -3268,7 +3461,9 @@ class WasmInterpreterInternals {
break;
}
case kExprElse:
- case kExprCatch: {
+ case kExprUnwind:
+ case kExprCatch:
+ case kExprCatchAll: {
len = LookupTargetDelta(code, pc);
TRACE(" end => @%zu\n", pc + len);
break;
@@ -3283,13 +3478,18 @@ class WasmInterpreterInternals {
continue; // Do not bump pc.
}
case kExprRethrow: {
- HandleScope handle_scope(isolate_); // Avoid leaking handles.
- WasmValue ex = Pop();
- if (ex.to_externref()->IsNull()) {
- return DoTrap(kTrapRethrowNull, pc);
- }
+ BranchDepthImmediate<Decoder::kNoValidation> imm(&decoder,
+ code->at(pc + 1));
+ HandleScope scope(isolate_); // Avoid leaking handles.
+ DCHECK(!frames_.back().caught_exception_stack.is_null());
+ int index = code->side_table->rethrow_map_[pc];
+ DCHECK_LE(0, index);
+ DCHECK_LT(index, frames_.back().caught_exception_stack->Size());
+ Handle<Object> exception = handle(
+ frames_.back().caught_exception_stack->get(index), isolate_);
+ DCHECK(!exception->IsTheHole());
CommitPc(pc); // Needed for local unwinding.
- if (!DoRethrowException(ex)) return;
+ if (!DoRethrowException(exception)) return;
ReloadFromFrameOnException(&decoder, &code, &pc, &limit);
continue; // Do not bump pc.
}
@@ -3351,7 +3551,26 @@ class WasmInterpreterInternals {
case kExprUnreachable: {
return DoTrap(kTrapUnreachable, pc);
}
+ case kExprDelegate: {
+ BranchDepthImmediate<Decoder::kNoValidation> imm(&decoder,
+ code->at(pc + 1));
+ len = 1 + imm.length;
+ break;
+ }
case kExprEnd: {
+ if (code->side_table->rethrow_map_.count(pc)) {
+ // Implicit rethrow after unwind.
+ HandleScope scope(isolate_);
+ DCHECK(!frames_.back().caught_exception_stack.is_null());
+ int index = code->side_table->rethrow_map_[pc];
+ Handle<Object> exception = handle(
+ frames_.back().caught_exception_stack->get(index), isolate_);
+ DCHECK(!exception->IsTheHole());
+ CommitPc(pc); // Needed for local unwinding.
+ if (!DoRethrowException(exception)) return;
+ ReloadFromFrameOnException(&decoder, &code, &pc, &limit);
+ continue; // Do not bump pc.
+ }
break;
}
case kExprI32Const: {
@@ -3438,7 +3657,7 @@ class WasmInterpreterInternals {
InterpreterCode* target = codemap_.GetCode(imm.index);
CHECK(!target->function->imported);
// Execute an internal call.
- if (!DoCall(&decoder, target, &pc, &limit)) return;
+ if (!DoCall(&decoder, &target, &pc, &limit)) return;
code = target;
continue; // Do not bump pc.
} break;
@@ -3453,7 +3672,7 @@ class WasmInterpreterInternals {
switch (result.type) {
case CallResult::INTERNAL:
// The import is a function of this instance. Call it directly.
- if (!DoCall(&decoder, result.interpreter_code, &pc, &limit))
+ if (!DoCall(&decoder, &result.interpreter_code, &pc, &limit))
return;
code = result.interpreter_code;
continue; // Do not bump pc.
@@ -3525,7 +3744,7 @@ class WasmInterpreterInternals {
auto& global = module()->globals[imm.index];
switch (global.type.kind()) {
#define CASE_TYPE(valuetype, ctype) \
- case ValueType::valuetype: { \
+ case valuetype: { \
uint8_t* ptr = \
WasmInstanceObject::GetGlobalStorage(instance_object_, global); \
WriteLittleEndianValue<ctype>(reinterpret_cast<Address>(ptr), \
@@ -3534,8 +3753,8 @@ class WasmInterpreterInternals {
}
FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
#undef CASE_TYPE
- case ValueType::kRef:
- case ValueType::kOptRef: {
+ case kRef:
+ case kOptRef: {
// TODO(7748): Type checks or DCHECKs for ref types?
HandleScope handle_scope(isolate_); // Avoid leaking handles.
Handle<FixedArray> global_buffer; // The buffer of the global.
@@ -3547,11 +3766,12 @@ class WasmInterpreterInternals {
global_buffer->set(global_index, *ref);
break;
}
- case ValueType::kRtt: // TODO(7748): Implement.
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kStmt:
- case ValueType::kBottom:
+ case kRtt: // TODO(7748): Implement.
+ case kRttWithDepth:
+ case kI8:
+ case kI16:
+ case kStmt:
+ case kBottom:
UNREACHABLE();
}
len = 1 + imm.length;
@@ -3920,19 +4140,19 @@ class WasmInterpreterInternals {
}
WasmValue val = GetStackValue(i);
switch (val.type().kind()) {
- case ValueType::kI32:
+ case kI32:
PrintF("i32:%d", val.to<int32_t>());
break;
- case ValueType::kI64:
+ case kI64:
PrintF("i64:%" PRId64 "", val.to<int64_t>());
break;
- case ValueType::kF32:
+ case kF32:
PrintF("f32:%a", val.to<float>());
break;
- case ValueType::kF64:
+ case kF64:
PrintF("f64:%la", val.to<double>());
break;
- case ValueType::kS128: {
+ case kS128: {
// This defaults to tracing all S128 values as i32x4 values for now,
// when there is more state to know what type of values are on the
// stack, the right format should be printed here.
@@ -3940,11 +4160,11 @@ class WasmInterpreterInternals {
PrintF("i32x4:%d,%d,%d,%d", s.val[0], s.val[1], s.val[2], s.val[3]);
break;
}
- case ValueType::kStmt:
+ case kStmt:
PrintF("void");
break;
- case ValueType::kRef:
- case ValueType::kOptRef: {
+ case kRef:
+ case kOptRef: {
if (val.type().is_reference_to(HeapType::kExtern)) {
Handle<Object> ref = val.to_externref();
if (ref->IsNull()) {
@@ -3958,13 +4178,14 @@ class WasmInterpreterInternals {
}
break;
}
- case ValueType::kRtt:
+ case kRtt:
+ case kRttWithDepth:
// TODO(7748): Implement properly.
PrintF("rtt");
break;
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kBottom:
+ case kI8:
+ case kI16:
+ case kBottom:
UNREACHABLE();
break;
}
diff --git a/deps/v8/test/common/wasm/wasm-interpreter.h b/deps/v8/test/common/wasm/wasm-interpreter.h
index 4df373df46..ab89f5dc15 100644
--- a/deps/v8/test/common/wasm/wasm-interpreter.h
+++ b/deps/v8/test/common/wasm/wasm-interpreter.h
@@ -39,7 +39,17 @@ struct ControlTransferEntry {
uint32_t target_arity;
};
-using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;
+struct CatchControlTransferEntry : public ControlTransferEntry {
+ int exception_index;
+ int target_control_index;
+};
+
+struct ControlTransferMap {
+ explicit ControlTransferMap(Zone* zone) : map(zone), catch_map(zone) {}
+
+ ZoneMap<pc_t, ControlTransferEntry> map;
+ ZoneMap<pc_t, ZoneVector<CatchControlTransferEntry>> catch_map;
+};
// An interpreter capable of executing WebAssembly.
class WasmInterpreter {
diff --git a/deps/v8/test/common/wasm/wasm-macro-gen.h b/deps/v8/test/common/wasm/wasm-macro-gen.h
index 106d330913..7ddc32fc89 100644
--- a/deps/v8/test/common/wasm/wasm-macro-gen.h
+++ b/deps/v8/test/common/wasm/wasm-macro-gen.h
@@ -113,8 +113,8 @@
#define WASM_HEAP_TYPE(heap_type) static_cast<byte>((heap_type).code() & 0x7f)
-#define WASM_REF_TYPE(type) \
- (type).kind() == ValueType::kRef ? kRefCode : kOptRefCode, \
+#define WASM_REF_TYPE(type) \
+ (type).kind() == kRef ? kRefCode : kOptRefCode, \
WASM_HEAP_TYPE((type).heap_type())
#define WASM_BLOCK(...) kExprBlock, kVoidCode, __VA_ARGS__, kExprEnd
@@ -183,6 +183,10 @@
#define WASM_TRY_CATCH_T(t, trystmt, catchstmt, except) \
kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprCatch, \
except, catchstmt, kExprEnd
+#define WASM_TRY_CATCH_CATCH_T(t, trystmt, except1, catchstmt1, except2, \
+ catchstmt2) \
+ kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprCatch, \
+ except1, catchstmt1, kExprCatch, except2, catchstmt2, kExprEnd
#define WASM_TRY_CATCH_R(t, trystmt, catchstmt) \
kExprTry, WASM_REF_TYPE(t), trystmt, kExprCatch, catchstmt, kExprEnd
#define WASM_TRY_CATCH_ALL_T(t, trystmt, catchstmt) \
@@ -190,6 +194,12 @@
catchstmt, kExprEnd
#define WASM_TRY_DELEGATE(trystmt, depth) \
kExprTry, kVoidCode, trystmt, kExprDelegate, depth
+#define WASM_TRY_DELEGATE_T(t, trystmt, depth) \
+ kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprDelegate, \
+ depth
+#define WASM_TRY_UNWIND_T(t, trystmt, unwindstmt) \
+ kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprUnwind, \
+ unwindstmt, kExprEnd
#define WASM_SELECT(tval, fval, cond) tval, fval, cond, kExprSelect
#define WASM_SELECT_I(tval, fval, cond) \
@@ -215,6 +225,7 @@
val, cond, kExprBrIf, static_cast<byte>(depth), kExprDrop
#define WASM_CONTINUE(depth) kExprBr, static_cast<byte>(depth)
#define WASM_UNREACHABLE kExprUnreachable
+#define WASM_RETURN(...) __VA_ARGS__, kExprReturn
#define WASM_BR_TABLE(key, count, ...) \
key, kExprBrTable, U32V_1(count), __VA_ARGS__
@@ -464,6 +475,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
index, val, \
static_cast<byte>(v8::internal::wasm::LoadStoreOpcodeOf(type, true)), \
alignment, ZERO_OFFSET
+#define WASM_RETHROW(index) kExprRethrow, static_cast<byte>(index)
#define WASM_CALL_FUNCTION0(index) kExprCallFunction, static_cast<byte>(index)
#define WASM_CALL_FUNCTION(index, ...) \
@@ -497,19 +509,30 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
struct_obj, value, WASM_GC_OP(kExprStructSet), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
#define WASM_REF_NULL(type_encoding) kExprRefNull, type_encoding
-#define WASM_REF_FUNC(val) kExprRefFunc, val
+#define WASM_REF_FUNC(index) kExprRefFunc, index
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
#define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
-#define WASM_REF_TEST(obj_type, rtt_type, ref, rtt) \
- ref, rtt, WASM_GC_OP(kExprRefTest), obj_type, rtt_type
-#define WASM_REF_CAST(obj_type, rtt_type, ref, rtt) \
- ref, rtt, WASM_GC_OP(kExprRefCast), obj_type, rtt_type
+#define WASM_REF_TEST(ref, rtt) ref, rtt, WASM_GC_OP(kExprRefTest)
+#define WASM_REF_CAST(ref, rtt) ref, rtt, WASM_GC_OP(kExprRefCast)
// Takes a reference value from the value stack to allow sequences of
// conditional branches.
#define WASM_BR_ON_CAST(depth, rtt) \
rtt, WASM_GC_OP(kExprBrOnCast), static_cast<byte>(depth)
+#define WASM_REF_IS_DATA(ref) ref, WASM_GC_OP(kExprRefIsData)
+#define WASM_REF_AS_DATA(ref) ref, WASM_GC_OP(kExprRefAsData)
+#define WASM_BR_ON_DATA(depth, ref) \
+ ref, WASM_GC_OP(kExprBrOnData), static_cast<byte>(depth)
+#define WASM_REF_IS_FUNC(ref) ref, WASM_GC_OP(kExprRefIsFunc)
+#define WASM_REF_AS_FUNC(ref) ref, WASM_GC_OP(kExprRefAsFunc)
+#define WASM_BR_ON_FUNC(depth, ref) \
+ ref, WASM_GC_OP(kExprBrOnFunc), static_cast<byte>(depth)
+#define WASM_REF_IS_I31(ref) ref, WASM_GC_OP(kExprRefIsI31)
+#define WASM_REF_AS_I31(ref) ref, WASM_GC_OP(kExprRefAsI31)
+#define WASM_BR_ON_I31(depth, ref) \
+ ref, WASM_GC_OP(kExprBrOnI31), static_cast<byte>(depth)
+
#define WASM_ARRAY_NEW_WITH_RTT(index, default_value, length, rtt) \
default_value, length, rtt, WASM_GC_OP(kExprArrayNewWithRtt), \
static_cast<byte>(index)
@@ -526,7 +549,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_ARRAY_LEN(typeidx, array) \
array, WASM_GC_OP(kExprArrayLen), static_cast<byte>(typeidx)
-#define WASM_RTT(depth, typeidx) kRttCode, U32V_1(depth), U32V_1(typeidx)
+#define WASM_RTT_WITH_DEPTH(depth, typeidx) \
+ kRttWithDepthCode, U32V_1(depth), U32V_1(typeidx)
+#define WASM_RTT(typeidx) kRttCode, U32V_1(typeidx)
#define WASM_RTT_CANON(typeidx) \
WASM_GC_OP(kExprRttCanon), static_cast<byte>(typeidx)
#define WASM_RTT_SUB(typeidx, supertype) \
diff --git a/deps/v8/test/common/wasm/wasm-module-runner.cc b/deps/v8/test/common/wasm/wasm-module-runner.cc
index f9ef2e6708..c74d0ec56c 100644
--- a/deps/v8/test/common/wasm/wasm-module-runner.cc
+++ b/deps/v8/test/common/wasm/wasm-module-runner.cc
@@ -49,31 +49,32 @@ OwnedVector<WasmValue> MakeDefaultInterpreterArguments(Isolate* isolate,
for (size_t i = 0; i < param_count; ++i) {
switch (sig->GetParam(i).kind()) {
- case ValueType::kI32:
+ case kI32:
arguments[i] = WasmValue(int32_t{0});
break;
- case ValueType::kI64:
+ case kI64:
arguments[i] = WasmValue(int64_t{0});
break;
- case ValueType::kF32:
+ case kF32:
arguments[i] = WasmValue(0.0f);
break;
- case ValueType::kF64:
+ case kF64:
arguments[i] = WasmValue(0.0);
break;
- case ValueType::kS128:
+ case kS128:
arguments[i] = WasmValue(Simd128{});
break;
- case ValueType::kOptRef:
+ case kOptRef:
arguments[i] =
WasmValue(Handle<Object>::cast(isolate->factory()->null_value()));
break;
- case ValueType::kRef:
- case ValueType::kRtt:
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kStmt:
- case ValueType::kBottom:
+ case kRef:
+ case kRtt:
+ case kRttWithDepth:
+ case kI8:
+ case kI16:
+ case kStmt:
+ case kBottom:
UNREACHABLE();
}
}
@@ -88,26 +89,27 @@ OwnedVector<Handle<Object>> MakeDefaultArguments(Isolate* isolate,
for (size_t i = 0; i < param_count; ++i) {
switch (sig->GetParam(i).kind()) {
- case ValueType::kI32:
- case ValueType::kF32:
- case ValueType::kF64:
- case ValueType::kS128:
+ case kI32:
+ case kF32:
+ case kF64:
+ case kS128:
// Argument here for kS128 does not matter as we should error out before
// hitting this case.
arguments[i] = handle(Smi::zero(), isolate);
break;
- case ValueType::kI64:
+ case kI64:
arguments[i] = BigInt::FromInt64(isolate, 0);
break;
- case ValueType::kOptRef:
+ case kOptRef:
arguments[i] = isolate->factory()->null_value();
break;
- case ValueType::kRef:
- case ValueType::kRtt:
- case ValueType::kI8:
- case ValueType::kI16:
- case ValueType::kStmt:
- case ValueType::kBottom:
+ case kRef:
+ case kRtt:
+ case kRttWithDepth:
+ case kI8:
+ case kI16:
+ case kStmt:
+ case kBottom:
UNREACHABLE();
}
}
@@ -169,16 +171,16 @@ WasmInterpretationResult InterpretWasmModule(
if (func->sig->return_count() > 0) {
WasmValue return_value = interpreter.GetReturnValue();
switch (func->sig->GetReturn(0).kind()) {
- case ValueType::kI32:
+ case kI32:
result = return_value.to<int32_t>();
break;
- case ValueType::kI64:
+ case kI64:
result = static_cast<int32_t>(return_value.to<int64_t>());
break;
- case ValueType::kF32:
+ case kF32:
result = static_cast<int32_t>(return_value.to<float>());
break;
- case ValueType::kF64:
+ case kF64:
result = static_cast<int32_t>(return_value.to<double>());
break;
default: