summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/function-body-decoder-impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/wasm/function-body-decoder-impl.h')
-rw-r--r--deps/v8/src/wasm/function-body-decoder-impl.h906
1 files changed, 460 insertions, 446 deletions
diff --git a/deps/v8/src/wasm/function-body-decoder-impl.h b/deps/v8/src/wasm/function-body-decoder-impl.h
index 0d3517c554..5b7201abb6 100644
--- a/deps/v8/src/wasm/function-body-decoder-impl.h
+++ b/deps/v8/src/wasm/function-body-decoder-impl.h
@@ -183,21 +183,6 @@ void DecodeError(Decoder* decoder, const char* str) {
namespace value_type_reader {
-V8_INLINE WasmFeature feature_for_heap_type(HeapType heap_type) {
- switch (heap_type.representation()) {
- case HeapType::kFunc:
- case HeapType::kExtern:
- return WasmFeature::kFeature_reftypes;
- case HeapType::kEq:
- case HeapType::kI31:
- case HeapType::kData:
- case HeapType::kAny:
- return WasmFeature::kFeature_gc;
- case HeapType::kBottom:
- UNREACHABLE();
- }
-}
-
// If {module} is not null, the read index will be checked against the module's
// type capacity.
template <Decoder::ValidateFlag validate>
@@ -215,29 +200,27 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
uint8_t uint_7_mask = 0x7F;
uint8_t code = static_cast<ValueTypeCode>(heap_index) & uint_7_mask;
switch (code) {
- case kFuncRefCode:
case kEqRefCode:
- case kExternRefCode:
case kI31RefCode:
case kDataRefCode:
- case kAnyRefCode: {
- HeapType result = HeapType::from_code(code);
- if (!VALIDATE(enabled.contains(feature_for_heap_type(result)))) {
+ case kArrayRefCode:
+ case kAnyRefCodeAlias:
+ if (!VALIDATE(enabled.has_gc())) {
DecodeError<validate>(
decoder, pc,
- "invalid heap type '%s', enable with --experimental-wasm-%s",
- result.name().c_str(),
- WasmFeatures::name_for_feature(feature_for_heap_type(result)));
+ "invalid heap type '%s', enable with --experimental-wasm-gc",
+ HeapType::from_code(code).name().c_str());
return HeapType(HeapType::kBottom);
}
- return result;
- }
+ V8_FALLTHROUGH;
+ case kAnyRefCode:
+ case kFuncRefCode:
+ return HeapType::from_code(code);
default:
DecodeError<validate>(decoder, pc, "Unknown heap type %" PRId64,
heap_index);
return HeapType(HeapType::kBottom);
}
- UNREACHABLE();
} else {
if (!VALIDATE(enabled.has_typed_funcref())) {
DecodeError<validate>(decoder, pc,
@@ -264,6 +247,9 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
}
}
+HeapType consume_heap_type(Decoder* decoder, const WasmModule* module,
+ const WasmFeatures& enabled);
+
// Read a value type starting at address {pc} using {decoder}.
// No bytes are consumed.
// The length of the read value type is written in {length}.
@@ -281,26 +267,27 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
}
ValueTypeCode code = static_cast<ValueTypeCode>(val);
switch (code) {
- case kFuncRefCode:
case kEqRefCode:
- case kExternRefCode:
case kI31RefCode:
case kDataRefCode:
- case kAnyRefCode: {
- HeapType heap_type = HeapType::from_code(code);
- Nullability nullability = code == kI31RefCode || code == kDataRefCode
- ? kNonNullable
- : kNullable;
- ValueType result = ValueType::Ref(heap_type, nullability);
- if (!VALIDATE(enabled.contains(feature_for_heap_type(heap_type)))) {
+ case kArrayRefCode:
+ case kAnyRefCodeAlias:
+ if (!VALIDATE(enabled.has_gc())) {
DecodeError<validate>(
decoder, pc,
- "invalid value type '%s', enable with --experimental-wasm-%s",
- result.name().c_str(),
- WasmFeatures::name_for_feature(feature_for_heap_type(heap_type)));
+ "invalid value type '%sref', enable with --experimental-wasm-gc",
+ HeapType::from_code(code).name().c_str());
return kWasmBottom;
}
- return result;
+ V8_FALLTHROUGH;
+ case kAnyRefCode:
+ case kFuncRefCode: {
+ HeapType heap_type = HeapType::from_code(code);
+ Nullability nullability =
+ code == kI31RefCode || code == kDataRefCode || code == kArrayRefCode
+ ? kNonNullable
+ : kNullable;
+ return ValueType::Ref(heap_type, nullability);
}
case kI32Code:
return kWasmI32;
@@ -326,22 +313,27 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
return heap_type.is_bottom() ? kWasmBottom
: ValueType::Ref(heap_type, nullability);
}
- case kRttWithDepthCode: {
+ // TODO(7748): This is here only for backwards compatibility, and the parsed
+ // depth is ignored.
+ case kRttWithDepthCode:
+ case kRttCode: {
if (!VALIDATE(enabled.has_gc())) {
DecodeError<validate>(
decoder, pc,
"invalid value type 'rtt', enable with --experimental-wasm-gc");
return kWasmBottom;
}
- uint32_t depth = decoder->read_u32v<validate>(pc + 1, length, "depth");
- *length += 1;
- if (!VALIDATE(depth <= kV8MaxRttSubtypingDepth)) {
- DecodeError<validate>(
- decoder, pc,
- "subtyping depth %u is greater than the maximum depth "
- "%u supported by V8",
- depth, kV8MaxRttSubtypingDepth);
- return kWasmBottom;
+ if (code == kRttWithDepthCode) {
+ uint32_t depth = decoder->read_u32v<validate>(pc + 1, length, "depth");
+ *length += 1;
+ if (!VALIDATE(depth <= kV8MaxRttSubtypingDepth)) {
+ DecodeError<validate>(
+ decoder, pc,
+ "subtyping depth %u is greater than the maximum depth "
+ "%u supported by V8",
+ depth, kV8MaxRttSubtypingDepth);
+ return kWasmBottom;
+ }
}
uint32_t type_index_length;
uint32_t type_index =
@@ -362,32 +354,6 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
type_index);
return kWasmBottom;
}
- return ValueType::Rtt(type_index, depth);
- }
- case kRttCode: {
- if (!VALIDATE(enabled.has_gc())) {
- DecodeError<validate>(
- decoder, pc,
- "invalid value type 'rtt', enable with --experimental-wasm-gc");
- return kWasmBottom;
- }
- uint32_t type_index = decoder->read_u32v<validate>(pc + 1, length);
- *length += 1;
- if (!VALIDATE(type_index < kV8MaxWasmTypes)) {
- DecodeError<validate>(
- decoder, pc,
- "Type index %u is greater than the maximum number %zu "
- "of type definitions supported by V8",
- type_index, kV8MaxWasmTypes);
- return kWasmBottom;
- }
- // We use capacity over size so this works mid-DecodeTypeSection.
- if (!VALIDATE(module == nullptr ||
- type_index < module->types.capacity())) {
- DecodeError<validate>(decoder, pc, "Type index %u is out of bounds",
- type_index);
- return kWasmBottom;
- }
return ValueType::Rtt(type_index);
}
case kS128Code: {
@@ -944,6 +910,8 @@ struct ControlBase : public PcForErrors<validate> {
F(F32Const, Value* result, float value) \
F(F64Const, Value* result, double value) \
F(S128Const, Simd128Immediate<validate>& imm, Value* result) \
+ F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
+ Value* result) \
F(RefNull, ValueType type, Value* result) \
F(RefFunc, uint32_t function_index, Value* result) \
F(GlobalGet, Value* result, const GlobalIndexImmediate<validate>& imm) \
@@ -953,149 +921,153 @@ struct ControlBase : public PcForErrors<validate> {
const Value& rtt, Value* result) \
F(ArrayInit, const ArrayIndexImmediate<validate>& imm, \
const base::Vector<Value>& elements, const Value& rtt, Value* result) \
+ F(ArrayInitFromData, const ArrayIndexImmediate<validate>& array_imm, \
+ const IndexImmediate<validate>& data_segment, const Value& offset, \
+ const Value& length, const Value& rtt, Value* result) \
F(RttCanon, uint32_t type_index, Value* result) \
- F(RttSub, uint32_t type_index, const Value& parent, Value* result, \
- WasmRttSubMode mode) \
F(DoReturn, uint32_t drop_values)
-#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) \
- /* Control: */ \
- F(Block, Control* block) \
- F(Loop, Control* block) \
- F(Try, Control* block) \
- F(If, const Value& cond, Control* if_block) \
- F(FallThruTo, Control* c) \
- F(PopControl, Control* block) \
- /* Instructions: */ \
- F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
- F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
- Value* result) \
- F(RefAsNonNull, const Value& arg, Value* result) \
- F(Drop) \
- F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \
- F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \
- F(LocalTee, const Value& value, Value* result, \
- const IndexImmediate<validate>& imm) \
- F(AllocateLocals, base::Vector<Value> local_values) \
- F(DeallocateLocals, uint32_t count) \
- F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \
- F(TableGet, const Value& index, Value* result, \
- const IndexImmediate<validate>& imm) \
- F(TableSet, const Value& index, const Value& value, \
- const IndexImmediate<validate>& imm) \
- F(Trap, TrapReason reason) \
- F(NopForTestingUnsupportedInLiftoff) \
- F(Select, const Value& cond, const Value& fval, const Value& tval, \
- Value* result) \
- F(BrOrRet, uint32_t depth, uint32_t drop_values) \
- F(BrIf, const Value& cond, uint32_t depth) \
- F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
- F(Else, Control* if_block) \
- F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
- const Value& index, Value* result) \
- F(LoadTransform, LoadType type, LoadTransformationKind transform, \
- const MemoryAccessImmediate<validate>& imm, const Value& index, \
- Value* result) \
- F(LoadLane, LoadType type, const Value& value, const Value& index, \
- const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \
- Value* result) \
- F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
- const Value& index, const Value& value) \
- F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \
- const Value& index, const Value& value, const uint8_t laneidx) \
- F(CurrentMemoryPages, Value* result) \
- F(MemoryGrow, const Value& value, Value* result) \
- F(CallDirect, const CallFunctionImmediate<validate>& imm, \
- const Value args[], Value returns[]) \
- F(CallIndirect, const Value& index, \
- const CallIndirectImmediate<validate>& imm, const Value args[], \
- Value returns[]) \
- F(CallRef, const Value& func_ref, const FunctionSig* sig, \
- uint32_t sig_index, const Value args[], const Value returns[]) \
- F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \
- uint32_t sig_index, const Value args[]) \
- F(ReturnCall, const CallFunctionImmediate<validate>& imm, \
- const Value args[]) \
- F(ReturnCallIndirect, const Value& index, \
- const CallIndirectImmediate<validate>& imm, const Value args[]) \
- F(BrOnNull, const Value& ref_object, uint32_t depth, \
- bool pass_null_along_branch, Value* result_on_fallthrough) \
- F(BrOnNonNull, const Value& ref_object, uint32_t depth) \
- F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \
- F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
- const base::Vector<Value> inputs, Value* result) \
- F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \
- F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \
- const Value& input0, const Value& input1, Value* result) \
- F(Throw, const TagIndexImmediate<validate>& imm, \
- const base::Vector<Value>& args) \
- F(Rethrow, Control* block) \
- F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \
- base::Vector<Value> caught_values) \
- F(Delegate, uint32_t depth, Control* block) \
- F(CatchAll, Control* block) \
- F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \
- const MemoryAccessImmediate<validate>& imm, Value* result) \
- F(AtomicFence) \
- F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
- const Value& src, const Value& size) \
- F(DataDrop, const IndexImmediate<validate>& imm) \
- F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
- const Value& src, const Value& size) \
- F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
- const Value& value, const Value& size) \
- F(TableInit, const TableInitImmediate<validate>& imm, \
- base::Vector<Value> args) \
- F(ElemDrop, const IndexImmediate<validate>& imm) \
- F(TableCopy, const TableCopyImmediate<validate>& imm, \
- base::Vector<Value> args) \
- F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \
- const Value& delta, Value* result) \
- F(TableSize, const IndexImmediate<validate>& imm, Value* result) \
- F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \
- const Value& value, const Value& count) \
- F(StructGet, const Value& struct_object, \
- const FieldImmediate<validate>& field, bool is_signed, Value* result) \
- F(StructSet, const Value& struct_object, \
- const FieldImmediate<validate>& field, const Value& field_value) \
- F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
- const Value& length, const Value& initial_value, const Value& rtt, \
- Value* result) \
- F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
- const Value& length, const Value& rtt, Value* result) \
- F(ArrayGet, const Value& array_obj, \
- const ArrayIndexImmediate<validate>& imm, const Value& index, \
- bool is_signed, Value* result) \
- F(ArraySet, const Value& array_obj, \
- const ArrayIndexImmediate<validate>& imm, const Value& index, \
- const Value& value) \
- F(ArrayLen, const Value& array_obj, Value* result) \
- F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \
- const Value& dst_index, const Value& length) \
- F(I31New, const Value& input, Value* result) \
- F(I31GetS, const Value& input, Value* result) \
- F(I31GetU, const Value& input, Value* result) \
- F(RefTest, const Value& obj, const Value& rtt, Value* result) \
- F(RefCast, const Value& obj, const Value& rtt, Value* result) \
- F(AssertNull, const Value& obj, Value* result) \
- F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \
- uint32_t depth) \
- F(BrOnCastFail, const Value& obj, const Value& rtt, \
- Value* result_on_fallthrough, uint32_t depth) \
- F(RefIsFunc, const Value& object, Value* result) \
- F(RefIsData, const Value& object, Value* result) \
- F(RefIsI31, const Value& object, Value* result) \
- F(RefAsFunc, const Value& object, Value* result) \
- F(RefAsData, const Value& object, Value* result) \
- F(RefAsI31, const Value& object, Value* result) \
- F(BrOnFunc, const Value& object, Value* value_on_branch, uint32_t br_depth) \
- F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \
- F(BrOnI31, const Value& object, Value* value_on_branch, uint32_t br_depth) \
- F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \
- uint32_t br_depth) \
- F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \
- uint32_t br_depth) \
- F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \
+#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) /* force 80 columns */ \
+ /* Control: */ \
+ F(Block, Control* block) \
+ F(Loop, Control* block) \
+ F(Try, Control* block) \
+ F(If, const Value& cond, Control* if_block) \
+ F(FallThruTo, Control* c) \
+ F(PopControl, Control* block) \
+ /* Instructions: */ \
+ F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
+ F(RefAsNonNull, const Value& arg, Value* result) \
+ F(Drop) \
+ F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \
+ F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \
+ F(LocalTee, const Value& value, Value* result, \
+ const IndexImmediate<validate>& imm) \
+ F(AllocateLocals, base::Vector<Value> local_values) \
+ F(DeallocateLocals, uint32_t count) \
+ F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \
+ F(TableGet, const Value& index, Value* result, \
+ const IndexImmediate<validate>& imm) \
+ F(TableSet, const Value& index, const Value& value, \
+ const IndexImmediate<validate>& imm) \
+ F(Trap, TrapReason reason) \
+ F(NopForTestingUnsupportedInLiftoff) \
+ F(Select, const Value& cond, const Value& fval, const Value& tval, \
+ Value* result) \
+ F(BrOrRet, uint32_t depth, uint32_t drop_values) \
+ F(BrIf, const Value& cond, uint32_t depth) \
+ F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
+ F(Else, Control* if_block) \
+ F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
+ const Value& index, Value* result) \
+ F(LoadTransform, LoadType type, LoadTransformationKind transform, \
+ const MemoryAccessImmediate<validate>& imm, const Value& index, \
+ Value* result) \
+ F(LoadLane, LoadType type, const Value& value, const Value& index, \
+ const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \
+ Value* result) \
+ F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
+ const Value& index, const Value& value) \
+ F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \
+ const Value& index, const Value& value, const uint8_t laneidx) \
+ F(CurrentMemoryPages, Value* result) \
+ F(MemoryGrow, const Value& value, Value* result) \
+ F(CallDirect, const CallFunctionImmediate<validate>& imm, \
+ const Value args[], Value returns[]) \
+ F(CallIndirect, const Value& index, \
+ const CallIndirectImmediate<validate>& imm, const Value args[], \
+ Value returns[]) \
+ F(CallRef, const Value& func_ref, const FunctionSig* sig, \
+ uint32_t sig_index, const Value args[], const Value returns[]) \
+ F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \
+ uint32_t sig_index, const Value args[]) \
+ F(ReturnCall, const CallFunctionImmediate<validate>& imm, \
+ const Value args[]) \
+ F(ReturnCallIndirect, const Value& index, \
+ const CallIndirectImmediate<validate>& imm, const Value args[]) \
+ F(BrOnNull, const Value& ref_object, uint32_t depth, \
+ bool pass_null_along_branch, Value* result_on_fallthrough) \
+ F(BrOnNonNull, const Value& ref_object, uint32_t depth) \
+ F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \
+ F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
+ const base::Vector<Value> inputs, Value* result) \
+ F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \
+ F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \
+ const Value& input0, const Value& input1, Value* result) \
+ F(Throw, const TagIndexImmediate<validate>& imm, \
+ const base::Vector<Value>& args) \
+ F(Rethrow, Control* block) \
+ F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \
+ base::Vector<Value> caught_values) \
+ F(Delegate, uint32_t depth, Control* block) \
+ F(CatchAll, Control* block) \
+ F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \
+ const MemoryAccessImmediate<validate>& imm, Value* result) \
+ F(AtomicFence) \
+ F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
+ const Value& src, const Value& size) \
+ F(DataDrop, const IndexImmediate<validate>& imm) \
+ F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
+ const Value& src, const Value& size) \
+ F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
+ const Value& value, const Value& size) \
+ F(TableInit, const TableInitImmediate<validate>& imm, \
+ base::Vector<Value> args) \
+ F(ElemDrop, const IndexImmediate<validate>& imm) \
+ F(TableCopy, const TableCopyImmediate<validate>& imm, \
+ base::Vector<Value> args) \
+ F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \
+ const Value& delta, Value* result) \
+ F(TableSize, const IndexImmediate<validate>& imm, Value* result) \
+ F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \
+ const Value& value, const Value& count) \
+ F(StructGet, const Value& struct_object, \
+ const FieldImmediate<validate>& field, bool is_signed, Value* result) \
+ F(StructSet, const Value& struct_object, \
+ const FieldImmediate<validate>& field, const Value& field_value) \
+ F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
+ const Value& length, const Value& initial_value, const Value& rtt, \
+ Value* result) \
+ F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
+ const Value& length, const Value& rtt, Value* result) \
+ F(ArrayGet, const Value& array_obj, \
+ const ArrayIndexImmediate<validate>& imm, const Value& index, \
+ bool is_signed, Value* result) \
+ F(ArraySet, const Value& array_obj, \
+ const ArrayIndexImmediate<validate>& imm, const Value& index, \
+ const Value& value) \
+ F(ArrayLen, const Value& array_obj, Value* result) \
+ F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \
+ const Value& dst_index, const Value& length) \
+ F(I31New, const Value& input, Value* result) \
+ F(I31GetS, const Value& input, Value* result) \
+ F(I31GetU, const Value& input, Value* result) \
+ F(RefTest, const Value& obj, const Value& rtt, Value* result) \
+ F(RefCast, const Value& obj, const Value& rtt, Value* result) \
+ F(AssertNull, const Value& obj, Value* result) \
+ F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \
+ uint32_t depth) \
+ F(BrOnCastFail, const Value& obj, const Value& rtt, \
+ Value* result_on_fallthrough, uint32_t depth) \
+ F(RefIsFunc, const Value& object, Value* result) \
+ F(RefIsData, const Value& object, Value* result) \
+ F(RefIsI31, const Value& object, Value* result) \
+ F(RefIsArray, const Value& object, Value* result) \
+ F(RefAsFunc, const Value& object, Value* result) \
+ F(RefAsData, const Value& object, Value* result) \
+ F(RefAsI31, const Value& object, Value* result) \
+ F(RefAsArray, const Value& object, Value* result) \
+ F(BrOnFunc, const Value& object, Value* value_on_branch, uint32_t br_depth) \
+ F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \
+ F(BrOnI31, const Value& object, Value* value_on_branch, uint32_t br_depth) \
+ F(BrOnArray, const Value& object, Value* value_on_branch, uint32_t br_depth) \
+ F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \
+ uint32_t br_depth) \
+ F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \
+ uint32_t br_depth) \
+ F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \
+ uint32_t br_depth) \
+ F(BrOnNonArray, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth)
// Generic Wasm bytecode decoder with utilities for decoding immediates,
@@ -1281,6 +1253,8 @@ class WasmDecoder : public Decoder {
}
bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
+ // We compare with the current size of the globals vector. This is important
+ // if we are decoding a constant expression in the global section.
if (!VALIDATE(imm.index < module_->globals.size())) {
DecodeError(pc, "Invalid global index: %u", imm.index);
return false;
@@ -1354,13 +1328,6 @@ class WasmDecoder : public Decoder {
bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
if (!ValidateSignature(pc, imm.sig_imm)) return false;
- // call_indirect is not behind the reftypes feature, so we have to impose
- // the older format if reftypes is not enabled.
- if (!VALIDATE((imm.table_imm.index == 0 && imm.table_imm.length == 1) ||
- this->enabled_.has_reftypes())) {
- DecodeError(pc + imm.sig_imm.length, "expected table index 0, found %u",
- imm.table_imm.index);
- }
if (!ValidateTable(pc + imm.sig_imm.length, imm.table_imm)) {
return false;
}
@@ -1538,6 +1505,9 @@ class WasmDecoder : public Decoder {
// The following Validate* functions all validate an IndexImmediate, albeit
// differently according to context.
bool ValidateTable(const byte* pc, IndexImmediate<validate>& imm) {
+ if (imm.index > 0 || imm.length > 1) {
+ this->detected_->Add(kFeature_reftypes);
+ }
if (!VALIDATE(imm.index < module_->tables.size())) {
DecodeError(pc, "invalid table index: %u", imm.index);
return false;
@@ -1717,7 +1687,7 @@ class WasmDecoder : public Decoder {
case kExprRefAsNonNull:
return 1;
-#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
+#define DECLARE_OPCODE_CASE(name, ...) case kExpr##name:
// clang-format off
/********** Simple and memory opcodes **********/
FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
@@ -1892,6 +1862,13 @@ class WasmDecoder : public Decoder {
pc + length + dst_imm.length);
return length + dst_imm.length + src_imm.length;
}
+ case kExprArrayInitFromData:
+ case kExprArrayInitFromDataStatic: {
+ ArrayIndexImmediate<validate> array_imm(decoder, pc + length);
+ IndexImmediate<validate> data_imm(
+ decoder, pc + length + array_imm.length, "data segment index");
+ return length + array_imm.length + data_imm.length;
+ }
case kExprBrOnCast:
case kExprBrOnCastFail:
case kExprBrOnData:
@@ -1901,8 +1878,6 @@ class WasmDecoder : public Decoder {
return length + imm.length;
}
case kExprRttCanon:
- case kExprRttSub:
- case kExprRttFreshSub:
case kExprRefTestStatic:
case kExprRefCastStatic:
case kExprBrOnCastStatic:
@@ -1939,7 +1914,7 @@ class WasmDecoder : public Decoder {
// Prefixed opcodes (already handled, included here for completeness of
// switch)
FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE)
- FOREACH_NUMERIC_OPCODE(DECLARE_OPCODE_CASE)
+ FOREACH_NUMERIC_OPCODE(DECLARE_OPCODE_CASE, DECLARE_OPCODE_CASE)
FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_GC_OPCODE(DECLARE_OPCODE_CASE)
@@ -2047,13 +2022,19 @@ class WasmDecoder : public Decoder {
return {2, 1};
FOREACH_SIMD_CONST_OPCODE(DECLARE_OPCODE_CASE)
return {0, 1};
+ // Special case numeric opcodes without fixed signature.
+ case kExprMemoryInit:
+ case kExprMemoryCopy:
+ case kExprMemoryFill:
+ return {3, 0};
+ case kExprTableGrow:
+ return {2, 1};
+ case kExprTableFill:
+ return {3, 0};
default: {
sig = WasmOpcodes::Signature(opcode);
- if (sig) {
- return {sig->parameter_count(), sig->return_count()};
- } else {
- UNREACHABLE();
- }
+ DCHECK_NOT_NULL(sig);
+ return {sig->parameter_count(), sig->return_count()};
}
}
}
@@ -2069,8 +2050,6 @@ class WasmDecoder : public Decoder {
case kExprI31GetU:
case kExprArrayNewDefault:
case kExprArrayLen:
- case kExprRttSub:
- case kExprRttFreshSub:
case kExprRefTestStatic:
case kExprRefCastStatic:
case kExprBrOnCastStatic:
@@ -2080,6 +2059,7 @@ class WasmDecoder : public Decoder {
return {2, 0};
case kExprArrayNew:
case kExprArrayNewDefaultWithRtt:
+ case kExprArrayInitFromDataStatic:
case kExprArrayGet:
case kExprArrayGetS:
case kExprArrayGetU:
@@ -2096,6 +2076,7 @@ class WasmDecoder : public Decoder {
case kExprStructNewDefault:
return {0, 1};
case kExprArrayNewWithRtt:
+ case kExprArrayInitFromData:
return {3, 1};
case kExprStructNewWithRtt: {
StructIndexImmediate<validate> imm(this, pc + 2);
@@ -2253,6 +2234,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DCHECK_LE(this->pc_, this->end_);
DCHECK_EQ(this->num_locals(), 0);
+ locals_offset_ = this->pc_offset();
this->InitializeLocalsFromSig();
uint32_t params_count = static_cast<uint32_t>(this->num_locals());
uint32_t locals_length;
@@ -2359,7 +2341,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
uint32_t pc_relative_offset() const {
- return this->pc_offset() - first_instruction_offset;
+ return this->pc_offset() - locals_offset_;
}
void DecodeFunctionBody() {
@@ -2393,7 +2375,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CALL_INTERFACE_IF_OK_AND_REACHABLE(StartFunctionBody, c);
}
- first_instruction_offset = this->pc_offset();
// Decode the function body.
while (this->pc_ < this->end_) {
// Most operations only grow the stack by at least one element (unary and
@@ -2426,7 +2407,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
private:
- uint32_t first_instruction_offset = 0;
+ uint32_t locals_offset_ = 0;
Interface interface_;
// The value stack, stored as individual pointers for maximum performance.
@@ -2518,9 +2499,16 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Append("T");
break;
case kControlIfElse:
+ Append("E");
+ break;
case kControlTryCatch:
+ Append("C");
+ break;
case kControlTryCatchAll:
- case kControlLet: // TODO(7748): Implement
+ Append("A");
+ break;
+ case kControlLet:
+ Append("D");
break;
}
if (c.start_merge.arity) Append("%u-", c.start_merge.arity);
@@ -2572,7 +2560,20 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
#define BUILD_SIMPLE_OPCODE(op, _, sig) \
DECODE(op) { return BuildSimpleOperator_##sig(kExpr##op); }
- FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
+ FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE)
+#undef BUILD_SIMPLE_OPCODE
+
+#define BUILD_SIMPLE_OPCODE(op, _, sig) \
+ DECODE(op) { \
+ if (decoding_mode == kInitExpression) { \
+ if (!VALIDATE(this->enabled_.has_extended_const())) { \
+ NonConstError(this, kExpr##op); \
+ return 0; \
+ } \
+ } \
+ return BuildSimpleOperator_##sig(kExpr##op); \
+ }
+ FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_OPCODE)
#undef BUILD_SIMPLE_OPCODE
DECODE(Block) {
@@ -2712,7 +2713,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CHECK_PROTOTYPE_OPCODE(typed_funcref);
BranchDepthImmediate<validate> imm(this, this->pc_ + 1);
if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0;
- Value ref_object = Peek(0, 0);
+ Value ref_object = Peek(0);
Control* c = control_at(imm.depth);
if (!VALIDATE(TypeCheckBranch<true>(c, 1))) return 0;
switch (ref_object.type.kind()) {
@@ -2768,6 +2769,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
if (V8_LIKELY(current_code_reachable_and_ok_)) {
CALL_INTERFACE(Forward, ref_object, stack_value(1));
CALL_INTERFACE(BrOrRet, imm.depth, 0);
+ // We know that the following code is not reachable, but according
+ // to the spec it technically is. Set it to spec-only reachable.
+ SetSucceedingCodeDynamicallyUnreachable();
c->br_merge()->reached = true;
}
break;
@@ -2802,8 +2806,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
ArgVector let_local_values =
- PeekArgs(static_cast<uint32_t>(imm.in_arity()),
- base::VectorOf(this->local_types_.data(), new_locals_count));
+ PeekArgs(base::VectorOf(this->local_types_.data(), new_locals_count));
ArgVector args = PeekArgs(imm.sig, new_locals_count);
Control* let_block = PushControl(kControlLet, new_locals_count,
let_local_values.length() + args.length());
@@ -2925,7 +2928,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DECODE(Select) {
Value cond = Peek(0, 2, kWasmI32);
- Value fval = Peek(1, 1);
+ Value fval = Peek(1);
Value tval = Peek(2, 0, fval.type);
ValueType type = tval.type == kWasmBottom ? fval.type : tval.type;
if (!VALIDATE(!type.is_reference())) {
@@ -2941,7 +2944,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(SelectWithType) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
this->module_);
if (this->failed()) return 0;
@@ -3075,7 +3078,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(RefNull) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
this->module_);
if (!VALIDATE(this->ok())) return 0;
@@ -3087,8 +3090,8 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(RefIsNull) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
- Value value = Peek(0, 0);
+ this->detected_->Add(kFeature_reftypes);
+ Value value = Peek(0);
Value result = CreateValue(kWasmI32);
switch (value.type.kind()) {
case kOptRef:
@@ -3116,7 +3119,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(RefFunc) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
IndexImmediate<validate> imm(this, this->pc_ + 1, "function index");
if (!this->ValidateFunction(this->pc_ + 1, imm)) return 0;
HeapType heap_type(this->enabled_.has_typed_funcref()
@@ -3130,7 +3133,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DECODE(RefAsNonNull) {
CHECK_PROTOTYPE_OPCODE(typed_funcref);
- Value value = Peek(0, 0);
+ Value value = Peek(0);
switch (value.type.kind()) {
case kBottom:
// We are in unreachable code. Forward the bottom value.
@@ -3192,7 +3195,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(Drop) {
- Peek(0, 0);
+ Peek(0);
CALL_INTERFACE_IF_OK_AND_REACHABLE(Drop);
Drop(1);
return 1;
@@ -3221,7 +3224,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(TableGet) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
IndexImmediate<validate> imm(this, this->pc_ + 1, "table index");
if (!this->ValidateTable(this->pc_ + 1, imm)) return 0;
Value index = Peek(0, 0, kWasmI32);
@@ -3233,7 +3236,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
DECODE(TableSet) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
IndexImmediate<validate> imm(this, this->pc_ + 1, "table index");
if (!this->ValidateTable(this->pc_ + 1, imm)) return 0;
Value value = Peek(0, 1, this->module_->tables[imm.index].type);
@@ -3366,7 +3369,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DECODE(CallRef) {
CHECK_PROTOTYPE_OPCODE(typed_funcref);
- Value func_ref = Peek(0, 0);
+ Value func_ref = Peek(0);
ValueType func_type = func_ref.type;
if (func_type == kWasmBottom) {
// We are in unreachable code, maintain the polymorphic stack.
@@ -3392,7 +3395,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DECODE(ReturnCallRef) {
CHECK_PROTOTYPE_OPCODE(typed_funcref);
CHECK_PROTOTYPE_OPCODE(return_call);
- Value func_ref = Peek(0, 0);
+ Value func_ref = Peek(0);
ValueType func_type = func_ref.type;
if (func_type == kWasmBottom) {
// We are in unreachable code, maintain the polymorphic stack.
@@ -3419,7 +3422,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
this->pc_, &opcode_length, "numeric index");
if (full_opcode == kExprTableGrow || full_opcode == kExprTableSize ||
full_opcode == kExprTableFill) {
- CHECK_PROTOTYPE_OPCODE(reftypes);
+ this->detected_->Add(kFeature_reftypes);
}
trace_msg->AppendOpcode(full_opcode);
return DecodeNumericOpcode(full_opcode, opcode_length);
@@ -3511,8 +3514,11 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
static constexpr OpcodeHandler GetOpcodeHandlerTableEntry(size_t idx) {
DECODE_IMPL(Nop);
#define BUILD_SIMPLE_OPCODE(op, _, sig) DECODE_IMPL(op);
- FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
+ FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE)
#undef BUILD_SIMPLE_OPCODE
+#define BUILD_SIMPLE_EXTENDED_CONST_OPCODE(op, _, sig) DECODE_IMPL_CONST(op);
+ FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_EXTENDED_CONST_OPCODE)
+#undef BUILD_SIMPLE_EXTENDED_CONST_OPCODE
DECODE_IMPL(Block);
DECODE_IMPL(Rethrow);
DECODE_IMPL(Throw);
@@ -3692,8 +3698,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Drop(static_cast<int>(type->field_count()));
}
- V8_INLINE ArgVector PeekArgs(uint32_t base_index,
- base::Vector<ValueType> arg_types) {
+ V8_INLINE ArgVector PeekArgs(base::Vector<ValueType> arg_types) {
int size = static_cast<int>(arg_types.size());
EnsureStackArguments(size);
ArgVector args(stack_value(size), arg_types.size());
@@ -4050,28 +4055,13 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprStructNewWithRtt: {
StructIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
+ ValueType rtt_type = ValueType::Rtt(imm.index);
Value rtt = opcode == kExprStructNew
- ? CreateValue(ValueType::Rtt(imm.index))
- : Peek(0, imm.struct_type->field_count());
+ ? CreateValue(rtt_type)
+ : Peek(0, imm.struct_type->field_count(), rtt_type);
if (opcode == kExprStructNew) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
- } else {
- DCHECK_EQ(opcode, kExprStructNewWithRtt);
- if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
- PopTypeError(imm.struct_type->field_count(), rtt, "rtt");
- return 0;
- }
- // TODO(7748): Drop this check if {imm} is dropped from the proposal
- // à la https://github.com/WebAssembly/function-references/pull/31.
- if (!VALIDATE(rtt.type.is_bottom() ||
- (rtt.type.ref_index() == imm.index &&
- rtt.type.has_depth()))) {
- PopTypeError(
- imm.struct_type->field_count(), rtt,
- "rtt with depth for type " + std::to_string(imm.index));
- return 0;
- }
}
ArgVector args = PeekArgs(imm.struct_type, 1);
Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable));
@@ -4098,27 +4088,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
}
}
- Value rtt = opcode == kExprStructNewDefault
- ? CreateValue(ValueType::Rtt(imm.index))
- : Peek(0, 0);
+ ValueType rtt_type = ValueType::Rtt(imm.index);
+ Value rtt = opcode == kExprStructNewDefault ? CreateValue(rtt_type)
+ : Peek(0, 0, rtt_type);
if (opcode == kExprStructNewDefault) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
- } else {
- DCHECK_EQ(opcode, kExprStructNewDefaultWithRtt);
- if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
- PopTypeError(0, rtt, "rtt");
- return 0;
- }
- // TODO(7748): Drop this check if {imm} is dropped from the proposal
- // à la https://github.com/WebAssembly/function-references/pull/31.
- if (!VALIDATE(rtt.type.is_bottom() ||
- (rtt.type.ref_index() == imm.index &&
- rtt.type.has_depth()))) {
- PopTypeError(
- 0, rtt, "rtt with depth for type " + std::to_string(imm.index));
- return 0;
- }
}
Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable));
CALL_INTERFACE_IF_OK_AND_REACHABLE(StructNewDefault, imm, rtt, &value);
@@ -4197,27 +4172,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
NON_CONST_ONLY
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
- Value rtt = opcode == kExprArrayNew
- ? CreateValue(ValueType::Rtt(imm.index))
- : Peek(0, 2);
+ ValueType rtt_type = ValueType::Rtt(imm.index);
+ Value rtt = opcode == kExprArrayNew ? CreateValue(rtt_type)
+ : Peek(0, 2, rtt_type);
if (opcode == kExprArrayNew) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
- } else {
- DCHECK_EQ(opcode, kExprArrayNewWithRtt);
- if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
- PopTypeError(2, rtt, "rtt");
- return 0;
- }
- // TODO(7748): Drop this check if {imm} is dropped from the proposal
- // à la https://github.com/WebAssembly/function-references/pull/31.
- if (!VALIDATE(rtt.type.is_bottom() ||
- (rtt.type.ref_index() == imm.index &&
- rtt.type.has_depth()))) {
- PopTypeError(
- 2, rtt, "rtt with depth for type " + std::to_string(imm.index));
- return 0;
- }
}
Value length = Peek(1, 1, kWasmI32);
Value initial_value =
@@ -4241,27 +4201,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
imm.array_type->element_type().name().c_str());
return 0;
}
- Value rtt = opcode == kExprArrayNewDefault
- ? CreateValue(ValueType::Rtt(imm.index))
- : Peek(0, 1);
+ ValueType rtt_type = ValueType::Rtt(imm.index);
+ Value rtt = opcode == kExprArrayNewDefault ? CreateValue(rtt_type)
+ : Peek(0, 1, rtt_type);
if (opcode == kExprArrayNewDefault) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
- } else {
- DCHECK_EQ(opcode, kExprArrayNewDefaultWithRtt);
- if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) {
- PopTypeError(1, rtt, "rtt");
- return 0;
- }
- // TODO(7748): Drop this check if {imm} is dropped from the proposal
- // à la https://github.com/WebAssembly/function-references/pull/31.
- if (!VALIDATE(rtt.type.is_bottom() ||
- (rtt.type.ref_index() == imm.index &&
- rtt.type.has_depth()))) {
- PopTypeError(
- 1, rtt, "rtt with depth for type " + std::to_string(imm.index));
- return 0;
- }
}
Value length = Peek(1, 0, kWasmI32);
Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable));
@@ -4271,6 +4216,54 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(value);
return opcode_length + imm.length;
}
+ case kExprArrayInitFromData:
+ case kExprArrayInitFromDataStatic: {
+ ArrayIndexImmediate<validate> array_imm(this,
+ this->pc_ + opcode_length);
+ if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0;
+ ValueType element_type = array_imm.array_type->element_type();
+ if (element_type.is_reference()) {
+ this->DecodeError(
+ "array.init_from_data can only be used with value-type arrays, "
+ "found array type #%d instead",
+ array_imm.index);
+ return 0;
+ }
+#if V8_TARGET_BIG_ENDIAN
+ // Byte sequences in data segments are interpreted as little endian for
+ // the purposes of this instruction. This means that those will have to
+ // be transformed in big endian architectures. TODO(7748): Implement.
+ if (element_type.element_size_bytes() > 1) {
+ UNIMPLEMENTED();
+ }
+#endif
+ const byte* data_index_pc =
+ this->pc_ + opcode_length + array_imm.length;
+ IndexImmediate<validate> data_segment(this, data_index_pc,
+ "data segment");
+ if (!this->ValidateDataSegment(data_index_pc, data_segment)) return 0;
+
+ ValueType rtt_type = ValueType::Rtt(array_imm.index);
+ Value rtt = opcode == kExprArrayInitFromDataStatic
+ ? CreateValue(rtt_type)
+ : Peek(0, 2, rtt_type);
+ if (opcode == kExprArrayInitFromDataStatic) {
+ CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt);
+ Push(rtt);
+ }
+
+ Value length = Peek(1, 1, kWasmI32);
+ Value offset = Peek(2, 0, kWasmI32);
+
+ Value array =
+ CreateValue(ValueType::Ref(array_imm.index, kNonNullable));
+ CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayInitFromData, array_imm,
+ data_segment, offset, length, rtt,
+ &array);
+ Drop(3); // rtt, length, offset
+ Push(array);
+ return opcode_length + array_imm.length + data_segment.length;
+ }
case kExprArrayGetS:
case kExprArrayGetU: {
NON_CONST_ONLY
@@ -4332,9 +4325,11 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
case kExprArrayLen: {
NON_CONST_ONLY
+ // Read but ignore an immediate array type index.
+ // TODO(7748): Remove this once we are ready to make breaking changes.
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
- if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
- Value array_obj = Peek(0, 0, ValueType::Ref(imm.index, kNullable));
+ Value array_obj =
+ Peek(0, 0, ValueType::Ref(HeapType::kArray, kNullable));
Value value = CreateValue(kWasmI32);
CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayLen, array_obj, &value);
Drop(array_obj);
@@ -4442,57 +4437,22 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
"type index");
if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
- Value value = CreateValue(ValueType::Rtt(
- imm.index, GetSubtypingDepth(this->module_, imm.index)));
+ Value value = CreateValue(ValueType::Rtt(imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &value);
Push(value);
return opcode_length + imm.length;
}
- case kExprRttFreshSub:
- case kExprRttSub: {
- IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
- "type index");
- if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
- Value parent = Peek(0, 0);
- if (parent.type.is_bottom()) {
- DCHECK(!current_code_reachable_and_ok_);
- // Just leave the unreachable/bottom value on the stack.
- } else {
- if (!VALIDATE(parent.type.is_rtt() &&
- IsHeapSubtypeOf(imm.index, parent.type.ref_index(),
- this->module_))) {
- PopTypeError(
- 0, parent,
- "rtt for a supertype of type " + std::to_string(imm.index));
- return 0;
- }
- Value value = parent.type.has_depth()
- ? CreateValue(ValueType::Rtt(
- imm.index, parent.type.depth() + 1))
- : CreateValue(ValueType::Rtt(imm.index));
-
- WasmRttSubMode mode = opcode == kExprRttSub
- ? WasmRttSubMode::kCanonicalize
- : WasmRttSubMode::kFresh;
- CALL_INTERFACE_IF_OK_AND_REACHABLE(RttSub, imm.index, parent, &value,
- mode);
- Drop(parent);
- Push(value);
- }
- return opcode_length + imm.length;
- }
case kExprRefTest:
case kExprRefTestStatic: {
NON_CONST_ONLY
// "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}."
- Value rtt = Peek(0, 1); // This is safe for the ...Static instruction.
+ Value rtt = Peek(0); // This is safe for the ...Static instruction.
if (opcode == kExprRefTestStatic) {
IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
"type index");
if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
opcode_length += imm.length;
- rtt = CreateValue(ValueType::Rtt(
- imm.index, GetSubtypingDepth(this->module_, imm.index)));
+ rtt = CreateValue(ValueType::Rtt(imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
} else {
@@ -4502,7 +4462,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
}
- Value obj = Peek(1, 0);
+ Value obj = Peek(1);
Value value = CreateValue(kWasmI32);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type,
@@ -4542,14 +4502,13 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprRefCast:
case kExprRefCastStatic: {
NON_CONST_ONLY
- Value rtt = Peek(0, 1); // This is safe for the ...Static instruction.
+ Value rtt = Peek(0); // This is safe for the ...Static instruction.
if (opcode == kExprRefCastStatic) {
IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
"type index");
if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
opcode_length += imm.length;
- rtt = CreateValue(ValueType::Rtt(
- imm.index, GetSubtypingDepth(this->module_, imm.index)));
+ rtt = CreateValue(ValueType::Rtt(imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
} else {
@@ -4559,7 +4518,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
}
- Value obj = Peek(1, 0);
+ Value obj = Peek(1);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type,
ValueType::Ref(HeapType::kData, kNullable),
@@ -4593,7 +4552,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CALL_INTERFACE(AssertNull, obj, &value);
} else {
CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast);
- EndControl();
+ // We know that the following code is not reachable, but according
+ // to the spec it technically is. Set it to spec-only reachable.
+ SetSucceedingCodeDynamicallyUnreachable();
}
} else {
CALL_INTERFACE(RefCast, obj, rtt, &value);
@@ -4612,14 +4573,14 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
control_.size())) {
return 0;
}
- Value rtt = Peek(0, 1); // This is safe for the ...Static instruction.
+ uint32_t pc_offset = opcode_length + branch_depth.length;
+ Value rtt = Peek(0); // This is safe for the ...Static instruction.
if (opcode == kExprBrOnCastStatic) {
- IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
+ IndexImmediate<validate> imm(this, this->pc_ + pc_offset,
"type index");
if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
- opcode_length += imm.length;
- rtt = CreateValue(ValueType::Rtt(
- imm.index, GetSubtypingDepth(this->module_, imm.index)));
+ pc_offset += imm.length;
+ rtt = CreateValue(ValueType::Rtt(imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
} else {
@@ -4629,7 +4590,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
}
- Value obj = Peek(1, 0);
+ Value obj = Peek(1);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type,
ValueType::Ref(HeapType::kData, kNullable),
@@ -4655,24 +4616,28 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
? kWasmBottom
: ValueType::Ref(rtt.type.ref_index(), kNonNullable));
Push(result_on_branch);
+ // The {value_on_branch} parameter we pass to the interface must
+ // be pointer-identical to the object on the stack, so we can't
+ // reuse {result_on_branch} which was passed-by-value to {Push}.
+ Value* value_on_branch = stack_value(1);
if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0;
if (V8_LIKELY(current_code_reachable_and_ok_)) {
// This logic ensures that code generation can assume that functions
// can only be cast to function types, and data objects to data types.
if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) {
CALL_INTERFACE(Drop); // rtt
+ CALL_INTERFACE(Forward, obj, value_on_branch);
// The branch will still not be taken on null.
if (obj.type.is_nullable()) {
CALL_INTERFACE(BrOnNonNull, obj, branch_depth.depth);
} else {
CALL_INTERFACE(BrOrRet, branch_depth.depth, 0);
+ // We know that the following code is not reachable, but according
+ // to the spec it technically is. Set it to spec-only reachable.
+ SetSucceedingCodeDynamicallyUnreachable();
}
c->br_merge()->reached = true;
} else if (V8_LIKELY(!TypeCheckAlwaysFails(obj, rtt))) {
- // The {value_on_branch} parameter we pass to the interface must
- // be pointer-identical to the object on the stack, so we can't
- // reuse {result_on_branch} which was passed-by-value to {Push}.
- Value* value_on_branch = stack_value(1);
CALL_INTERFACE(BrOnCast, obj, rtt, value_on_branch,
branch_depth.depth);
c->br_merge()->reached = true;
@@ -4682,7 +4647,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Drop(result_on_branch);
Push(obj); // Restore stack state on fallthrough.
- return opcode_length + branch_depth.length;
+ return pc_offset;
}
case kExprBrOnCastFail:
case kExprBrOnCastStaticFail: {
@@ -4693,14 +4658,14 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
control_.size())) {
return 0;
}
- Value rtt = Peek(0, 1); // This is safe for the ...Static instruction.
+ uint32_t pc_offset = opcode_length + branch_depth.length;
+ Value rtt = Peek(0); // This is safe for the ...Static instruction.
if (opcode == kExprBrOnCastStaticFail) {
- IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
+ IndexImmediate<validate> imm(this, this->pc_ + pc_offset,
"type index");
if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0;
- opcode_length += imm.length;
- rtt = CreateValue(ValueType::Rtt(
- imm.index, GetSubtypingDepth(this->module_, imm.index)));
+ pc_offset += imm.length;
+ rtt = CreateValue(ValueType::Rtt(imm.index));
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Push(rtt);
} else {
@@ -4710,7 +4675,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
}
- Value obj = Peek(1, 0);
+ Value obj = Peek(1);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type,
ValueType::Ref(HeapType::kData, kNullable),
@@ -4771,43 +4736,83 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
// Make sure the correct value is on the stack state on fallthrough.
Drop(obj);
Push(result_on_fallthrough);
- return opcode_length + branch_depth.length;
+ return pc_offset;
}
-#define ABSTRACT_TYPE_CHECK(heap_type) \
- case kExprRefIs##heap_type: { \
- NON_CONST_ONLY \
- Value arg = Peek(0, 0, kWasmAnyRef); \
- Value result = CreateValue(kWasmI32); \
- CALL_INTERFACE_IF_OK_AND_REACHABLE(RefIs##heap_type, arg, &result); \
- Drop(arg); \
- Push(result); \
- return opcode_length; \
+#define ABSTRACT_TYPE_CHECK(h_type) \
+ case kExprRefIs##h_type: { \
+ NON_CONST_ONLY \
+ Value arg = Peek(0, 0, kWasmAnyRef); \
+ if (this->failed()) return 0; \
+ Value result = CreateValue(kWasmI32); \
+ if (V8_LIKELY(current_code_reachable_and_ok_)) { \
+ if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \
+ this->module_)) { \
+ if (arg.type.is_nullable()) { \
+ /* We abuse ref.as_non_null, which isn't otherwise used as a unary \
+ * operator, as a sentinel for the negation of ref.is_null. */ \
+ CALL_INTERFACE(UnOp, kExprRefAsNonNull, arg, &result); \
+ } else { \
+ CALL_INTERFACE(Drop); \
+ CALL_INTERFACE(I32Const, &result, 1); \
+ } \
+ } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \
+ arg.type.heap_representation(), \
+ this->module_)) { \
+ CALL_INTERFACE(Drop); \
+ CALL_INTERFACE(I32Const, &result, 0); \
+ } else { \
+ CALL_INTERFACE(RefIs##h_type, arg, &result); \
+ } \
+ } \
+ Drop(arg); \
+ Push(result); \
+ return opcode_length; \
}
-
ABSTRACT_TYPE_CHECK(Data)
ABSTRACT_TYPE_CHECK(Func)
ABSTRACT_TYPE_CHECK(I31)
+ ABSTRACT_TYPE_CHECK(Array)
#undef ABSTRACT_TYPE_CHECK
-#define ABSTRACT_TYPE_CAST(heap_type) \
- case kExprRefAs##heap_type: { \
- NON_CONST_ONLY \
- Value arg = Peek(0, 0, kWasmAnyRef); \
- Value result = \
- CreateValue(ValueType::Ref(HeapType::k##heap_type, kNonNullable)); \
- CALL_INTERFACE_IF_OK_AND_REACHABLE(RefAs##heap_type, arg, &result); \
- Drop(arg); \
- Push(result); \
- return opcode_length; \
+#define ABSTRACT_TYPE_CAST(h_type) \
+ case kExprRefAs##h_type: { \
+ NON_CONST_ONLY \
+ Value arg = Peek(0, 0, kWasmAnyRef); \
+ ValueType non_nullable_abstract_type = \
+ ValueType::Ref(HeapType::k##h_type, kNonNullable); \
+ Value result = CreateValue(non_nullable_abstract_type); \
+ if (V8_LIKELY(current_code_reachable_and_ok_)) { \
+ if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \
+ this->module_)) { \
+ if (arg.type.is_nullable()) { \
+ CALL_INTERFACE(RefAsNonNull, arg, &result); \
+ } else { \
+ CALL_INTERFACE(Forward, arg, &result); \
+ } \
+ } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \
+ arg.type.heap_representation(), \
+ this->module_)) { \
+ CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast); \
+ /* We know that the following code is not reachable, but according */ \
+ /* to the spec it technically is. Set it to spec-only reachable. */ \
+ SetSucceedingCodeDynamicallyUnreachable(); \
+ } else { \
+ CALL_INTERFACE(RefAs##h_type, arg, &result); \
+ } \
+ } \
+ Drop(arg); \
+ Push(result); \
+ return opcode_length; \
}
-
ABSTRACT_TYPE_CAST(Data)
ABSTRACT_TYPE_CAST(Func)
ABSTRACT_TYPE_CAST(I31)
+ ABSTRACT_TYPE_CAST(Array)
#undef ABSTRACT_TYPE_CAST
case kExprBrOnData:
case kExprBrOnFunc:
+ case kExprBrOnArray:
case kExprBrOnI31: {
NON_CONST_ONLY
BranchDepthImmediate<validate> branch_depth(this,
@@ -4834,7 +4839,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
HeapType::Representation heap_type =
opcode == kExprBrOnFunc
? HeapType::kFunc
- : opcode == kExprBrOnData ? HeapType::kData : HeapType::kI31;
+ : opcode == kExprBrOnData
+ ? HeapType::kData
+ : opcode == kExprBrOnArray ? HeapType::kArray
+ : HeapType::kI31;
Value result_on_branch =
CreateValue(ValueType::Ref(heap_type, kNonNullable));
Push(result_on_branch);
@@ -4848,6 +4856,8 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CALL_INTERFACE(BrOnFunc, obj, value_on_branch, branch_depth.depth);
} else if (opcode == kExprBrOnData) {
CALL_INTERFACE(BrOnData, obj, value_on_branch, branch_depth.depth);
+ } else if (opcode == kExprBrOnArray) {
+ CALL_INTERFACE(BrOnArray, obj, value_on_branch, branch_depth.depth);
} else {
CALL_INTERFACE(BrOnI31, obj, value_on_branch, branch_depth.depth);
}
@@ -4859,6 +4869,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
case kExprBrOnNonData:
case kExprBrOnNonFunc:
+ case kExprBrOnNonArray:
case kExprBrOnNonI31: {
NON_CONST_ONLY
BranchDepthImmediate<validate> branch_depth(this,
@@ -4880,7 +4891,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
HeapType::Representation heap_type =
opcode == kExprBrOnNonFunc
? HeapType::kFunc
- : opcode == kExprBrOnNonData ? HeapType::kData : HeapType::kI31;
+ : opcode == kExprBrOnNonData
+ ? HeapType::kData
+ : opcode == kExprBrOnNonArray ? HeapType::kArray
+ : HeapType::kI31;
Value value_on_fallthrough =
CreateValue(ValueType::Ref(heap_type, kNonNullable));
@@ -4891,6 +4905,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
} else if (opcode == kExprBrOnNonData) {
CALL_INTERFACE(BrOnNonData, obj, &value_on_fallthrough,
branch_depth.depth);
+ } else if (opcode == kExprBrOnNonArray) {
+ CALL_INTERFACE(BrOnNonArray, obj, &value_on_fallthrough,
+ branch_depth.depth);
} else {
CALL_INTERFACE(BrOnNonI31, obj, &value_on_fallthrough,
branch_depth.depth);
@@ -4973,10 +4990,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
unsigned DecodeNumericOpcode(WasmOpcode opcode, uint32_t opcode_length) {
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
- if (!VALIDATE(sig != nullptr)) {
- this->DecodeError("invalid numeric opcode");
- return 0;
- }
switch (opcode) {
case kExprI32SConvertSatF32:
case kExprI32UConvertSatF32:
@@ -4992,10 +5005,11 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprMemoryInit: {
MemoryInitImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
- Value size = Peek(0, 2, sig->GetParam(2));
- Value src = Peek(1, 1, sig->GetParam(1));
- Value dst = Peek(2, 0, sig->GetParam(0));
- CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryInit, imm, dst, src, size);
+ ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32;
+ Value size = Peek(0, 2, kWasmI32);
+ Value offset = Peek(1, 1, kWasmI32);
+ Value dst = Peek(2, 0, mem_type);
+ CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryInit, imm, dst, offset, size);
Drop(3);
return opcode_length + imm.length;
}
@@ -5011,9 +5025,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprMemoryCopy: {
MemoryCopyImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
- Value size = Peek(0, 2, sig->GetParam(2));
- Value src = Peek(1, 1, sig->GetParam(1));
- Value dst = Peek(2, 0, sig->GetParam(0));
+ ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32;
+ Value size = Peek(0, 2, mem_type);
+ Value src = Peek(1, 1, mem_type);
+ Value dst = Peek(2, 0, mem_type);
CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryCopy, imm, dst, src, size);
Drop(3);
return opcode_length + imm.length;
@@ -5021,9 +5036,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprMemoryFill: {
MemoryIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
- Value size = Peek(0, 2, sig->GetParam(2));
- Value value = Peek(1, 1, sig->GetParam(1));
- Value dst = Peek(2, 0, sig->GetParam(0));
+ ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32;
+ Value size = Peek(0, 2, mem_type);
+ Value value = Peek(1, 1, kWasmI32);
+ Value dst = Peek(2, 0, mem_type);
CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryFill, imm, dst, value, size);
Drop(3);
return opcode_length + imm.length;
@@ -5059,7 +5075,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
"table index");
if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0;
- Value delta = Peek(0, 1, sig->GetParam(1));
+ Value delta = Peek(0, 1, kWasmI32);
Value value = Peek(1, 0, this->module_->tables[imm.index].type);
Value result = CreateValue(kWasmI32);
CALL_INTERFACE_IF_OK_AND_REACHABLE(TableGrow, imm, value, delta,
@@ -5081,9 +5097,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
IndexImmediate<validate> imm(this, this->pc_ + opcode_length,
"table index");
if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0;
- Value count = Peek(0, 2, sig->GetParam(2));
+ Value count = Peek(0, 2, kWasmI32);
Value value = Peek(1, 1, this->module_->tables[imm.index].type);
- Value start = Peek(2, 0, sig->GetParam(0));
+ Value start = Peek(2, 0, kWasmI32);
CALL_INTERFACE_IF_OK_AND_REACHABLE(TableFill, imm, start, value, count);
Drop(3);
return opcode_length + imm.length;
@@ -5183,7 +5199,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
V8_INLINE Value Peek(int depth, int index, ValueType expected) {
- Value val = Peek(depth, index);
+ Value val = Peek(depth);
if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) ||
val.type == kWasmBottom || expected == kWasmBottom)) {
PopTypeError(index, val, expected);
@@ -5191,7 +5207,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return val;
}
- V8_INLINE Value Peek(int depth, int index) {
+ V8_INLINE Value Peek(int depth) {
DCHECK(!control_.empty());
uint32_t limit = control_.back().stack_depth;
if (V8_UNLIKELY(stack_size() <= limit + depth)) {
@@ -5407,11 +5423,13 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
int BuildSimpleOperator(WasmOpcode opcode, const FunctionSig* sig) {
DCHECK_GE(1, sig->return_count());
- ValueType ret = sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(0);
if (sig->parameter_count() == 1) {
- return BuildSimpleOperator(opcode, ret, sig->GetParam(0));
+ // All current simple unary operators have exactly 1 return value.
+ DCHECK_EQ(1, sig->return_count());
+ return BuildSimpleOperator(opcode, sig->GetReturn(0), sig->GetParam(0));
} else {
DCHECK_EQ(2, sig->parameter_count());
+ ValueType ret = sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(0);
return BuildSimpleOperator(opcode, ret, sig->GetParam(0),
sig->GetParam(1));
}
@@ -5419,16 +5437,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
ValueType arg_type) {
+ DCHECK_NE(kWasmVoid, return_type);
Value val = Peek(0, 0, arg_type);
- if (return_type == kWasmVoid) {
- CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, opcode, val, nullptr);
- Drop(val);
- } else {
- Value ret = CreateValue(return_type);
- CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, opcode, val, &ret);
- Drop(val);
- Push(ret);
- }
+ Value ret = CreateValue(return_type);
+ CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, opcode, val, &ret);
+ Drop(val);
+ Push(ret);
return 1;
}