[wasm-gc] Trap parameter for AssertNotNull

The AssertNotNull operator can be used to represent a trivial type
cast. Therefore it needs to take the trap id as a parameter.
We also use this operator in one more place in
{graph-builder-interface}.

Bug: v8:7748
Change-Id: I679c996ef07063c03e1103acac1db91184b15c0e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4061514
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84543}
This commit is contained in:
Manos Koukoutos 2022-11-29 10:53:12 +01:00 committed by V8 LUCI CQ
parent a1d477f8d5
commit 7be868e17d
12 changed files with 57 additions and 35 deletions

View File

@ -56,7 +56,11 @@ std::ostream& operator<<(std::ostream& os, TrapId trap_id) {
TrapId TrapIdOf(const Operator* const op) {
DCHECK(op->opcode() == IrOpcode::kTrapIf ||
op->opcode() == IrOpcode::kTrapUnless);
op->opcode() == IrOpcode::kTrapUnless
#if V8_ENABLE_WEBASSEMBLY
|| op->opcode() == IrOpcode::kAssertNotNull
#endif
);
return OpParameter<TrapId>(op);
}

View File

@ -1200,14 +1200,16 @@ struct SimplifiedOperatorGlobalCache final {
};
NullOperator kNull;
struct AssertNotNullOperator final : public Operator {
AssertNotNullOperator()
: Operator(
struct AssertNotNullOperator final : public Operator1<TrapId> {
explicit AssertNotNullOperator(TrapId trap_id)
: Operator1(
IrOpcode::kAssertNotNull,
Operator::kNoWrite | Operator::kNoThrow | Operator::kIdempotent,
"AssertNotNull", 1, 1, 1, 1, 1, 1) {}
"AssertNotNull", 1, 1, 1, 1, 1, 1, trap_id) {}
};
AssertNotNullOperator kAssertNotNull;
AssertNotNullOperator kAssertNotNullIllegalCast{TrapId::kTrapIllegalCast};
AssertNotNullOperator kAssertNotNullNullDereference{
TrapId::kTrapNullDereference};
#endif
#define SPECULATIVE_NUMBER_BINOP(Name) \
@ -1404,8 +1406,15 @@ const Operator* SimplifiedOperatorBuilder::RttCanon(int index) {
const Operator* SimplifiedOperatorBuilder::Null() { return &cache_.kNull; }
const Operator* SimplifiedOperatorBuilder::AssertNotNull() {
return &cache_.kAssertNotNull;
const Operator* SimplifiedOperatorBuilder::AssertNotNull(TrapId trap_id) {
switch (trap_id) {
case TrapId::kTrapNullDereference:
return &cache_.kAssertNotNullNullDereference;
case TrapId::kTrapIllegalCast:
return &cache_.kAssertNotNullIllegalCast;
default:
UNREACHABLE();
}
}
const Operator* SimplifiedOperatorBuilder::IsNull() { return &cache_.kIsNull; }

View File

@ -1086,7 +1086,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* VerifyType();
#if V8_ENABLE_WEBASSEMBLY
const Operator* AssertNotNull();
const Operator* AssertNotNull(TrapId trap_id);
const Operator* IsNull();
const Operator* IsNotNull();
const Operator* Null();

View File

@ -1142,8 +1142,10 @@ void WasmGraphBuilder::TrapIfFalse(wasm::TrapReason reason, Node* cond,
}
Node* WasmGraphBuilder::AssertNotNull(Node* object,
wasm::WasmCodePosition position) {
Node* result = gasm_->AssertNotNull(object);
wasm::WasmCodePosition position,
wasm::TrapReason reason) {
TrapId trap_id = GetTrapIdForTrap(reason);
Node* result = gasm_->AssertNotNull(object, trap_id);
SetSourcePosition(result, position);
return result;
}

View File

@ -255,7 +255,9 @@ class WasmGraphBuilder {
Node* EffectPhi(unsigned count, Node** effects_and_control);
Node* RefNull();
Node* RefFunc(uint32_t function_index);
Node* AssertNotNull(Node* object, wasm::WasmCodePosition position);
Node* AssertNotNull(
Node* object, wasm::WasmCodePosition position,
wasm::TrapReason reason = wasm::TrapReason::kTrapNullDereference);
Node* TraceInstruction(uint32_t mark_id);
Node* Int32Constant(int32_t value);
Node* Int64Constant(int64_t value);

View File

@ -248,7 +248,7 @@ Reduction WasmGCLowering::ReduceAssertNotNull(Node* node) {
Node* object = NodeProperties::GetValueInput(node, 0);
gasm_.InitializeEffectControl(effect, control);
if (!v8_flags.experimental_wasm_skip_null_checks) {
gasm_.TrapIf(IsNull(object), TrapId::kTrapNullDereference);
gasm_.TrapIf(IsNull(object), TrapIdOf(node->op()));
}
ReplaceWithValue(node, object, gasm_.effect(), gasm_.control());

View File

@ -266,7 +266,8 @@ Reduction WasmGCOperatorReducer::ReduceWasmTypeCast(Node* node) {
} else {
gasm_.InitializeEffectControl(effect, control);
return Replace(
SetType(gasm_.AssertNotNull(object), object_type.type.AsNonNull()));
SetType(gasm_.AssertNotNull(object, TrapId::kTrapIllegalCast),
object_type.type.AsNonNull()));
}
}

View File

@ -366,9 +366,9 @@ Node* WasmGraphAssembler::IsNotNull(Node* object) {
return AddNode(graph()->NewNode(simplified_.IsNotNull(), object, control()));
}
Node* WasmGraphAssembler::AssertNotNull(Node* object) {
return AddNode(graph()->NewNode(simplified_.AssertNotNull(), object, effect(),
control()));
Node* WasmGraphAssembler::AssertNotNull(Node* object, TrapId trap_id) {
return AddNode(graph()->NewNode(simplified_.AssertNotNull(trap_id), object,
effect(), control()));
}
Node* WasmGraphAssembler::WasmExternInternalize(Node* object) {

View File

@ -249,7 +249,7 @@ class WasmGraphAssembler : public GraphAssembler {
Node* IsNotNull(Node* object);
Node* AssertNotNull(Node* object);
Node* AssertNotNull(Node* object, TrapId trap_id);
Node* WasmExternInternalize(Node* object);

View File

@ -2642,8 +2642,8 @@ class LiftoffCompiler {
__ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap);
}
void AssertNullImpl(FullDecoder* decoder, const Value& arg, Value* result,
LiftoffCondition cond) {
void AssertNullTypecheckImpl(FullDecoder* decoder, const Value& arg,
Value* result, LiftoffCondition cond) {
LiftoffRegList pinned;
LiftoffRegister obj = pinned.set(__ PopToRegister(pinned));
Label* trap_label =
@ -2658,12 +2658,14 @@ class LiftoffCompiler {
__ PushRegister(kRefNull, obj);
}
void AssertNull(FullDecoder* decoder, const Value& arg, Value* result) {
AssertNullImpl(decoder, arg, result, kUnequal);
void AssertNullTypecheck(FullDecoder* decoder, const Value& arg,
Value* result) {
AssertNullTypecheckImpl(decoder, arg, result, kUnequal);
}
void AssertNotNull(FullDecoder* decoder, const Value& arg, Value* result) {
AssertNullImpl(decoder, arg, result, kEqual);
void AssertNotNullTypecheck(FullDecoder* decoder, const Value& arg,
Value* result) {
AssertNullTypecheckImpl(decoder, arg, result, kEqual);
}
void NopForTestingUnsupportedInLiftoff(FullDecoder* decoder) {
@ -6067,7 +6069,7 @@ class LiftoffCompiler {
case HeapType::kNoExtern:
case HeapType::kNoFunc:
DCHECK(null_succeeds);
return AssertNull(decoder, obj, result_val);
return AssertNullTypecheck(decoder, obj, result_val);
case HeapType::kAny:
// Any may never need a cast as it is either implicitly convertible or
// never convertible for any given type.

View File

@ -1093,8 +1093,8 @@ struct ControlBase : public PcForErrors<ValidationTag::full_validation> {
bool null_succeeds) \
F(RefCastAbstract, const Value& obj, HeapType type, Value* result, \
bool null_succeeds) \
F(AssertNull, const Value& obj, Value* result) \
F(AssertNotNull, const Value& obj, Value* result) \
F(AssertNullTypecheck, const Value& obj, Value* result) \
F(AssertNotNullTypecheck, 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, \
@ -4892,7 +4892,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
CALL_INTERFACE(Drop);
}
if (obj.type.is_nullable() && !null_succeeds) {
CALL_INTERFACE(AssertNotNull, obj, &value);
CALL_INTERFACE(AssertNotNullTypecheck, obj, &value);
} else {
CALL_INTERFACE(Forward, obj, &value);
}
@ -4905,7 +4905,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
// is null.
if (obj.type.is_nullable() && null_succeeds) {
// Drop rtt from the stack, then assert that obj is null.
CALL_INTERFACE(AssertNull, obj, &value);
CALL_INTERFACE(AssertNullTypecheck, obj, &value);
} else {
CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast);
// We know that the following code is not reachable, but according
@ -5115,7 +5115,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
if (obj.type.is_nullable()) {
// Drop rtt from the stack, then assert that obj is null.
CALL_INTERFACE(Drop);
CALL_INTERFACE(AssertNull, obj, &value);
CALL_INTERFACE(AssertNullTypecheck, obj, &value);
} else {
CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast);
// We know that the following code is not reachable, but according

View File

@ -469,16 +469,18 @@ class WasmGraphBuildingInterface {
builder_->Trap(reason, decoder->position());
}
void AssertNull(FullDecoder* decoder, const Value& obj, Value* result) {
void AssertNullTypecheck(FullDecoder* decoder, const Value& obj,
Value* result) {
builder_->TrapIfFalse(wasm::TrapReason::kTrapIllegalCast,
builder_->IsNull(obj.node), decoder->position());
Forward(decoder, obj, result);
}
void AssertNotNull(FullDecoder* decoder, const Value& obj, Value* result) {
builder_->TrapIfTrue(wasm::TrapReason::kTrapIllegalCast,
builder_->IsNull(obj.node), decoder->position());
Forward(decoder, obj, result);
void AssertNotNullTypecheck(FullDecoder* decoder, const Value& obj,
Value* result) {
SetAndTypeNode(result,
builder_->AssertNotNull(obj.node, decoder->position(),
TrapReason::kTrapIllegalCast));
}
void NopForTestingUnsupportedInLiftoff(FullDecoder* decoder) {}