Commit 88b2939d authored by Victor Gomes's avatar Victor Gomes Committed by V8 LUCI CQ

[maglev] Support ThrowIf<condition> bytecodes

- ThrowReferenceErrorIfHole
- ThrowSuperNotCalledIfHole
- ThrowSuperAlreadyCalledIfNotHole
- ThrowIfNotSuperConstructor

Bug: v8:7700
Change-Id: I565a196869905cddaf1203deae7469dcadbfcdf6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3802685Reviewed-by: 's avatarJakob Linke <jgruber@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82106}
parent 405fa4d6
...@@ -2162,26 +2162,50 @@ void MaglevGraphBuilder::VisitThrowReferenceErrorIfHole() { ...@@ -2162,26 +2162,50 @@ void MaglevGraphBuilder::VisitThrowReferenceErrorIfHole() {
ValueNode* value = GetAccumulatorTagged(); ValueNode* value = GetAccumulatorTagged();
// Avoid the check if we know it is not the hole. // Avoid the check if we know it is not the hole.
if (IsConstantNode(value->opcode())) { if (IsConstantNode(value->opcode())) {
// Only RootConstant and Constant nodes can be equal to the hole. if (IsConstantNodeTheHole(value)) {
if (RootConstant* constant = value->TryCast<RootConstant>()) { ValueNode* constant = GetConstant(name);
if (constant->index() == RootIndex::kTheHoleValue) { BuildCallRuntime(Runtime::kThrowAccessedUninitializedVariable,
// TODO(victorgomes): Throw immediately instead. {constant});
AddNewNode<ThrowReferenceErrorIfHole>({value}, name); BuildAbort(AbortReason::kUnexpectedReturnFromThrow);
}
} else if (Constant* constant = value->TryCast<Constant>()) {
if (constant->IsTheHole()) {
// TODO(victorgomes): Throw immediately instead.
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
}
} }
} else { return;
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
} }
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
}
void MaglevGraphBuilder::VisitThrowSuperNotCalledIfHole() {
// ThrowSuperNotCalledIfHole
ValueNode* value = GetAccumulatorTagged();
// Avoid the check if we know it is not the hole.
if (IsConstantNode(value->opcode())) {
if (IsConstantNodeTheHole(value)) {
BuildCallRuntime(Runtime::kThrowSuperNotCalled, {});
BuildAbort(AbortReason::kUnexpectedReturnFromThrow);
}
return;
}
AddNewNode<ThrowSuperNotCalledIfHole>({value});
}
void MaglevGraphBuilder::VisitThrowSuperAlreadyCalledIfNotHole() {
// ThrowSuperAlreadyCalledIfNotHole
ValueNode* value = GetAccumulatorTagged();
// Avoid the check if we know it is the hole.
if (IsConstantNode(value->opcode())) {
if (!IsConstantNodeTheHole(value)) {
BuildCallRuntime(Runtime::kThrowSuperAlreadyCalledError, {});
BuildAbort(AbortReason::kUnexpectedReturnFromThrow);
}
return;
}
AddNewNode<ThrowSuperAlreadyCalledIfNotHole>({value});
}
void MaglevGraphBuilder::VisitThrowIfNotSuperConstructor() {
// ThrowIfNotSuperConstructor <constructor>
ValueNode* constructor = LoadRegisterTagged(0);
ValueNode* function =
GetTaggedValue(interpreter::Register::function_closure());
AddNewNode<ThrowIfNotSuperConstructor>({constructor, function});
} }
MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowSuperNotCalledIfHole)
MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowSuperAlreadyCalledIfNotHole)
MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowIfNotSuperConstructor)
MAGLEV_UNIMPLEMENTED_BYTECODE(SwitchOnGeneratorState) MAGLEV_UNIMPLEMENTED_BYTECODE(SwitchOnGeneratorState)
MAGLEV_UNIMPLEMENTED_BYTECODE(SuspendGenerator) MAGLEV_UNIMPLEMENTED_BYTECODE(SuspendGenerator)
MAGLEV_UNIMPLEMENTED_BYTECODE(ResumeGenerator) MAGLEV_UNIMPLEMENTED_BYTECODE(ResumeGenerator)
......
...@@ -398,6 +398,18 @@ class MaglevGraphBuilder { ...@@ -398,6 +398,18 @@ class MaglevGraphBuilder {
return node; return node;
} }
bool IsConstantNodeTheHole(ValueNode* value) {
DCHECK(IsConstantNode(value->opcode()));
if (RootConstant* constant = value->TryCast<RootConstant>()) {
return constant->index() == RootIndex::kTheHoleValue;
}
if (Constant* constant = value->TryCast<Constant>()) {
return constant->IsTheHole();
}
// The other constants nodes cannot be TheHole.
return false;
}
// Move an existing ValueNode between two registers. You can pass // Move an existing ValueNode between two registers. You can pass
// virtual_accumulator as the src or dst to move in or out of the accumulator. // virtual_accumulator as the src or dst to move in or out of the accumulator.
void MoveNodeBetweenRegisters(interpreter::Register src, void MoveNodeBetweenRegisters(interpreter::Register src,
......
...@@ -114,6 +114,8 @@ class MaglevGraphVerifier { ...@@ -114,6 +114,8 @@ class MaglevGraphVerifier {
case Opcode::kTestUndetectable: case Opcode::kTestUndetectable:
case Opcode::kTestTypeOf: case Opcode::kTestTypeOf:
case Opcode::kThrowReferenceErrorIfHole: case Opcode::kThrowReferenceErrorIfHole:
case Opcode::kThrowSuperNotCalledIfHole:
case Opcode::kThrowSuperAlreadyCalledIfNotHole:
case Opcode::kReturn: case Opcode::kReturn:
DCHECK_EQ(node->input_count(), 1); DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged); CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
...@@ -154,6 +156,7 @@ class MaglevGraphVerifier { ...@@ -154,6 +156,7 @@ class MaglevGraphVerifier {
case Opcode::kStoreTaggedFieldWithWriteBarrier: case Opcode::kStoreTaggedFieldWithWriteBarrier:
case Opcode::kLoadNamedGeneric: case Opcode::kLoadNamedGeneric:
case Opcode::kToNumberOrNumeric: case Opcode::kToNumberOrNumeric:
case Opcode::kThrowIfNotSuperConstructor:
DCHECK_EQ(node->input_count(), 2); DCHECK_EQ(node->input_count(), 2);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged); CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
CheckValueInputIs(node, 1, ValueRepresentation::kTagged); CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
......
...@@ -2508,6 +2508,81 @@ void ThrowReferenceErrorIfHole::GenerateCode(MaglevCodeGenState* code_gen_state, ...@@ -2508,6 +2508,81 @@ void ThrowReferenceErrorIfHole::GenerateCode(MaglevCodeGenState* code_gen_state,
__ Move(kContextRegister, code_gen_state->native_context().object()); __ Move(kContextRegister, code_gen_state->native_context().object());
__ Push(node->name().object()); __ Push(node->name().object());
__ CallRuntime(Runtime::kThrowAccessedUninitializedVariable, 1); __ CallRuntime(Runtime::kThrowAccessedUninitializedVariable, 1);
code_gen_state->DefineLazyDeoptPoint(node->lazy_deopt_info());
__ Abort(AbortReason::kUnexpectedReturnFromThrow);
},
this);
}
void ThrowSuperNotCalledIfHole::AllocateVreg(
MaglevVregAllocationState* vreg_state) {
UseAny(value());
}
void ThrowSuperNotCalledIfHole::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
if (value().operand().IsRegister()) {
__ CompareRoot(ToRegister(value()), RootIndex::kTheHoleValue);
} else {
DCHECK(value().operand().IsStackSlot());
__ CompareRoot(code_gen_state->ToMemOperand(value()),
RootIndex::kTheHoleValue);
}
JumpToDeferredIf(
equal, code_gen_state,
[](MaglevCodeGenState* code_gen_state, Label* return_label,
ThrowSuperNotCalledIfHole* node) {
__ Move(kContextRegister, code_gen_state->native_context().object());
__ CallRuntime(Runtime::kThrowSuperNotCalled, 0);
code_gen_state->DefineLazyDeoptPoint(node->lazy_deopt_info());
__ Abort(AbortReason::kUnexpectedReturnFromThrow);
},
this);
}
void ThrowSuperAlreadyCalledIfNotHole::AllocateVreg(
MaglevVregAllocationState* vreg_state) {
UseAny(value());
}
void ThrowSuperAlreadyCalledIfNotHole::GenerateCode(
MaglevCodeGenState* code_gen_state, const ProcessingState& state) {
if (value().operand().IsRegister()) {
__ CompareRoot(ToRegister(value()), RootIndex::kTheHoleValue);
} else {
DCHECK(value().operand().IsStackSlot());
__ CompareRoot(code_gen_state->ToMemOperand(value()),
RootIndex::kTheHoleValue);
}
JumpToDeferredIf(
not_equal, code_gen_state,
[](MaglevCodeGenState* code_gen_state, Label* return_label,
ThrowSuperAlreadyCalledIfNotHole* node) {
__ Move(kContextRegister, code_gen_state->native_context().object());
__ CallRuntime(Runtime::kThrowSuperAlreadyCalledError, 0);
code_gen_state->DefineLazyDeoptPoint(node->lazy_deopt_info());
__ Abort(AbortReason::kUnexpectedReturnFromThrow);
},
this);
}
void ThrowIfNotSuperConstructor::AllocateVreg(
MaglevVregAllocationState* vreg_state) {
UseRegister(constructor());
UseRegister(function());
}
void ThrowIfNotSuperConstructor::GenerateCode(
MaglevCodeGenState* code_gen_state, const ProcessingState& state) {
__ LoadMap(kScratchRegister, ToRegister(constructor()));
__ testl(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsConstructorBit::kMask));
JumpToDeferredIf(
equal, code_gen_state,
[](MaglevCodeGenState* code_gen_state, Label* return_label,
ThrowIfNotSuperConstructor* node) {
__ Move(kContextRegister, code_gen_state->native_context().object());
__ Push(ToRegister(node->constructor()));
__ Push(ToRegister(node->function()));
__ CallRuntime(Runtime::kThrowNotSuperConstructor, 2);
code_gen_state->DefineLazyDeoptPoint(node->lazy_deopt_info());
__ Abort(AbortReason::kUnexpectedReturnFromThrow); __ Abort(AbortReason::kUnexpectedReturnFromThrow);
}, },
this); this);
......
...@@ -178,6 +178,9 @@ class CompactInterpreterFrameState; ...@@ -178,6 +178,9 @@ class CompactInterpreterFrameState;
V(IncreaseInterruptBudget) \ V(IncreaseInterruptBudget) \
V(ReduceInterruptBudget) \ V(ReduceInterruptBudget) \
V(ThrowReferenceErrorIfHole) \ V(ThrowReferenceErrorIfHole) \
V(ThrowSuperNotCalledIfHole) \
V(ThrowSuperAlreadyCalledIfNotHole) \
V(ThrowIfNotSuperConstructor) \
GAP_MOVE_NODE_LIST(V) \ GAP_MOVE_NODE_LIST(V) \
VALUE_NODE_LIST(V) VALUE_NODE_LIST(V)
...@@ -705,11 +708,12 @@ class NodeBase : public ZoneObject { ...@@ -705,11 +708,12 @@ class NodeBase : public ZoneObject {
const RegisterSnapshot& register_snapshot() const { const RegisterSnapshot& register_snapshot() const {
DCHECK(properties().needs_register_snapshot()); DCHECK(properties().needs_register_snapshot());
DCHECK(!properties().can_lazy_deopt());
if (properties().can_eager_deopt()) { if (properties().can_eager_deopt()) {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>( return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
eager_deopt_info()); eager_deopt_info());
} else if (properties().can_lazy_deopt()) {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
lazy_deopt_info());
} else { } else {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>( return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
last_input_address()); last_input_address());
...@@ -718,11 +722,12 @@ class NodeBase : public ZoneObject { ...@@ -718,11 +722,12 @@ class NodeBase : public ZoneObject {
void set_register_snapshot(RegisterSnapshot snapshot) { void set_register_snapshot(RegisterSnapshot snapshot) {
DCHECK(properties().needs_register_snapshot()); DCHECK(properties().needs_register_snapshot());
DCHECK(!properties().can_lazy_deopt());
if (properties().can_eager_deopt()) { if (properties().can_eager_deopt()) {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(eager_deopt_info()) = *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(eager_deopt_info()) =
snapshot; snapshot;
} else if (properties().can_lazy_deopt()) {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(lazy_deopt_info()) =
snapshot;
} else { } else {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(last_input_address()) = *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(last_input_address()) =
snapshot; snapshot;
...@@ -2828,7 +2833,8 @@ class ThrowReferenceErrorIfHole ...@@ -2828,7 +2833,8 @@ class ThrowReferenceErrorIfHole
const compiler::NameRef& name) const compiler::NameRef& name)
: Base(bitfield), name_(name) {} : Base(bitfield), name_(name) {}
static constexpr OpProperties kProperties = OpProperties::DeferredCall(); static constexpr OpProperties kProperties =
OpProperties::LazyDeopt() | OpProperties::DeferredCall();
const compiler::NameRef& name() const { return name_; } const compiler::NameRef& name() const { return name_; }
...@@ -2842,6 +2848,59 @@ class ThrowReferenceErrorIfHole ...@@ -2842,6 +2848,59 @@ class ThrowReferenceErrorIfHole
const compiler::NameRef name_; const compiler::NameRef name_;
}; };
class ThrowSuperNotCalledIfHole
: public FixedInputNodeT<1, ThrowSuperNotCalledIfHole> {
using Base = FixedInputNodeT<1, ThrowSuperNotCalledIfHole>;
public:
explicit ThrowSuperNotCalledIfHole(uint64_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties =
OpProperties::LazyDeopt() | OpProperties::DeferredCall();
Input& value() { return Node::input(0); }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class ThrowSuperAlreadyCalledIfNotHole
: public FixedInputNodeT<1, ThrowSuperAlreadyCalledIfNotHole> {
using Base = FixedInputNodeT<1, ThrowSuperAlreadyCalledIfNotHole>;
public:
explicit ThrowSuperAlreadyCalledIfNotHole(uint64_t bitfield)
: Base(bitfield) {}
static constexpr OpProperties kProperties =
OpProperties::LazyDeopt() | OpProperties::DeferredCall();
Input& value() { return Node::input(0); }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class ThrowIfNotSuperConstructor
: public FixedInputNodeT<2, ThrowIfNotSuperConstructor> {
using Base = FixedInputNodeT<2, ThrowIfNotSuperConstructor>;
public:
explicit ThrowIfNotSuperConstructor(uint64_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties =
OpProperties::LazyDeopt() | OpProperties::DeferredCall();
Input& constructor() { return Node::input(0); }
Input& function() { return Node::input(1); }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
// Represents either a direct BasicBlock pointer, or an entry in a list of // Represents either a direct BasicBlock pointer, or an entry in a list of
// unresolved BasicBlockRefs which will be mutated (in place) at some point into // unresolved BasicBlockRefs which will be mutated (in place) at some point into
// direct BasicBlock pointers. // direct BasicBlock pointers.
......
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