You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A new F() instance reads F's current .prototype, not its own [[Prototype]], after F.prototype is reassigned #11391
Found while reviewing #11383 (#10877). Reproduces on f6ad6defe (PR #11383's merge base) and is not changed by #11383.
Repro
functionF(this: any){}(Fasany).prototype={a: 1};consto: any=new(Fasany)();(Fasany).prototype={a: 2,b: 3};// o's [[Prototype]] is still { a: 1 }console.log(o.a,o.b,Object.getPrototypeOf(o)===(Fasany).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
changelog: key the #11391 fragment on PR 11407
fix(runtime): a new F() instance reads its recorded [[Prototype]] aft…
changelog: key the #11391 fragment on PR 11407
fix(runtime): a new F() instance reads its recorded [[Prototype]] aft…
changelog: key the #11391 fragment on PR 11407