[wasm] Implement the Extended Constants proposal

This proposal adds i32 and i64 addition, subtraction, and multiplication
to the list of constant expressions.
See https://github.com/WebAssembly/extended-const.

Bug: v8:12089
Change-Id: I23a27a54a15fd37ee1d553992ab3b355eb9d317c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3497665
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79362}
This commit is contained in:
Manos Koukoutos 2022-03-04 08:03:41 +00:00 committed by V8 LUCI CQ
parent 6b565a04f2
commit bf1565d708
8 changed files with 364 additions and 133 deletions

View File

@ -910,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) \
@ -935,8 +937,6 @@ struct ControlBase : public PcForErrors<validate> {
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) \
@ -2560,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) {
@ -3501,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);

View File

@ -44,6 +44,40 @@ void InitExprInterface::S128Const(FullDecoder* decoder,
result->runtime_value = WasmValue(imm.value, kWasmS128);
}
void InitExprInterface::BinOp(FullDecoder* decoder, WasmOpcode opcode,
const Value& lhs, const Value& rhs,
Value* result) {
if (!generate_result()) return;
switch (opcode) {
case kExprI32Add:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i32() + rhs.runtime_value.to_i32());
break;
case kExprI32Sub:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i32() - rhs.runtime_value.to_i32());
break;
case kExprI32Mul:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i32() * rhs.runtime_value.to_i32());
break;
case kExprI64Add:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i64() + rhs.runtime_value.to_i64());
break;
case kExprI64Sub:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i64() - rhs.runtime_value.to_i64());
break;
case kExprI64Mul:
result->runtime_value =
WasmValue(lhs.runtime_value.to_i64() * rhs.runtime_value.to_i64());
break;
default:
UNREACHABLE();
}
}
void InitExprInterface::RefNull(FullDecoder* decoder, ValueType type,
Value* result) {
if (!generate_result()) return;

View File

@ -64,7 +64,12 @@
/* Stack Switching proposal. */ \
/* https://github.com/WebAssembly/stack-switching */ \
/* V8 side owner: thibaudm, fgm */ \
V(stack_switching, "stack switching", false)
V(stack_switching, "stack switching", false) \
\
/* Extended Constant Expressions Proposal. */ \
/* https://github.com/WebAssembly/extended-const */ \
/* V8 side owner: manoskouk */ \
V(extended_const, "extended constant expressions", false)
// #############################################################################
// Staged features (disabled by default, but enabled via --wasm-staging (also

View File

@ -116,136 +116,145 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(MemoryGrow, 0x40, i_i)
// Expressions with signatures.
#define FOREACH_SIMPLE_OPCODE(V) \
V(I32Eqz, 0x45, i_i) \
V(I32Eq, 0x46, i_ii) \
V(I32Ne, 0x47, i_ii) \
V(I32LtS, 0x48, i_ii) \
V(I32LtU, 0x49, i_ii) \
V(I32GtS, 0x4a, i_ii) \
V(I32GtU, 0x4b, i_ii) \
V(I32LeS, 0x4c, i_ii) \
V(I32LeU, 0x4d, i_ii) \
V(I32GeS, 0x4e, i_ii) \
V(I32GeU, 0x4f, i_ii) \
V(I64Eqz, 0x50, i_l) \
V(I64Eq, 0x51, i_ll) \
V(I64Ne, 0x52, i_ll) \
V(I64LtS, 0x53, i_ll) \
V(I64LtU, 0x54, i_ll) \
V(I64GtS, 0x55, i_ll) \
V(I64GtU, 0x56, i_ll) \
V(I64LeS, 0x57, i_ll) \
V(I64LeU, 0x58, i_ll) \
V(I64GeS, 0x59, i_ll) \
V(I64GeU, 0x5a, i_ll) \
V(F32Eq, 0x5b, i_ff) \
V(F32Ne, 0x5c, i_ff) \
V(F32Lt, 0x5d, i_ff) \
V(F32Gt, 0x5e, i_ff) \
V(F32Le, 0x5f, i_ff) \
V(F32Ge, 0x60, i_ff) \
V(F64Eq, 0x61, i_dd) \
V(F64Ne, 0x62, i_dd) \
V(F64Lt, 0x63, i_dd) \
V(F64Gt, 0x64, i_dd) \
V(F64Le, 0x65, i_dd) \
V(F64Ge, 0x66, i_dd) \
V(I32Clz, 0x67, i_i) \
V(I32Ctz, 0x68, i_i) \
V(I32Popcnt, 0x69, i_i) \
V(I32Add, 0x6a, i_ii) \
V(I32Sub, 0x6b, i_ii) \
V(I32Mul, 0x6c, i_ii) \
V(I32DivS, 0x6d, i_ii) \
V(I32DivU, 0x6e, i_ii) \
V(I32RemS, 0x6f, i_ii) \
V(I32RemU, 0x70, i_ii) \
V(I32And, 0x71, i_ii) \
V(I32Ior, 0x72, i_ii) \
V(I32Xor, 0x73, i_ii) \
V(I32Shl, 0x74, i_ii) \
V(I32ShrS, 0x75, i_ii) \
V(I32ShrU, 0x76, i_ii) \
V(I32Rol, 0x77, i_ii) \
V(I32Ror, 0x78, i_ii) \
V(I64Clz, 0x79, l_l) \
V(I64Ctz, 0x7a, l_l) \
V(I64Popcnt, 0x7b, l_l) \
V(I64Add, 0x7c, l_ll) \
V(I64Sub, 0x7d, l_ll) \
V(I64Mul, 0x7e, l_ll) \
V(I64DivS, 0x7f, l_ll) \
V(I64DivU, 0x80, l_ll) \
V(I64RemS, 0x81, l_ll) \
V(I64RemU, 0x82, l_ll) \
V(I64And, 0x83, l_ll) \
V(I64Ior, 0x84, l_ll) \
V(I64Xor, 0x85, l_ll) \
V(I64Shl, 0x86, l_ll) \
V(I64ShrS, 0x87, l_ll) \
V(I64ShrU, 0x88, l_ll) \
V(I64Rol, 0x89, l_ll) \
V(I64Ror, 0x8a, l_ll) \
V(F32Abs, 0x8b, f_f) \
V(F32Neg, 0x8c, f_f) \
V(F32Ceil, 0x8d, f_f) \
V(F32Floor, 0x8e, f_f) \
V(F32Trunc, 0x8f, f_f) \
V(F32NearestInt, 0x90, f_f) \
V(F32Sqrt, 0x91, f_f) \
V(F32Add, 0x92, f_ff) \
V(F32Sub, 0x93, f_ff) \
V(F32Mul, 0x94, f_ff) \
V(F32Div, 0x95, f_ff) \
V(F32Min, 0x96, f_ff) \
V(F32Max, 0x97, f_ff) \
V(F32CopySign, 0x98, f_ff) \
V(F64Abs, 0x99, d_d) \
V(F64Neg, 0x9a, d_d) \
V(F64Ceil, 0x9b, d_d) \
V(F64Floor, 0x9c, d_d) \
V(F64Trunc, 0x9d, d_d) \
V(F64NearestInt, 0x9e, d_d) \
V(F64Sqrt, 0x9f, d_d) \
V(F64Add, 0xa0, d_dd) \
V(F64Sub, 0xa1, d_dd) \
V(F64Mul, 0xa2, d_dd) \
V(F64Div, 0xa3, d_dd) \
V(F64Min, 0xa4, d_dd) \
V(F64Max, 0xa5, d_dd) \
V(F64CopySign, 0xa6, d_dd) \
V(I32ConvertI64, 0xa7, i_l) \
V(I32SConvertF32, 0xa8, i_f) \
V(I32UConvertF32, 0xa9, i_f) \
V(I32SConvertF64, 0xaa, i_d) \
V(I32UConvertF64, 0xab, i_d) \
V(I64SConvertI32, 0xac, l_i) \
V(I64UConvertI32, 0xad, l_i) \
V(I64SConvertF32, 0xae, l_f) \
V(I64UConvertF32, 0xaf, l_f) \
V(I64SConvertF64, 0xb0, l_d) \
V(I64UConvertF64, 0xb1, l_d) \
V(F32SConvertI32, 0xb2, f_i) \
V(F32UConvertI32, 0xb3, f_i) \
V(F32SConvertI64, 0xb4, f_l) \
V(F32UConvertI64, 0xb5, f_l) \
V(F32ConvertF64, 0xb6, f_d) \
V(F64SConvertI32, 0xb7, d_i) \
V(F64UConvertI32, 0xb8, d_i) \
V(F64SConvertI64, 0xb9, d_l) \
V(F64UConvertI64, 0xba, d_l) \
V(F64ConvertF32, 0xbb, d_f) \
V(I32ReinterpretF32, 0xbc, i_f) \
V(I64ReinterpretF64, 0xbd, l_d) \
V(F32ReinterpretI32, 0xbe, f_i) \
V(F64ReinterpretI64, 0xbf, d_l) \
V(I32SExtendI8, 0xc0, i_i) \
V(I32SExtendI16, 0xc1, i_i) \
V(I64SExtendI8, 0xc2, l_l) \
V(I64SExtendI16, 0xc3, l_l) \
// The following opcodes can be used as constant expressions under
// --experimental-wasm-extended-const.
#define FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(V) \
V(I32Add, 0x6a, i_ii) \
V(I32Sub, 0x6b, i_ii) \
V(I32Mul, 0x6c, i_ii) \
V(I64Add, 0x7c, l_ll) \
V(I64Sub, 0x7d, l_ll) \
V(I64Mul, 0x7e, l_ll)
#define FOREACH_SIMPLE_NON_CONST_OPCODE(V) \
V(I32Eqz, 0x45, i_i) \
V(I32Eq, 0x46, i_ii) \
V(I32Ne, 0x47, i_ii) \
V(I32LtS, 0x48, i_ii) \
V(I32LtU, 0x49, i_ii) \
V(I32GtS, 0x4a, i_ii) \
V(I32GtU, 0x4b, i_ii) \
V(I32LeS, 0x4c, i_ii) \
V(I32LeU, 0x4d, i_ii) \
V(I32GeS, 0x4e, i_ii) \
V(I32GeU, 0x4f, i_ii) \
V(I64Eqz, 0x50, i_l) \
V(I64Eq, 0x51, i_ll) \
V(I64Ne, 0x52, i_ll) \
V(I64LtS, 0x53, i_ll) \
V(I64LtU, 0x54, i_ll) \
V(I64GtS, 0x55, i_ll) \
V(I64GtU, 0x56, i_ll) \
V(I64LeS, 0x57, i_ll) \
V(I64LeU, 0x58, i_ll) \
V(I64GeS, 0x59, i_ll) \
V(I64GeU, 0x5a, i_ll) \
V(F32Eq, 0x5b, i_ff) \
V(F32Ne, 0x5c, i_ff) \
V(F32Lt, 0x5d, i_ff) \
V(F32Gt, 0x5e, i_ff) \
V(F32Le, 0x5f, i_ff) \
V(F32Ge, 0x60, i_ff) \
V(F64Eq, 0x61, i_dd) \
V(F64Ne, 0x62, i_dd) \
V(F64Lt, 0x63, i_dd) \
V(F64Gt, 0x64, i_dd) \
V(F64Le, 0x65, i_dd) \
V(F64Ge, 0x66, i_dd) \
V(I32Clz, 0x67, i_i) \
V(I32Ctz, 0x68, i_i) \
V(I32Popcnt, 0x69, i_i) \
V(I32DivS, 0x6d, i_ii) \
V(I32DivU, 0x6e, i_ii) \
V(I32RemS, 0x6f, i_ii) \
V(I32RemU, 0x70, i_ii) \
V(I32And, 0x71, i_ii) \
V(I32Ior, 0x72, i_ii) \
V(I32Xor, 0x73, i_ii) \
V(I32Shl, 0x74, i_ii) \
V(I32ShrS, 0x75, i_ii) \
V(I32ShrU, 0x76, i_ii) \
V(I32Rol, 0x77, i_ii) \
V(I32Ror, 0x78, i_ii) \
V(I64Clz, 0x79, l_l) \
V(I64Ctz, 0x7a, l_l) \
V(I64Popcnt, 0x7b, l_l) \
V(I64DivS, 0x7f, l_ll) \
V(I64DivU, 0x80, l_ll) \
V(I64RemS, 0x81, l_ll) \
V(I64RemU, 0x82, l_ll) \
V(I64And, 0x83, l_ll) \
V(I64Ior, 0x84, l_ll) \
V(I64Xor, 0x85, l_ll) \
V(I64Shl, 0x86, l_ll) \
V(I64ShrS, 0x87, l_ll) \
V(I64ShrU, 0x88, l_ll) \
V(I64Rol, 0x89, l_ll) \
V(I64Ror, 0x8a, l_ll) \
V(F32Abs, 0x8b, f_f) \
V(F32Neg, 0x8c, f_f) \
V(F32Ceil, 0x8d, f_f) \
V(F32Floor, 0x8e, f_f) \
V(F32Trunc, 0x8f, f_f) \
V(F32NearestInt, 0x90, f_f) \
V(F32Sqrt, 0x91, f_f) \
V(F32Add, 0x92, f_ff) \
V(F32Sub, 0x93, f_ff) \
V(F32Mul, 0x94, f_ff) \
V(F32Div, 0x95, f_ff) \
V(F32Min, 0x96, f_ff) \
V(F32Max, 0x97, f_ff) \
V(F32CopySign, 0x98, f_ff) \
V(F64Abs, 0x99, d_d) \
V(F64Neg, 0x9a, d_d) \
V(F64Ceil, 0x9b, d_d) \
V(F64Floor, 0x9c, d_d) \
V(F64Trunc, 0x9d, d_d) \
V(F64NearestInt, 0x9e, d_d) \
V(F64Sqrt, 0x9f, d_d) \
V(F64Add, 0xa0, d_dd) \
V(F64Sub, 0xa1, d_dd) \
V(F64Mul, 0xa2, d_dd) \
V(F64Div, 0xa3, d_dd) \
V(F64Min, 0xa4, d_dd) \
V(F64Max, 0xa5, d_dd) \
V(F64CopySign, 0xa6, d_dd) \
V(I32ConvertI64, 0xa7, i_l) \
V(I32SConvertF32, 0xa8, i_f) \
V(I32UConvertF32, 0xa9, i_f) \
V(I32SConvertF64, 0xaa, i_d) \
V(I32UConvertF64, 0xab, i_d) \
V(I64SConvertI32, 0xac, l_i) \
V(I64UConvertI32, 0xad, l_i) \
V(I64SConvertF32, 0xae, l_f) \
V(I64UConvertF32, 0xaf, l_f) \
V(I64SConvertF64, 0xb0, l_d) \
V(I64UConvertF64, 0xb1, l_d) \
V(F32SConvertI32, 0xb2, f_i) \
V(F32UConvertI32, 0xb3, f_i) \
V(F32SConvertI64, 0xb4, f_l) \
V(F32UConvertI64, 0xb5, f_l) \
V(F32ConvertF64, 0xb6, f_d) \
V(F64SConvertI32, 0xb7, d_i) \
V(F64UConvertI32, 0xb8, d_i) \
V(F64SConvertI64, 0xb9, d_l) \
V(F64UConvertI64, 0xba, d_l) \
V(F64ConvertF32, 0xbb, d_f) \
V(I32ReinterpretF32, 0xbc, i_f) \
V(I64ReinterpretF64, 0xbd, l_d) \
V(F32ReinterpretI32, 0xbe, f_i) \
V(F64ReinterpretI64, 0xbf, d_l) \
V(I32SExtendI8, 0xc0, i_i) \
V(I32SExtendI16, 0xc1, i_i) \
V(I64SExtendI8, 0xc2, l_l) \
V(I64SExtendI16, 0xc3, l_l) \
V(I64SExtendI32, 0xc4, l_l)
#define FOREACH_SIMPLE_OPCODE(V) \
FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(V) \
FOREACH_SIMPLE_NON_CONST_OPCODE(V)
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) V(RefEq, 0xd5, i_qq)
// For compatibility with Asm.js.

