Skip to content

A new F() instance reads F's current .prototype, not its own [[Prototype]], after F.prototype is reassigned #11391

Description

@proggeramlug

Found while reviewing #11383 (#10877). Reproduces on f6ad6defe (PR #11383's merge base) and is not changed by #11383.

Repro

function F(this: any) {}
(F as any).prototype = { a: 1 };
const o: any = new (F as any)();
(F as any).prototype = { a: 2, b: 3 };        // o's [[Prototype]] is still { a: 1 }
console.log(o.a, o.b, Object.getPrototypeOf(o) === (F as any).prototype);
o.own = 1;
console.log(o.a, o.b);
line 1 line 2
node 1 undefined false 1 undefined
perry f6ad6defe 1 3 false 1 3

o.b answers 3, a property of an object that is not on o's prototype chain. Object.getPrototypeOf(o) is right, so the recorded per-instance link is right. The read path is wrong.

Mechanism

A new F() instance carries F's synthetic class id and a recorded per-instance prototype link. On an own-key miss, get_field_by_name_object_tail asks the class-id walk first (resolve_proto_chain_field_with_receiver). That walk reads CLASS_PROTOTYPE_OBJECTS[F], which is F's current .prototype. Only after that does it ask resolve_inherited_field, which reads the instance's own [[Prototype]]. When F.prototype has been reassigned since construction, the class-id walk answers from the wrong object. This is the same pair of walks behind #10877's 2^depth cost on F.prototype = new G() chains. #11383 skips the second walk when the two name the same object. It does not change which walk answers.

Correct design

The instance's own [[Prototype]] is the authority: after #11342 it is part of the instance's shape and meta. For an instance whose prototype was recorded at construction, the class-id walk must not answer. The read walks the recorded chain once. That also makes #11383's resolve_proto_chain_field_noting_miss reconciliation unnecessary. Related: #10507, where F.prototype identity is re-derived from side tables on every operation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions