LibJS/Bytecode: Generate bytecode for deleting super properties
This commit is contained in:
parent
0d50e5eeee
commit
23daf5097b
Notes:
sideshowbarker
2024-07-17 17:49:11 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/23daf5097b Pull-request: https://github.com/SerenityOS/serenity/pull/19857
5 changed files with 97 additions and 0 deletions
|
@ -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()) {
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
O(CreateVariable) \
|
||||
O(Decrement) \
|
||||
O(DeleteById) \
|
||||
O(DeleteByIdWithThis) \
|
||||
O(DeleteByValue) \
|
||||
O(DeleteByValueWithThis) \
|
||||
O(DeleteVariable) \
|
||||
O(Div) \
|
||||
O(EnterUnwindContext) \
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue