mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibJS: Add PutBySpread
instruction
This object property kind had completely different behaviour. By adding an instruction for it, we can remove a bunch of special casing, and avoid creating dummy `PropertyKey` values.
This commit is contained in:
parent
27859c17b4
commit
bc05f6303f
Notes:
github-actions[bot]
2024-11-09 16:56:05 +00:00
Author: https://github.com/yyny Commit: https://github.com/LadybirdBrowser/ladybird/commit/bc05f6303f5 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2120 Reviewed-by: https://github.com/trflynn89
4 changed files with 56 additions and 21 deletions
|
@ -1132,12 +1132,12 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ObjectExpression::gener
|
|||
case ObjectProperty::Type::Setter:
|
||||
property_kind = Bytecode::Op::PropertyKind::Setter;
|
||||
break;
|
||||
case ObjectProperty::Type::Spread:
|
||||
property_kind = Bytecode::Op::PropertyKind::Spread;
|
||||
break;
|
||||
case ObjectProperty::Type::ProtoSetter:
|
||||
property_kind = Bytecode::Op::PropertyKind::ProtoSetter;
|
||||
break;
|
||||
case ObjectProperty::Type::Spread:
|
||||
generator.emit<Bytecode::Op::PutBySpread>(object, TRY(property->key().generate_bytecode(generator)).value());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is<StringLiteral>(property->key())) {
|
||||
|
@ -1147,7 +1147,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ObjectExpression::gener
|
|||
Optional<ScopedOperand> value;
|
||||
if (property_kind == Bytecode::Op::PropertyKind::ProtoSetter) {
|
||||
value = TRY(property->value().generate_bytecode(generator)).value();
|
||||
} else if (property_kind != Bytecode::Op::PropertyKind::Spread) {
|
||||
} else {
|
||||
ByteString identifier = string_literal.value();
|
||||
if (property_kind == Bytecode::Op::PropertyKind::Getter)
|
||||
identifier = ByteString::formatted("get {}", identifier);
|
||||
|
@ -1155,21 +1155,14 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ObjectExpression::gener
|
|||
identifier = ByteString::formatted("set {}", identifier);
|
||||
auto name = generator.intern_identifier(identifier);
|
||||
value = TRY(generator.emit_named_evaluation_if_anonymous_function(property->value(), name)).value();
|
||||
} else {
|
||||
// Spread the key.
|
||||
value = TRY(property->key().generate_bytecode(generator)).value();
|
||||
}
|
||||
|
||||
generator.emit<Bytecode::Op::PutById>(object, key_name, *value, property_kind, generator.next_property_lookup_cache());
|
||||
} else {
|
||||
auto property_name = TRY(property->key().generate_bytecode(generator)).value();
|
||||
Optional<ScopedOperand> value;
|
||||
if (property_kind != Bytecode::Op::PropertyKind::Spread)
|
||||
value = TRY(property->value().generate_bytecode(generator)).value();
|
||||
else
|
||||
value = property_name;
|
||||
auto value = TRY(property->value().generate_bytecode(generator)).value();
|
||||
|
||||
generator.emit<Bytecode::Op::PutByValue>(object, property_name, *value, property_kind);
|
||||
generator.emit<Bytecode::Op::PutByValue>(object, property_name, value, property_kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
O(PostfixIncrement) \
|
||||
O(PutById) \
|
||||
O(PutByIdWithThis) \
|
||||
O(PutBySpread) \
|
||||
O(PutByValue) \
|
||||
O(PutByValueWithThis) \
|
||||
O(PutPrivateById) \
|
||||
|
|
|
@ -649,6 +649,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
HANDLE_INSTRUCTION(PostfixIncrement);
|
||||
HANDLE_INSTRUCTION(PutById);
|
||||
HANDLE_INSTRUCTION(PutByIdWithThis);
|
||||
HANDLE_INSTRUCTION(PutBySpread);
|
||||
HANDLE_INSTRUCTION(PutByValue);
|
||||
HANDLE_INSTRUCTION(PutByValueWithThis);
|
||||
HANDLE_INSTRUCTION(PutPrivateById);
|
||||
|
@ -1213,9 +1214,6 @@ inline ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value thi
|
|||
case Op::PropertyKind::DirectKeyValue:
|
||||
object->define_direct_property(name, value, Attribute::Enumerable | Attribute::Writable | Attribute::Configurable);
|
||||
break;
|
||||
case Op::PropertyKind::Spread:
|
||||
TRY(object->copy_data_properties(vm, value, {}));
|
||||
break;
|
||||
case Op::PropertyKind::ProtoSetter:
|
||||
if (value.is_object() || value.is_null())
|
||||
MUST(object->internal_set_prototype_of(value.is_object() ? &value.as_object() : nullptr));
|
||||
|
@ -1362,7 +1360,7 @@ inline ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Optional<Depreca
|
|||
}
|
||||
}
|
||||
|
||||
auto property_key = kind != Op::PropertyKind::Spread ? TRY(property_key_value.to_property_key(vm)) : PropertyKey { 0 };
|
||||
auto property_key = TRY(property_key_value.to_property_key(vm));
|
||||
TRY(put_by_property_key(vm, base, base, value, base_identifier, property_key, kind));
|
||||
return {};
|
||||
}
|
||||
|
@ -2417,6 +2415,20 @@ ThrowCompletionOr<void> HasPrivateId::execute_impl(Bytecode::Interpreter& interp
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> PutBySpread::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
auto value = interpreter.get(m_src);
|
||||
auto base = interpreter.get(m_base);
|
||||
|
||||
// a. Let baseObj be ? ToObject(V.[[Base]]).
|
||||
auto object = TRY(base.to_object(vm));
|
||||
|
||||
TRY(object->copy_data_properties(vm, value, {}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
@ -2807,7 +2819,7 @@ ThrowCompletionOr<void> PutByValueWithThis::execute_impl(Bytecode::Interpreter&
|
|||
auto& vm = interpreter.vm();
|
||||
auto value = interpreter.get(m_src);
|
||||
auto base = interpreter.get(m_base);
|
||||
auto property_key = m_kind != PropertyKind::Spread ? TRY(interpreter.get(m_property).to_property_key(vm)) : PropertyKey { 0 };
|
||||
auto property_key = TRY(interpreter.get(m_property).to_property_key(vm));
|
||||
TRY(put_by_property_key(vm, base, interpreter.get(m_this_value), value, {}, property_key, m_kind));
|
||||
return {};
|
||||
}
|
||||
|
@ -3158,14 +3170,19 @@ static StringView property_kind_to_string(PropertyKind kind)
|
|||
return "key-value"sv;
|
||||
case PropertyKind::DirectKeyValue:
|
||||
return "direct-key-value"sv;
|
||||
case PropertyKind::Spread:
|
||||
return "spread"sv;
|
||||
case PropertyKind::ProtoSetter:
|
||||
return "proto-setter"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ByteString PutBySpread::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("PutBySpread {}, {}",
|
||||
format_operand("base"sv, m_base, executable),
|
||||
format_operand("src"sv, m_src, executable));
|
||||
}
|
||||
|
||||
ByteString PutById::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
auto kind = property_kind_to_string(m_kind);
|
||||
|
|
|
@ -1120,10 +1120,34 @@ enum class PropertyKind {
|
|||
Setter,
|
||||
KeyValue,
|
||||
DirectKeyValue, // Used for Object expressions. Always sets an own property, never calls a setter.
|
||||
Spread,
|
||||
ProtoSetter,
|
||||
};
|
||||
|
||||
class PutBySpread final : public Instruction {
|
||||
public:
|
||||
PutBySpread(Operand base, Operand src)
|
||||
: Instruction(Type::PutBySpread)
|
||||
, m_base(base)
|
||||
, m_src(src)
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void visit_operands_impl(Function<void(Operand&)> visitor)
|
||||
{
|
||||
visitor(m_base);
|
||||
visitor(m_src);
|
||||
}
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
Operand src() const { return m_src; }
|
||||
|
||||
private:
|
||||
Operand m_base;
|
||||
Operand m_src;
|
||||
};
|
||||
|
||||
class PutById final : public Instruction {
|
||||
public:
|
||||
explicit PutById(Operand base, IdentifierTableIndex property, Operand src, PropertyKind kind, u32 cache_index, Optional<IdentifierTableIndex> base_identifier = {})
|
||||
|
|
Loading…
Reference in a new issue