Просмотр исходного кода

LibJS/Bytecode: Don't clobber dst when assigning from object expression

When compiling code like this:

    x = { foo: x }

We don't want to put a new JS::Object in `x` until *after* we've
evaluated `x` for the `foo` field.

This fixes an issue when loading https://puter.com/ :^)
Andreas Kling 1 год назад
Родитель
Сommit
6402ad29a6

+ 2 - 2
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -948,11 +948,11 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ForStatement::gener
     return body_result;
 }
 
-Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ObjectExpression::generate_bytecode(Bytecode::Generator& generator, Optional<Bytecode::Operand> preferred_dst) const
+Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ObjectExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional<Bytecode::Operand> preferred_dst) const
 {
     Bytecode::Generator::SourceLocationScope scope(generator, *this);
 
-    auto object = choose_dst(generator, preferred_dst);
+    auto object = Bytecode::Operand(generator.allocate_register());
 
     generator.emit<Bytecode::Op::NewObject>(object);
     if (m_properties.is_empty())

+ 8 - 0
Userland/Libraries/LibJS/Tests/builtins/Array/array-basic.js

@@ -55,3 +55,11 @@ test("basic functionality", () => {
     expect(a.toString()).toBe("1,20,2,,,3");
     expect(a.getterSetterValue).toBe(20);
 });
+
+test("assigning array expression with destination referenced in array expression", () => {
+    function go(i) {
+        var i = [i];
+        return i;
+    }
+    expect(go("foo")).toEqual(["foo"]);
+});

+ 8 - 0
Userland/Libraries/LibJS/Tests/object-basic.js

@@ -122,6 +122,14 @@ describe("correct behavior", () => {
         Object.setPrototypeOf(derived, base);
         expect(derived.getNumber()).toBe(30);
     });
+
+    test("assigning object expression with destination referenced in object expression", () => {
+        function go(i) {
+            var i = { f: i };
+            return i;
+        }
+        expect(go("foo")).toEqual({ f: "foo" });
+    });
 });
 
 describe("side effects", () => {