فهرست منبع

LibJS/Bytecode: Support private class fields

This is accomplished with two new instructions:
- GetPrivateById
- PutPrivateById

Looks like 1616 new passes on test262. :^)
Andreas Kling 2 سال پیش
والد
کامیت
e5c7d8407b

+ 5 - 0
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -382,6 +382,8 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By
                         // To be continued later with PutByValue.
                     } else if (expression.property().is_identifier()) {
                         // Do nothing, this will be handled by PutById later.
+                    } else if (expression.property().is_private_identifier()) {
+                        // Do nothing, this will be handled by PutPrivateById later.
                     } else {
                         return Bytecode::CodeGenerationError {
                             &expression,
@@ -415,6 +417,9 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By
                     } else if (expression.property().is_identifier()) {
                         auto identifier_table_ref = generator.intern_identifier(verify_cast<Identifier>(expression.property()).string());
                         generator.emit<Bytecode::Op::PutById>(*base_object_register, identifier_table_ref);
+                    } else if (expression.property().is_private_identifier()) {
+                        auto identifier_table_ref = generator.intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
+                        generator.emit<Bytecode::Op::PutPrivateById>(*base_object_register, identifier_table_ref);
                     } else {
                         return Bytecode::CodeGenerationError {
                             &expression,

+ 7 - 0
Userland/Libraries/LibJS/Bytecode/Generator.cpp

@@ -198,6 +198,9 @@ CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode cons
             } else if (expression.property().is_identifier()) {
                 auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
                 emit<Bytecode::Op::GetById>(identifier_table_ref);
+            } else if (expression.property().is_private_identifier()) {
+                auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
+                emit<Bytecode::Op::GetPrivateById>(identifier_table_ref);
             } else {
                 return CodeGenerationError {
                     &expression,
@@ -238,6 +241,10 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const
             emit<Bytecode::Op::Load>(value_reg);
             auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
             emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref);
+        } else if (expression.property().is_private_identifier()) {
+            emit<Bytecode::Op::Load>(value_reg);
+            auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
+            emit<Bytecode::Op::PutPrivateById>(object_reg, identifier_table_ref);
         } else {
             return CodeGenerationError {
                 &expression,

+ 2 - 0
Userland/Libraries/LibJS/Bytecode/Instruction.h

@@ -38,6 +38,7 @@
     O(GetMethod)                     \
     O(GetNewTarget)                  \
     O(GetObjectPropertyIterator)     \
+    O(GetPrivateById)                \
     O(GetVariable)                   \
     O(GreaterThan)                   \
     O(GreaterThanEquals)             \
@@ -76,6 +77,7 @@
     O(PushDeclarativeEnvironment)    \
     O(PutById)                       \
     O(PutByValue)                    \
+    O(PutPrivateById)                \
     O(ResolveThisBinding)            \
     O(ResolveSuperBase)              \
     O(Return)                        \

+ 37 - 0
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -512,6 +512,16 @@ ThrowCompletionOr<void> GetById::execute_impl(Bytecode::Interpreter& interpreter
     return {};
 }
 
+ThrowCompletionOr<void> GetPrivateById::execute_impl(Bytecode::Interpreter& interpreter) const
+{
+    auto& vm = interpreter.vm();
+    auto const& name = interpreter.current_executable().get_identifier(m_property);
+    auto base_value = interpreter.accumulator();
+    auto private_reference = make_private_reference(vm, base_value, name);
+    interpreter.accumulator() = TRY(private_reference.get_value(vm));
+    return {};
+}
+
 ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter) const
 {
     auto& vm = interpreter.vm();
@@ -522,6 +532,17 @@ ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter
     return put_by_property_key(vm, object, value, name, m_kind);
 }
 
+ThrowCompletionOr<void> PutPrivateById::execute_impl(Bytecode::Interpreter& interpreter) const
+{
+    auto& vm = interpreter.vm();
+    // NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
+    auto value = interpreter.accumulator();
+    auto object = TRY(interpreter.reg(m_base).to_object(vm));
+    auto name = interpreter.current_executable().get_identifier(m_property);
+    auto private_reference = make_private_reference(vm, object, name);
+    return private_reference.put_value(vm, value);
+}
+
 ThrowCompletionOr<void> DeleteById::execute_impl(Bytecode::Interpreter& interpreter) const
 {
     auto& vm = interpreter.vm();
@@ -1252,11 +1273,27 @@ DeprecatedString PutById::to_deprecated_string_impl(Bytecode::Executable const&
     return DeprecatedString::formatted("PutById kind:{} base:{}, property:{} ({})", kind, m_base, m_property, executable.identifier_table->get(m_property));
 }
 
+DeprecatedString PutPrivateById::to_deprecated_string_impl(Bytecode::Executable const& executable) const
+{
+    auto kind = m_kind == PropertyKind::Getter
+        ? "getter"
+        : m_kind == PropertyKind::Setter
+        ? "setter"
+        : "property";
+
+    return DeprecatedString::formatted("PutPrivateById kind:{} base:{}, property:{} ({})", kind, m_base, m_property, executable.identifier_table->get(m_property));
+}
+
 DeprecatedString GetById::to_deprecated_string_impl(Bytecode::Executable const& executable) const
 {
     return DeprecatedString::formatted("GetById {} ({})", m_property, executable.identifier_table->get(m_property));
 }
 
+DeprecatedString GetPrivateById::to_deprecated_string_impl(Bytecode::Executable const& executable) const
+{
+    return DeprecatedString::formatted("GetPrivateById {} ({})", m_property, executable.identifier_table->get(m_property));
+}
+
 DeprecatedString DeleteById::to_deprecated_string_impl(Bytecode::Executable const& executable) const
 {
     return DeprecatedString::formatted("DeleteById {} ({})", m_property, executable.identifier_table->get(m_property));

+ 42 - 0
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -517,6 +517,23 @@ private:
     IdentifierTableIndex m_property;
 };
 
+class GetPrivateById final : public Instruction {
+public:
+    explicit GetPrivateById(IdentifierTableIndex property)
+        : Instruction(Type::GetPrivateById)
+        , 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:
+    IdentifierTableIndex m_property;
+};
+
 enum class PropertyKind {
     Getter,
     Setter,
@@ -550,6 +567,31 @@ private:
     PropertyKind m_kind;
 };
 
+class PutPrivateById final : public Instruction {
+public:
+    explicit PutPrivateById(Register base, IdentifierTableIndex property, PropertyKind kind = PropertyKind::KeyValue)
+        : Instruction(Type::PutPrivateById)
+        , m_base(base)
+        , m_property(property)
+        , m_kind(kind)
+    {
+    }
+
+    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;
+    IdentifierTableIndex m_property;
+    PropertyKind m_kind;
+};
+
 class DeleteById final : public Instruction {
 public:
     explicit DeleteById(IdentifierTableIndex property)