View File

@ -339,6 +339,12 @@ class InitExprInterface {
result->init_expr = WasmInitExpr(imm.value);
}
void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs,
const Value& rhs, Value* result) {
// TODO(12089): Implement.
UNIMPLEMENTED();
}
void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
result->init_expr = WasmInitExpr::RefNullConst(type.heap_representation());
}

View File

@ -0,0 +1,74 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-extended-const
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
(function ExtendedConstantsTestI32() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let imported_global_0 = builder.addImportedGlobal("m", "g0", kWasmI32, false);
let imported_global_1 = builder.addImportedGlobal("m", "g1", kWasmI32, false);
let defined_global = builder.addGlobal(
kWasmI32, false,
WasmInitExpr.I32Add(
WasmInitExpr.GlobalGet(imported_global_0),
WasmInitExpr.I32Mul(
WasmInitExpr.GlobalGet(imported_global_1),
WasmInitExpr.I32Sub(
WasmInitExpr.GlobalGet(imported_global_0),
WasmInitExpr.I32Const(1)))));
builder.addExportOfKind("global", kExternalGlobal, defined_global.index);
let value0 = 123;
let value1 = -450;
let global_obj0 = new WebAssembly.Global({value: "i32", mutable: false},
value0);
let global_obj1 = new WebAssembly.Global({value: "i32", mutable: false},
value1);
let instance = builder.instantiate({m : {g0: global_obj0, g1: global_obj1}});
assertEquals(value0 + (value1 * (value0 - 1)), instance.exports.global.value);
})();
(function ExtendedConstantsTestI64() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let imported_global_0 = builder.addImportedGlobal("m", "g0", kWasmI64, false);
let imported_global_1 = builder.addImportedGlobal("m", "g1", kWasmI64, false);
let defined_global = builder.addGlobal(
kWasmI64, false,
WasmInitExpr.I64Add(
WasmInitExpr.GlobalGet(imported_global_0),
WasmInitExpr.I64Mul(
WasmInitExpr.GlobalGet(imported_global_1),
WasmInitExpr.I64Sub(
WasmInitExpr.GlobalGet(imported_global_0),
WasmInitExpr.I64Const(1)))));
builder.addExportOfKind("global", kExternalGlobal, defined_global.index);
let value0 = 123n;
let value1 = -450n;
let global_obj0 = new WebAssembly.Global({value: "i64", mutable: false},
value0);
let global_obj1 = new WebAssembly.Global({value: "i64", mutable: false},
value1);
let instance = builder.instantiate({m : {g0: global_obj0, g1: global_obj1}});
assertEquals(value0 + (value1 * (value0 - 1n)),
instance.exports.global.value);
})();

