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() {
ValueNode* value = GetAccumulatorTagged();
// Avoid the check if we know it is not the hole.
if (IsConstantNode(value->opcode())) {
// Only RootConstant and Constant nodes can be equal to the hole.
if (RootConstant* constant = value->TryCast<RootConstant>()) {
if (constant->index() == RootIndex::kTheHoleValue) {
// TODO(victorgomes): Throw immediately instead.
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
}
} else if (Constant* constant = value->TryCast<Constant>()) {
if (constant->IsTheHole()) {
// TODO(victorgomes): Throw immediately instead.
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
}
if (IsConstantNodeTheHole(value)) {
ValueNode* constant = GetConstant(name);
BuildCallRuntime(Runtime::kThrowAccessedUninitializedVariable,
{constant});
BuildAbort(AbortReason::kUnexpectedReturnFromThrow);
}
} else {
AddNewNode<ThrowReferenceErrorIfHole>({value}, name);
return;
}
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(SuspendGenerator)
MAGLEV_UNIMPLEMENTED_BYTECODE(ResumeGenerator)
......
......@@ -398,6 +398,18 @@ class MaglevGraphBuilder {
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
// virtual_accumulator as the src or dst to move in or out of the accumulator.
void MoveNodeBetweenRegisters(interpreter::Register src,
......
......@@ -114,6 +114,8 @@ class MaglevGraphVerifier {
case Opcode::kTestUndetectable:
case Opcode::kTestTypeOf:
case Opcode::kThrowReferenceErrorIfHole:
case Opcode::kThrowSuperNotCalledIfHole:
case Opcode::kThrowSuperAlreadyCalledIfNotHole:
case Opcode::kReturn:
DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
......@@ -154,6 +156,7 @@ class MaglevGraphVerifier {
case Opcode::kStoreTaggedFieldWithWriteBarrier:
case Opcode::kLoadNamedGeneric:
case Opcode::kToNumberOrNumeric:
case Opcode::kThrowIfNotSuperConstructor:
DCHECK_EQ(node->input_count(), 2);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
......
......@@ -2508,6 +2508,81 @@ void ThrowReferenceErrorIfHole::GenerateCode(MaglevCodeGenState* code_gen_state,
__ Move(kContextRegister, code_gen_state->native_context().object());
__ Push(node->name().object());
__ 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);
},
this);
......
......@@ -178,6 +178,9 @@ class CompactInterpreterFrameState;
V(IncreaseInterruptBudget) \
V(ReduceInterruptBudget) \
V(ThrowReferenceErrorIfHole) \
V(ThrowSuperNotCalledIfHole) \
V(ThrowSuperAlreadyCalledIfNotHole) \
V(ThrowIfNotSuperConstructor) \
GAP_MOVE_NODE_LIST(V) \
VALUE_NODE_LIST(V)
......@@ -705,11 +708,12 @@ class NodeBase : public ZoneObject {
const RegisterSnapshot& register_snapshot() const {
DCHECK(properties().needs_register_snapshot());
DCHECK(!properties().can_lazy_deopt());
if (properties().can_eager_deopt()) {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
eager_deopt_info());
} else if (properties().can_lazy_deopt()) {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
lazy_deopt_info());
} else {
return *detail::ObjectPtrBeforeAddress<RegisterSnapshot>(
last_input_address());
......@@ -718,11 +722,12 @@ class NodeBase : public ZoneObject {
void set_register_snapshot(RegisterSnapshot snapshot) {
DCHECK(properties().needs_register_snapshot());
DCHECK(!properties().can_lazy_deopt());
if (properties().can_eager_deopt()) {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(eager_deopt_info()) =
snapshot;
} else if (properties().can_lazy_deopt()) {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(lazy_deopt_info()) =
snapshot;
} else {
*detail::ObjectPtrBeforeAddress<RegisterSnapshot>(last_input_address()) =
snapshot;
......@@ -2828,7 +2833,8 @@ class ThrowReferenceErrorIfHole
const compiler::NameRef& 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_; }
......@@ -2842,6 +2848,59 @@ class ThrowReferenceErrorIfHole
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
// unresolved BasicBlockRefs which will be mutated (in place) at some point into
// 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