Files
scriptc/tests/corpus/6918-local-class-expression-self-reference.mjs
T
Chris Tate 14694925c7 Bind a class expression's name used only in a shorthand property, and stop keeping local class prototypes alive
- A named function-local class expression whose only reference to its own
  name is a shorthand property (`static wrap() { return { Packed }; }`)
  now gets its name binding. The self-reference check read the shorthand
  name's property symbol, so the class lowered without the binding and the
  property held a placeholder function instead of the class.
- A function-local class's prototype takes its name from the class
  object's interned name instead of a registered copy. The registry kept
  every such prototype alive until the process exited, so evaluating a
  local class repeatedly kept each evaluation's prototype and the method
  state it captures: a program that evaluates a local class 200,000 times
  and prints each instance peaked at 121 MB, and now at 2 MB.
  Reusing a freed object clears its name.
2026-10-22 08:32:24 -05:00

62 lines
1.3 KiB
JavaScript

// Function-local class expressions in JavaScript whose static members and
// methods read the class by its own name.
function point(scale) {
const P = class Point {
static origin = new Point(0, 0);
static unit = Point.scaled(1);
constructor(x, y) {
this.x = x;
this.y = y;
}
static scaled(n) {
return new Point(n * scale, n * scale);
}
plus(other) {
return new Point(this.x + other.x, this.y + other.y);
}
};
return P;
}
const P = point(3);
const sum = P.origin.plus(P.unit).plus(P.unit);
console.log(sum.x, sum.y, P.unit instanceof P, P.name);
function selfName() {
const K = class Named {
static who() {
return Named === this;
}
};
return [K.who(), K.name, typeof K];
}
console.log(selfName());
function factory(tag) {
return class Tagged {
static count = 0;
constructor() {
Tagged.count++;
}
static make() {
return new Tagged();
}
get tag() {
return tag + Tagged.count;
}
};
}
const T = factory("t");
T.make();
console.log(T.make().tag, T.count, factory("u").count);
// The only reference to the name is a shorthand property.
function packed() {
const K = class Packed {
static wrap() {
return { Packed };
}
};
return [K.wrap().Packed === K, K.wrap().Packed.name];
}
console.log(packed());