View File

@ -1016,6 +1016,16 @@ class Binary {
case kSimdPrefix:
this.emit_bytes(wasmS128Const(expr.value));
break;
case kExprI32Add:
case kExprI32Sub:
case kExprI32Mul:
case kExprI64Add:
case kExprI64Sub:
case kExprI64Mul:
this.emit_init_expr_recursive(expr.operands[0]);
this.emit_init_expr_recursive(expr.operands[1]);
this.emit_u8(expr.kind);
break;
case kExprRefFunc:
this.emit_u8(kExprRefFunc);
this.emit_u32v(expr.value);
@ -1192,6 +1202,24 @@ class WasmInitExpr {
static S128Const(value) {
return {kind: kSimdPrefix, value: value};
}
static I32Add(lhs, rhs) {
return {kind: kExprI32Add, operands: [lhs, rhs]};
}
static I32Sub(lhs, rhs) {
return {kind: kExprI32Sub, operands: [lhs, rhs]};
}
static I32Mul(lhs, rhs) {
return {kind: kExprI32Mul, operands: [lhs, rhs]};
}
static I64Add(lhs, rhs) {
return {kind: kExprI64Add, operands: [lhs, rhs]};
}
static I64Sub(lhs, rhs) {
return {kind: kExprI64Sub, operands: [lhs, rhs]};
}
static I64Mul(lhs, rhs) {
return {kind: kExprI64Mul, operands: [lhs, rhs]};
}
static GlobalGet(index) {
return {kind: kExprGlobalGet, value: index};
}

View File

@ -2048,6 +2048,65 @@ TEST_F(WasmModuleVerifyTest, ElementSectionGlobalGetOutOfBounds) {
EXPECT_FAILURE_WITH_MSG(data, "Invalid global index: 0");
}
// Make sure extended constants do not work without the experimental feature.
TEST_F(WasmModuleVerifyTest, ExtendedConstantsFail) {
static const byte data[] = {
SECTION(Import, ENTRY_COUNT(1), // one import
0x01, 'm', 0x01, 'g', // module, name
kExternalGlobal, kI32Code, 0), // type, mutability
SECTION(Global, ENTRY_COUNT(1), // one defined global
kI32Code, 0, // type, mutability
// initializer
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI32Add,
kExprEnd)};
EXPECT_FAILURE_WITH_MSG(data,
"opcode i32.add is not allowed in init. expressions");
}
TEST_F(WasmModuleVerifyTest, ExtendedConstantsI32) {
WASM_FEATURE_SCOPE(extended_const);
static const byte data[] = {
SECTION(Import, ENTRY_COUNT(1), // one import
0x01, 'm', 0x01, 'g', // module, name
kExternalGlobal, kI32Code, 0), // type, mutability
SECTION(Global, ENTRY_COUNT(1), // one defined global
kI32Code, 0, // type, mutability
// initializer
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI32Add,
kExprGlobalGet, 0x00, kExprI32Sub, kExprGlobalGet, 0x00,
kExprI32Mul, kExprEnd)};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, ExtendedConstantsI64) {
WASM_FEATURE_SCOPE(extended_const);
static const byte data[] = {
SECTION(Import, ENTRY_COUNT(1), // one import
0x01, 'm', 0x01, 'g', // module, name
kExternalGlobal, kI64Code, 0), // type, mutability
SECTION(Global, ENTRY_COUNT(1), // one defined global
kI64Code, 0, // type, mutability
// initializer
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI64Add,
kExprGlobalGet, 0x00, kExprI64Sub, kExprGlobalGet, 0x00,
kExprI64Mul, kExprEnd)};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, ExtendedConstantsTypeError) {
WASM_FEATURE_SCOPE(extended_const);
static const byte data[] = {
SECTION(Import, ENTRY_COUNT(1), // one import
0x01, 'm', 0x01, 'g', // module, name
kExternalGlobal, kI32Code, 0), // type, mutability
SECTION(Global, ENTRY_COUNT(1), // one defined global
kI32Code, 0, // type, mutability
// initializer
kExprGlobalGet, 0x00, kExprI64Const, 1, kExprI32Add, kExprEnd)};
EXPECT_FAILURE_WITH_MSG(
data, "i32.add[1] expected type i32, found i64.const of type i64");
}
TEST_F(WasmModuleVerifyTest, IndirectFunctionNoFunctions) {
static const byte data[] = {
// sig#0 -------------------------------------------------------