Commit 0a69768a authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Implement ref.as_non_null, optimize struct instructions.

Implement the instruction ref.as_non_null, as per the wasm gc extension.

Changes:
- Add the respective wasm opcode, move some asmjs opcodes around.
- Add a new type of wasm trap, IllegalCast.
- Modify wasm decoding and compilation pipeline.
- Add a minimal test.
- In wasm-compiler, generalize Unreachable to Trap.
- Optimize struct.get and struct.set for non-null types.

Bug: v8:7748
Change-Id: If2f794306c7cbfabc06e4f64988132346085d6dd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2187616
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67705}
parent c74010bf
...@@ -323,6 +323,7 @@ extern enum MessageTemplate { ...@@ -323,6 +323,7 @@ extern enum MessageTemplate {
kWasmTrapBrOnExnNullRef, kWasmTrapBrOnExnNullRef,
kWasmTrapRethrowNullRef, kWasmTrapRethrowNullRef,
kWasmTrapNullDereference, kWasmTrapNullDereference,
kWasmTrapIllegalCast,
... ...
} }
......
...@@ -264,4 +264,8 @@ namespace wasm { ...@@ -264,4 +264,8 @@ namespace wasm {
builtin ThrowWasmTrapNullDereference(): JSAny { builtin ThrowWasmTrapNullDereference(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference)); tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference));
} }
builtin ThrowWasmTrapIllegalCast(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast));
}
} }
...@@ -1594,7 +1594,8 @@ enum class LoadSensitivity { ...@@ -1594,7 +1594,8 @@ enum class LoadSensitivity {
V(TrapTableOutOfBounds) \ V(TrapTableOutOfBounds) \
V(TrapBrOnExnNullRef) \ V(TrapBrOnExnNullRef) \
V(TrapRethrowNullRef) \ V(TrapRethrowNullRef) \
V(TrapNullDereference) V(TrapNullDereference) \
V(TrapIllegalCast)
enum KeyedAccessLoadMode { enum KeyedAccessLoadMode {
STANDARD_LOAD, STANDARD_LOAD,
......
...@@ -554,6 +554,7 @@ namespace internal { ...@@ -554,6 +554,7 @@ namespace internal {
T(WasmTrapBrOnExnNullRef, "br_on_exn on nullref value") \ T(WasmTrapBrOnExnNullRef, "br_on_exn on nullref value") \
T(WasmTrapRethrowNullRef, "rethrowing nullref value") \ T(WasmTrapRethrowNullRef, "rethrowing nullref value") \
T(WasmTrapNullDereference, "dereferencing a null pointer") \ T(WasmTrapNullDereference, "dereferencing a null pointer") \
T(WasmTrapIllegalCast, "illegal cast") \
T(WasmExceptionError, "wasm exception") \ T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \ /* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \ T(AsmJsInvalid, "Invalid asm.js: %") \
......
...@@ -299,6 +299,13 @@ Node* WasmGraphBuilder::RefFunc(uint32_t function_index) { ...@@ -299,6 +299,13 @@ Node* WasmGraphBuilder::RefFunc(uint32_t function_index) {
Uint32Constant(function_index), effect(), control())); Uint32Constant(function_index), effect(), control()));
} }
Node* WasmGraphBuilder::RefAsNonNull(Node* arg,
wasm::WasmCodePosition position) {
TrapIfTrue(wasm::kTrapIllegalCast, gasm_->WordEqual(arg, RefNull()),
position);
return arg;
}
Node* WasmGraphBuilder::NoContextConstant() { Node* WasmGraphBuilder::NoContextConstant() {
return mcgraph()->IntPtrConstant(0); return mcgraph()->IntPtrConstant(0);
} }
...@@ -1115,8 +1122,9 @@ Node* WasmGraphBuilder::Return(Vector<Node*> vals) { ...@@ -1115,8 +1122,9 @@ Node* WasmGraphBuilder::Return(Vector<Node*> vals) {
return ret; return ret;
} }
Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) { Node* WasmGraphBuilder::Trap(wasm::TrapReason reason,
TrapIfFalse(wasm::TrapReason::kTrapUnreachable, Int32Constant(0), position); wasm::WasmCodePosition position) {
TrapIfFalse(reason, Int32Constant(0), position);
Return(Vector<Node*>{}); Return(Vector<Node*>{});
return nullptr; return nullptr;
} }
...@@ -5135,24 +5143,29 @@ Node* WasmGraphBuilder::ArrayNew(uint32_t array_index, ...@@ -5135,24 +5143,29 @@ Node* WasmGraphBuilder::ArrayNew(uint32_t array_index,
} }
Node* WasmGraphBuilder::StructGet(Node* struct_object, Node* WasmGraphBuilder::StructGet(Node* struct_object,
const wasm::StructType* type, const wasm::StructType* struct_type,
uint32_t field_index, uint32_t field_index, CheckForNull null_check,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
MachineType machine_type = FieldType(type, field_index); if (null_check == kWithNullCheck) {
Node* offset = FieldOffset(mcgraph(), type, field_index);
TrapIfTrue(wasm::kTrapNullDereference, TrapIfTrue(wasm::kTrapNullDereference,
gasm_->WordEqual(struct_object, RefNull()), position); gasm_->WordEqual(struct_object, RefNull()), position);
}
MachineType machine_type = FieldType(struct_type, field_index);
Node* offset = FieldOffset(mcgraph(), struct_type, field_index);
return gasm_->Load(machine_type, struct_object, offset); return gasm_->Load(machine_type, struct_object, offset);
} }
Node* WasmGraphBuilder::StructSet(Node* struct_object, Node* WasmGraphBuilder::StructSet(Node* struct_object,
const wasm::StructType* type, const wasm::StructType* struct_type,
uint32_t field_index, Node* field_value, uint32_t field_index, Node* field_value,
CheckForNull null_check,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) {
TrapIfTrue(wasm::kTrapNullDereference, TrapIfTrue(wasm::kTrapNullDereference,
gasm_->WordEqual(struct_object, RefNull()), position); gasm_->WordEqual(struct_object, RefNull()), position);
return StoreStructFieldUnchecked(mcgraph(), gasm_.get(), struct_object, type, }
field_index, field_value); return StoreStructFieldUnchecked(mcgraph(), gasm_.get(), struct_object,
struct_type, field_index, field_value);
} }
class WasmDecorator final : public GraphDecorator { class WasmDecorator final : public GraphDecorator {
......
...@@ -162,6 +162,10 @@ class WasmGraphBuilder { ...@@ -162,6 +162,10 @@ class WasmGraphBuilder {
kRetpoline = true, kRetpoline = true,
kNoRetpoline = false kNoRetpoline = false
}; };
enum CheckForNull : bool { // --
kWithNullCheck = true,
kWithoutNullCheck = false
};
V8_EXPORT_PRIVATE WasmGraphBuilder( V8_EXPORT_PRIVATE WasmGraphBuilder(
wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph, wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph,
...@@ -187,6 +191,7 @@ class WasmGraphBuilder { ...@@ -187,6 +191,7 @@ class WasmGraphBuilder {
Node* EffectPhi(unsigned count, Node** effects_and_control); Node* EffectPhi(unsigned count, Node** effects_and_control);
Node* RefNull(); Node* RefNull();
Node* RefFunc(uint32_t function_index); Node* RefFunc(uint32_t function_index);
Node* RefAsNonNull(Node* arg, wasm::WasmCodePosition position);
Node* Uint32Constant(uint32_t value); Node* Uint32Constant(uint32_t value);
Node* Int32Constant(int32_t value); Node* Int32Constant(int32_t value);
Node* Int64Constant(int64_t value); Node* Int64Constant(int64_t value);
...@@ -245,7 +250,7 @@ class WasmGraphBuilder { ...@@ -245,7 +250,7 @@ class WasmGraphBuilder {
Node* arr[] = {fst, more...}; Node* arr[] = {fst, more...};
return Return(ArrayVector(arr)); return Return(ArrayVector(arr));
} }
Node* Unreachable(wasm::WasmCodePosition position); Node* Trap(wasm::TrapReason reason, wasm::WasmCodePosition position);
Node* CallDirect(uint32_t index, Vector<Node*> args, Vector<Node*> rets, Node* CallDirect(uint32_t index, Vector<Node*> args, Vector<Node*> rets,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
...@@ -369,10 +374,11 @@ class WasmGraphBuilder { ...@@ -369,10 +374,11 @@ class WasmGraphBuilder {
Node* StructNew(uint32_t struct_index, const wasm::StructType* type, Node* StructNew(uint32_t struct_index, const wasm::StructType* type,
Vector<Node*> fields); Vector<Node*> fields);
Node* StructGet(Node* struct_object, const wasm::StructType* type, Node* StructGet(Node* struct_object, const wasm::StructType* struct_type,
uint32_t field_index, wasm::WasmCodePosition position); uint32_t field_index, CheckForNull null_check,
Node* StructSet(Node* struct_object, const wasm::StructType* type, wasm::WasmCodePosition position);
uint32_t field_index, Node* value, Node* StructSet(Node* struct_object, const wasm::StructType* struct_type,
uint32_t field_index, Node* value, CheckForNull null_check,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
Node* ArrayNew(uint32_t array_index, const wasm::ArrayType* type, Node* ArrayNew(uint32_t array_index, const wasm::ArrayType* type,
Node* length, Node* initial_value); Node* length, Node* initial_value);
......
...@@ -1513,6 +1513,10 @@ class LiftoffCompiler { ...@@ -1513,6 +1513,10 @@ class LiftoffCompiler {
unsupported(decoder, kAnyRef, "func"); unsupported(decoder, kAnyRef, "func");
} }
void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) {
unsupported(decoder, kAnyRef, "ref.as_non_null");
}
void Drop(FullDecoder* decoder, const Value& value) { void Drop(FullDecoder* decoder, const Value& value) {
auto& slot = __ cache_state()->stack_state.back(); auto& slot = __ cache_state()->stack_state.back();
// If the dropped slot contains a register, decrement it's use count. // If the dropped slot contains a register, decrement it's use count.
...@@ -3372,6 +3376,11 @@ class LiftoffCompiler { ...@@ -3372,6 +3376,11 @@ class LiftoffCompiler {
unsupported(decoder, kGC, "array.new"); unsupported(decoder, kGC, "array.new");
} }
void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "");
}
private: private:
// Emit additional source positions for return addresses. Used by debugging to // Emit additional source positions for return addresses. Used by debugging to
// OSR frames with different sets of breakpoints. // OSR frames with different sets of breakpoints.
......
...@@ -844,6 +844,7 @@ enum class LoadTransformationKind : uint8_t { ...@@ -844,6 +844,7 @@ enum class LoadTransformationKind : uint8_t {
F(F64Const, Value* result, double value) \ F(F64Const, Value* result, double value) \
F(RefNull, Value* result) \ F(RefNull, Value* result) \
F(RefFunc, uint32_t function_index, Value* result) \ F(RefFunc, uint32_t function_index, Value* result) \
F(RefAsNonNull, const Value& arg, Value* result) \
F(Drop, const Value& value) \ F(Drop, const Value& value) \
F(DoReturn, Vector<Value> values) \ F(DoReturn, Vector<Value> values) \
F(LocalGet, Value* result, const LocalIndexImmediate<validate>& imm) \ F(LocalGet, Value* result, const LocalIndexImmediate<validate>& imm) \
...@@ -916,7 +917,8 @@ enum class LoadTransformationKind : uint8_t { ...@@ -916,7 +917,8 @@ enum class LoadTransformationKind : uint8_t {
F(StructSet, const Value& struct_object, \ F(StructSet, const Value& struct_object, \
const FieldIndexImmediate<validate>& field, const Value& field_value) \ const FieldIndexImmediate<validate>& field, const Value& field_value) \
F(ArrayNew, const ArrayIndexImmediate<validate>& imm, const Value& length, \ F(ArrayNew, const ArrayIndexImmediate<validate>& imm, const Value& length, \
const Value& initial_value, Value* result) const Value& initial_value, Value* result) \
F(PassThrough, const Value& from, Value* to)
// Generic Wasm bytecode decoder with utilities for decoding immediates, // Generic Wasm bytecode decoder with utilities for decoding immediates,
// lengths, etc. // lengths, etc.
...@@ -1573,6 +1575,7 @@ class WasmDecoder : public Decoder { ...@@ -1573,6 +1575,7 @@ class WasmDecoder : public Decoder {
case kExprTableGet: case kExprTableGet:
case kExprLocalTee: case kExprLocalTee:
case kExprMemoryGrow: case kExprMemoryGrow:
case kExprRefAsNonNull:
return {1, 1}; return {1, 1};
case kExprLocalSet: case kExprLocalSet:
case kExprGlobalSet: case kExprGlobalSet:
...@@ -2235,6 +2238,35 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2235,6 +2238,35 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len = 1 + imm.length; len = 1 + imm.length;
break; break;
} }
case kExprRefAsNonNull: {
CHECK_PROTOTYPE_OPCODE(anyref);
auto value = Pop();
switch (value.type.kind()) {
case ValueType::kRef: {
auto* result =
Push(ValueType(ValueType::kRef, value.type.ref_index()));
CALL_INTERFACE_IF_REACHABLE(PassThrough, value, result);
break;
}
case ValueType::kOptRef: {
auto* result =
Push(ValueType(ValueType::kRef, value.type.ref_index()));
CALL_INTERFACE_IF_REACHABLE(RefAsNonNull, value, result);
break;
}
case ValueType::kNullRef:
// TODO(7748): Fix this once the standard clears up (see
// https://github.com/WebAssembly/function-references/issues/21).
CALL_INTERFACE_IF_REACHABLE(Unreachable);
EndControl();
break;
default:
this->error(this->pc_ + 1,
"invalid agrument type to ref.as_non_null");
break;
}
break;
}
case kExprLocalGet: { case kExprLocalGet: {
LocalIndexImmediate<validate> imm(this, this->pc_); LocalIndexImmediate<validate> imm(this, this->pc_);
if (!this->Validate(this->pc_, imm)) break; if (!this->Validate(this->pc_, imm)) break;
...@@ -2968,7 +3000,6 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2968,7 +3000,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
auto struct_obj = auto struct_obj =
Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index)); Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index));
auto* value = Push(field.struct_index.struct_type->field(field.index)); auto* value = Push(field.struct_index.struct_type->field(field.index));
// TODO(7748): Optimize this when struct type is null/ref
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, value); CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, value);
break; break;
} }
...@@ -2980,7 +3011,6 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2980,7 +3011,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
0, ValueType(field.struct_index.struct_type->field(field.index))); 0, ValueType(field.struct_index.struct_type->field(field.index)));
auto struct_obj = auto struct_obj =
Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index)); Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index));
// TODO(7748): Optimize this when struct type is null/ref
CALL_INTERFACE_IF_REACHABLE(StructSet, struct_obj, field, field_value); CALL_INTERFACE_IF_REACHABLE(StructSet, struct_obj, field, field_value);
break; break;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "src/wasm/decoder.h" #include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h" #include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/function-body-decoder.h" #include "src/wasm/function-body-decoder.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-linkage.h" #include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-module.h" #include "src/wasm/wasm-module.h"
...@@ -259,6 +260,10 @@ class WasmGraphBuildingInterface { ...@@ -259,6 +260,10 @@ class WasmGraphBuildingInterface {
result->node = BUILD(RefFunc, function_index); result->node = BUILD(RefFunc, function_index);
} }
void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) {
result->node = BUILD(RefAsNonNull, arg.node, decoder->position());
}
void Drop(FullDecoder* decoder, const Value& value) {} void Drop(FullDecoder* decoder, const Value& value) {}
void DoReturn(FullDecoder* decoder, Vector<Value> values) { void DoReturn(FullDecoder* decoder, Vector<Value> values) {
...@@ -307,7 +312,7 @@ class WasmGraphBuildingInterface { ...@@ -307,7 +312,7 @@ class WasmGraphBuildingInterface {
} }
void Unreachable(FullDecoder* decoder) { void Unreachable(FullDecoder* decoder) {
BUILD(Unreachable, decoder->position()); BUILD(Trap, wasm::TrapReason::kTrapUnreachable, decoder->position());
} }
void Select(FullDecoder* decoder, const Value& cond, const Value& fval, void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
...@@ -614,16 +619,24 @@ class WasmGraphBuildingInterface { ...@@ -614,16 +619,24 @@ class WasmGraphBuildingInterface {
void StructGet(FullDecoder* decoder, const Value& struct_object, void StructGet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field, Value* result) { const FieldIndexImmediate<validate>& field, Value* result) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = struct_object.type.kind() == ValueType::kRef
? CheckForNull::kWithoutNullCheck
: CheckForNull::kWithNullCheck;
result->node = result->node =
BUILD(StructGet, struct_object.node, field.struct_index.struct_type, BUILD(StructGet, struct_object.node, field.struct_index.struct_type,
field.index, decoder->position()); field.index, null_check, decoder->position());
} }
void StructSet(FullDecoder* decoder, const Value& struct_object, void StructSet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field, const FieldIndexImmediate<validate>& field,
const Value& field_value) { const Value& field_value) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = struct_object.type.kind() == ValueType::kRef
? CheckForNull::kWithoutNullCheck
: CheckForNull::kWithNullCheck;
BUILD(StructSet, struct_object.node, field.struct_index.struct_type, BUILD(StructSet, struct_object.node, field.struct_index.struct_type,
field.index, field_value.node, decoder->position()); field.index, field_value.node, null_check, decoder->position());
} }
void ArrayNew(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm, void ArrayNew(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
...@@ -633,6 +646,10 @@ class WasmGraphBuildingInterface { ...@@ -633,6 +646,10 @@ class WasmGraphBuildingInterface {
initial_value.node); initial_value.node);
} }
void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
to->node = from.node;
}
private: private:
SsaEnv* ssa_env_ = nullptr; SsaEnv* ssa_env_ = nullptr;
compiler::WasmGraphBuilder* builder_; compiler::WasmGraphBuilder* builder_;
......
...@@ -116,6 +116,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) { ...@@ -116,6 +116,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_REF_OP(Null, "null") CASE_REF_OP(Null, "null")
CASE_REF_OP(IsNull, "is_null") CASE_REF_OP(IsNull, "is_null")
CASE_REF_OP(Func, "func") CASE_REF_OP(Func, "func")
CASE_REF_OP(AsNonNull, "as_non_null")
CASE_I32_OP(ConvertI64, "wrap_i64") CASE_I32_OP(ConvertI64, "wrap_i64")
CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc") CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc") CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
...@@ -467,6 +468,7 @@ bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) { ...@@ -467,6 +468,7 @@ bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) {
case kExprRefNull: case kExprRefNull:
case kExprRefIsNull: case kExprRefIsNull:
case kExprRefFunc: case kExprRefFunc:
case kExprRefAsNonNull:
return true; return true;
default: default:
return false; return false;
......
...@@ -60,7 +60,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&); ...@@ -60,7 +60,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(F32Const, 0x43, _) \ V(F32Const, 0x43, _) \
V(F64Const, 0x44, _) \ V(F64Const, 0x44, _) \
V(RefNull, 0xd0, _) \ V(RefNull, 0xd0, _) \
V(RefFunc, 0xd2, _) V(RefFunc, 0xd2, _) \
V(RefAsNonNull, 0xd3, _)
// Load memory expressions. // Load memory expressions.
#define FOREACH_LOAD_MEM_OPCODE(V) \ #define FOREACH_LOAD_MEM_OPCODE(V) \
...@@ -229,7 +230,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&); ...@@ -229,7 +230,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \ #define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
V(RefIsNull, 0xd1, i_r) \ V(RefIsNull, 0xd1, i_r) \
V(RefEq, 0xd3, i_rr) /* made-up opcode, guessing future spec (GC) */ V(RefEq, 0xd5, i_rr) // made-up opcode, guessing future spec (GC)
// For compatibility with Asm.js. // For compatibility with Asm.js.
// These opcodes are not spec'ed (or visible) externally; the idea is // These opcodes are not spec'ed (or visible) externally; the idea is
...@@ -247,8 +248,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&); ...@@ -247,8 +248,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(F64Pow, 0xce, d_dd) \ V(F64Pow, 0xce, d_dd) \
V(F64Mod, 0xcf, d_dd) \ V(F64Mod, 0xcf, d_dd) \
V(I32AsmjsDivS, 0xe7, i_ii) \ V(I32AsmjsDivS, 0xe7, i_ii) \
V(I32AsmjsDivU, 0xd4, i_ii) \ V(I32AsmjsDivU, 0xe8, i_ii) \
V(I32AsmjsRemS, 0xd5, i_ii) \ V(I32AsmjsRemS, 0xe9, i_ii) \
V(I32AsmjsRemU, 0xd6, i_ii) \ V(I32AsmjsRemU, 0xd6, i_ii) \
V(I32AsmjsLoadMem8S, 0xd7, i_i) \ V(I32AsmjsLoadMem8S, 0xd7, i_i) \
V(I32AsmjsLoadMem8U, 0xd8, i_i) \ V(I32AsmjsLoadMem8U, 0xd8, i_i) \
......
...@@ -83,7 +83,8 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -83,7 +83,8 @@ WASM_EXEC_TEST(BasicStruct) {
kExprEnd}; kExprEnd};
j->EmitCode(j_code, sizeof(j_code)); j->EmitCode(j_code, sizeof(j_code));
// Test struct.set, struct refs types in globals and if-results. // Test struct.set, ref.as_non_null,
// struct refs types in globals and if-results.
uint32_t k_global_index = builder->AddGlobal(kOptRefType, true); uint32_t k_global_index = builder->AddGlobal(kOptRefType, true);
WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v()); WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v());
uint32_t k_field_index = 0; uint32_t k_field_index = 0;
...@@ -91,10 +92,10 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -91,10 +92,10 @@ WASM_EXEC_TEST(BasicStruct) {
byte k_code[] = { byte k_code[] = {
WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55),
WASM_I32V(66))), WASM_I32V(66))),
WASM_STRUCT_GET( WASM_STRUCT_GET(type_index, k_field_index,
type_index, k_field_index, WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(
WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1), kOptRefType, WASM_I32V(1),
WASM_GET_GLOBAL(k_global_index), WASM_REF_NULL)), WASM_GET_GLOBAL(k_global_index), WASM_REF_NULL))),
kExprEnd}; kExprEnd};
k->EmitCode(k_code, sizeof(k_code)); k->EmitCode(k_code, sizeof(k_code));
......
...@@ -435,6 +435,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) { ...@@ -435,6 +435,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_REF_NULL kExprRefNull #define WASM_REF_NULL kExprRefNull
#define WASM_REF_FUNC(val) kExprRefFunc, val #define WASM_REF_FUNC(val) kExprRefFunc, val
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull #define WASM_REF_IS_NULL(val) val, kExprRefIsNull
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
#define WASM_ARRAY_NEW(index, default_value, length) \ #define WASM_ARRAY_NEW(index, default_value, length) \
default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index) default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment