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/ :^)
This commit is contained in:
Andreas Kling 2024-02-23 12:30:39 +01:00
parent b073fdd570
commit 6402ad29a6
Notes: sideshowbarker 2024-07-17 07:08:37 +09:00
3 changed files with 18 additions and 2 deletions

View file

@ -948,11 +948,11 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ForStatement::gener
return body_result; 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); 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); generator.emit<Bytecode::Op::NewObject>(object);
if (m_properties.is_empty()) if (m_properties.is_empty())

View file

@ -55,3 +55,11 @@ test("basic functionality", () => {
expect(a.toString()).toBe("1,20,2,,,3"); expect(a.toString()).toBe("1,20,2,,,3");
expect(a.getterSetterValue).toBe(20); 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"]);
});

View file

@ -122,6 +122,14 @@ describe("correct behavior", () => {
Object.setPrototypeOf(derived, base); Object.setPrototypeOf(derived, base);
expect(derived.getNumber()).toBe(30); 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", () => { describe("side effects", () => {