LibJS/Bytecode: Generate bytecode for deleting super properties

This commit is contained in:
Timothy Flynn 2023-07-06 17:10:40 -04:00 committed by Andreas Kling
parent 0d50e5eeee
commit 23daf5097b
5 changed files with 97 additions and 0 deletions

View file

@ -304,6 +304,21 @@ CodeGenerationErrorOr<void> Generator::emit_delete_reference(JS::ASTNode const&
if (is<MemberExpression>(node)) {
auto& expression = static_cast<MemberExpression const&>(node);
// https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
if (is<SuperExpression>(expression.object())) {
auto super_reference = TRY(emit_super_reference(expression));
if (super_reference.referenced_name.has_value()) {
emit<Bytecode::Op::DeleteByValueWithThis>(super_reference.this_value, *super_reference.referenced_name);
} else {
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
emit<Bytecode::Op::DeleteByIdWithThis>(super_reference.this_value, identifier_table_ref);
}
return {};
}
TRY(expression.object().generate_bytecode(*this));
if (expression.is_computed()) {

View file

@ -27,7 +27,9 @@
O(CreateVariable) \
O(Decrement) \
O(DeleteById) \
O(DeleteByIdWithThis) \
O(DeleteByValue) \
O(DeleteByValueWithThis) \
O(DeleteVariable) \
O(Div) \
O(EnterUnwindContext) \

View file

@ -627,6 +627,17 @@ ThrowCompletionOr<void> DeleteById::execute_impl(Bytecode::Interpreter& interpre
return {};
};
ThrowCompletionOr<void> DeleteByIdWithThis::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
auto base_value = interpreter.accumulator();
auto const& identifier = interpreter.current_executable().get_identifier(m_property);
bool strict = vm.in_strict_mode();
auto reference = Reference { base_value, identifier, interpreter.reg(m_this_value), strict };
interpreter.accumulator() = Value(TRY(reference.delete_(vm)));
return {};
};
ThrowCompletionOr<void> Jump::execute_impl(Bytecode::Interpreter& interpreter) const
{
interpreter.jump(*m_true_target);
@ -1115,6 +1126,21 @@ ThrowCompletionOr<void> DeleteByValue::execute_impl(Bytecode::Interpreter& inter
return {};
}
ThrowCompletionOr<void> DeleteByValueWithThis::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
// NOTE: Get the property key from the accumulator before side effects have a chance to overwrite it.
auto property_key_value = interpreter.accumulator();
auto base_value = interpreter.reg(m_base);
auto property_key = TRY(property_key_value.to_property_key(vm));
bool strict = vm.in_strict_mode();
auto reference = Reference { base_value, property_key, interpreter.reg(m_this_value), strict };
interpreter.accumulator() = Value(TRY(reference.delete_(vm)));
return {};
};
ThrowCompletionOr<void> GetIterator::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
@ -1511,6 +1537,11 @@ DeprecatedString DeleteById::to_deprecated_string_impl(Bytecode::Executable cons
return DeprecatedString::formatted("DeleteById {} ({})", m_property, executable.identifier_table->get(m_property));
}
DeprecatedString DeleteByIdWithThis::to_deprecated_string_impl(Bytecode::Executable const& executable) const
{
return DeprecatedString::formatted("DeleteByIdWithThis {} ({}) this_value:{}", m_property, executable.identifier_table->get(m_property), m_this_value);
}
DeprecatedString Jump::to_deprecated_string_impl(Bytecode::Executable const&) const
{
if (m_true_target.has_value())
@ -1712,6 +1743,11 @@ DeprecatedString DeleteByValue::to_deprecated_string_impl(Bytecode::Executable c
return DeprecatedString::formatted("DeleteByValue base:{}", m_base);
}
DeprecatedString DeleteByValueWithThis::to_deprecated_string_impl(Bytecode::Executable const&) const
{
return DeprecatedString::formatted("DeleteByValueWithThis base:{} this_value:{}", m_base, m_this_value);
}
DeprecatedString GetIterator::to_deprecated_string_impl(Executable const&) const
{
auto hint = m_hint == IteratorHint::Sync ? "sync" : "async";

View file

@ -740,6 +740,25 @@ private:
IdentifierTableIndex m_property;
};
class DeleteByIdWithThis final : public Instruction {
public:
DeleteByIdWithThis(Register this_value, IdentifierTableIndex property)
: Instruction(Type::DeleteByIdWithThis)
, m_this_value(this_value)
, m_property(property)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
void replace_references_impl(Register, Register) { }
private:
Register m_this_value;
IdentifierTableIndex m_property;
};
class GetByValue final : public Instruction {
public:
explicit GetByValue(Register base)
@ -865,6 +884,29 @@ private:
Register m_base;
};
class DeleteByValueWithThis final : public Instruction {
public:
DeleteByValueWithThis(Register base, Register this_value)
: Instruction(Type::DeleteByValueWithThis)
, m_base(base)
, m_this_value(this_value)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
void replace_references_impl(Register from, Register to)
{
if (m_base == from)
m_base = to;
}
private:
Register m_base;
Register m_this_value;
};
class Jump : public Instruction {
public:
constexpr static bool IsTerminator = true;

View file

@ -118,7 +118,9 @@ static NonnullOwnPtr<BasicBlock> eliminate_loads(BasicBlock const& block, size_t
break;
}
case DeleteById:
case DeleteByIdWithThis:
case DeleteByValue:
case DeleteByValueWithThis:
// These can trigger proxies, which call into user code
// So these are treated like calls
case GetByValue: