Skip to content

Commit

Permalink
More aggressively inline decorators in the static block
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Feb 20, 2024
1 parent 5bb0b08 commit 245367a
Show file tree
Hide file tree
Showing 21 changed files with 99 additions and 84 deletions.
1 change: 0 additions & 1 deletion babel.config.js
Expand Up @@ -543,7 +543,6 @@ function pluginToggleBooleanFlag({ types: t }, { name, value }) {
if (left.value === false) return res.replace(right.replacement);
if (right.value === false) return res.replace(left.replacement);
if (left.unrelated && right.unrelated) return res.unrelated();
console.log(left, right);
return res.replace(
t.logicalExpression("||", left.replacement, right.replacement)
);
Expand Down
Expand Up @@ -751,6 +751,32 @@ function createPrivateBrandCheckClosure(brandName: t.PrivateName) {
);
}

// Check if the expression does not reference function-specific
// context or the given identifier name.
// `true` means "maybe" and `false` means "no".
function usesFunctionContextOrRef(
expression: t.Node,
refName: string | undefined,
) {
try {
t.traverseFast(expression, node => {
if (
t.isThisExpression(node) ||
t.isSuper(node) ||
t.isIdentifier(node, { name: "arguments" }) ||
(t.isMetaProperty(node) && node.meta.name !== "import") ||
(refName && t.isIdentifier(node, { name: refName }))
) {
// TODO: Add early return support to t.traverseFast
throw null;
}
});
return false;
} catch {
return true;
}
}

function checkPrivateMethodUpdateError(
path: NodePath<t.Class>,
decoratedPrivateMethods: Set<string>,
Expand Down Expand Up @@ -810,6 +836,8 @@ function transformClass(

const classDecorators = path.node.decorators;
let hasElementDecorators = false;
let hasComputedKeysSideEffects = false;
let elemDecsUseFnContext = false;

const generateClassPrivateUid = createLazyPrivateUidGeneratorForClass(path);

Expand Down Expand Up @@ -868,6 +896,9 @@ function transformClass(
break;
}
hasElementDecorators = true;
elemDecsUseFnContext ||= element.node.decorators.some(dec =>
usesFunctionContextOrRef(dec, path.node.id?.name),
);
} else if (element.node.type === "ClassAccessorProperty") {
// @ts-expect-error todo: propertyVisitor.ClassAccessorProperty should be callable. Improve typings.
propertyVisitor.ClassAccessorProperty(
Expand Down Expand Up @@ -896,6 +927,10 @@ function transformClass(
isStatic,
);
}

if ("computed" in element.node && element.node.computed) {
hasComputedKeysSideEffects ||= !scopeParent.isStatic(element.node.key);
}
}

if (!classDecorators && !hasElementDecorators) {
Expand All @@ -922,14 +957,16 @@ function transformClass(
// Memoise the this value `a.b` of decorator member expressions `@a.b.dec`,
type HandleDecoratorExpressionsResult = {
// whether the whole decorator list requires memoisation
needMemoise: boolean;
hasSideEffects: boolean;
usesFnContext: boolean;
// the this value of each decorator if applicable
decoratorsThis: (t.Expression | undefined)[];
};
function handleDecoratorExpressions(
expressions: t.Expression[],
): HandleDecoratorExpressionsResult {
let needMemoise = false;
let hasSideEffects = false;
let usesFnContext = false;
const decoratorsThis: (t.Expression | null)[] = [];
for (const expression of expressions) {
let object;
Expand All @@ -954,11 +991,21 @@ function transformClass(
}
}
decoratorsThis.push(object);
needMemoise ||= !scopeParent.isStatic(expression);
hasSideEffects ||= !scopeParent.isStatic(expression);
usesFnContext ||= usesFunctionContextOrRef(
expression,
path.node.id?.name,
);
}
return { needMemoise, decoratorsThis };
return { hasSideEffects, usesFnContext, decoratorsThis };
}

const willExtractSomeElemDecs =
hasComputedKeysSideEffects ||
(process.env.BABEL_8_BREAKING
? elemDecsUseFnContext
: elemDecsUseFnContext || version !== "2023-11");

let needsDeclaraionForClassBinding = false;
let classDecorationsFlag = 0;
let classDecorations: t.Expression[] = [];
Expand All @@ -971,7 +1018,7 @@ function transformClass(
path.node.decorators = null;

const decoratorExpressions = classDecorators.map(el => el.expression);
const { needMemoise, decoratorsThis } =
const { hasSideEffects, decoratorsThis } =
handleDecoratorExpressions(decoratorExpressions);

const { haveThis, decs } = generateDecorationList(
Expand All @@ -982,7 +1029,7 @@ function transformClass(
classDecorationsFlag = haveThis ? 1 : 0;
classDecorations = decs;

if (needMemoise) {
if (hasSideEffects && willExtractSomeElemDecs) {
classDecorationsId = memoiseExpression(
t.arrayExpression(classDecorations),
"classDecs",
Expand Down Expand Up @@ -1042,16 +1089,22 @@ function transformClass(

if (hasDecorators) {
const decoratorExpressions = decorators.map(d => d.expression);
const { needMemoise, decoratorsThis } =
handleDecoratorExpressions(decoratorExpressions);
const {
hasSideEffects,
usesFnContext: usesFunctionContext,
decoratorsThis,
} = handleDecoratorExpressions(decoratorExpressions);
const { decs, haveThis } = generateDecorationList(
decoratorExpressions,
decoratorsThis,
version,
);
decoratorsHaveThis = haveThis;
decoratorsArray = decs.length === 1 ? decs[0] : t.arrayExpression(decs);
if (needMemoise) {
if (
usesFunctionContext ||
(hasSideEffects && willExtractSomeElemDecs)
) {
decoratorsArray = memoiseExpression(decoratorsArray, name + "Decs");
}
}
Expand Down
@@ -1,4 +1,4 @@
var _initStatic, _initClass, _accessorDecs, _init_accessor, _init_extra_accessor, _getterDecs, _setterDecs, _methodDecs, _propertyDecs, _init_property, _init_extra_property, _A, _temp;
var _initStatic, _initClass, _init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _A, _temp;
let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis;
function dec(Klass, context) {
original = Klass;
Expand All @@ -15,11 +15,6 @@ function captureInitializerThis(callback) {
});
};
}
_accessorDecs = captureInitializerThis(v => accessorThis = v);
_getterDecs = captureInitializerThis(v => getterThis = v);
_setterDecs = captureInitializerThis(v => setterThis = v);
_methodDecs = captureInitializerThis(v => methodThis = v);
_propertyDecs = captureInitializerThis(v => propertyThis = v);
let _Foo;
new (_A = /*#__PURE__*/new WeakMap(), (_temp = class extends babelHelpers.identity {
constructor() {
Expand All @@ -44,7 +39,7 @@ new (_A = /*#__PURE__*/new WeakMap(), (_temp = class extends babelHelpers.identi
({
e: [_init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _initStatic],
c: [_Foo, _initClass]
} = babelHelpers.applyDecs2311(_Foo2, [dec], [[_accessorDecs, 9, "accessor"], [_getterDecs, 11, "getter"], [_setterDecs, 12, "setter"], [_methodDecs, 10, "method"], [_propertyDecs, 8, "property"]]));
} = babelHelpers.applyDecs2311(_Foo2, [dec], [[captureInitializerThis(v => accessorThis = v), 9, "accessor"], [captureInitializerThis(v => getterThis = v), 11, "getter"], [captureInitializerThis(v => setterThis = v), 12, "setter"], [captureInitializerThis(v => methodThis = v), 10, "method"], [captureInitializerThis(v => propertyThis = v), 8, "property"]]));
_initStatic(_Foo2);
})();
})(), _temp))();
@@ -1,20 +1,18 @@
var _initClass, _classDecs, _initClass2, _classDecs2, _Bar2;
var _initClass, _initClass2, _Bar2;
const dec = () => {};
_classDecs = [dec1];
let _Bar;
class Bar {
static {
[_Bar, _initClass] = babelHelpers.applyDecs2311(this, _classDecs, []).c;
[_Bar, _initClass] = babelHelpers.applyDecs2311(this, [dec1], []).c;
}
static {
_initClass();
}
}
_classDecs2 = [dec2];
let _Foo;
class Foo extends (_Bar2 = _Bar) {
static {
[_Foo, _initClass2] = babelHelpers.applyDecs2311(this, _classDecs2, [], 0, void 0, _Bar2).c;
[_Foo, _initClass2] = babelHelpers.applyDecs2311(this, [dec2], [], 0, void 0, _Bar2).c;
}
static {
_initClass2();
Expand Down
@@ -1,4 +1,4 @@
var _initStatic, _initClass, _accessorDecs, _init_accessor, _init_extra_accessor, _getterDecs, _setterDecs, _methodDecs, _propertyDecs, _init_property, _init_extra_property;
var _initStatic, _initClass, _init_accessor, _init_extra_accessor, _init_property, _init_extra_property;
let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis;
function dec(Klass, context) {
original = Klass;
Expand All @@ -15,11 +15,6 @@ function captureInitializerThis(callback) {
});
};
}
_accessorDecs = captureInitializerThis(v => accessorThis = v);
_getterDecs = captureInitializerThis(v => getterThis = v);
_setterDecs = captureInitializerThis(v => setterThis = v);
_methodDecs = captureInitializerThis(v => methodThis = v);
_propertyDecs = captureInitializerThis(v => propertyThis = v);
let _Foo;
new class extends babelHelpers.identity {
static {
Expand All @@ -28,7 +23,7 @@ new class extends babelHelpers.identity {
({
e: [_init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _initStatic],
c: [_Foo, _initClass]
} = babelHelpers.applyDecs2311(this, [dec], [[_accessorDecs, 9, "accessor"], [_getterDecs, 11, "getter"], [_setterDecs, 12, "setter"], [_methodDecs, 10, "method"], [_propertyDecs, 8, "property"]]));
} = babelHelpers.applyDecs2311(this, [dec], [[captureInitializerThis(v => accessorThis = v), 9, "accessor"], [captureInitializerThis(v => getterThis = v), 11, "getter"], [captureInitializerThis(v => setterThis = v), 12, "setter"], [captureInitializerThis(v => methodThis = v), 10, "method"], [captureInitializerThis(v => propertyThis = v), 8, "property"]]));
_initStatic(this);
}
static get accessor() {
Expand Down
@@ -1,9 +1,8 @@
var _initClass, _classDecs;
_classDecs = [dec];
var _initClass;
let _A;
class A {
static {
[_A, _initClass] = babelHelpers.applyDecs2311(this, _classDecs, []).c;
[_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c;
}
static {
_initClass();
Expand Down
@@ -1,9 +1,8 @@
var _initClass, _classDecs;
_classDecs = [dec];
var _initClass;
let _default2;
class _default {
static {
[_default2, _initClass] = babelHelpers.applyDecs2311(babelHelpers.setFunctionName(this, "default"), _classDecs, []).c;
[_default2, _initClass] = babelHelpers.applyDecs2311(babelHelpers.setFunctionName(this, "default"), [dec], []).c;
}
static {
_initClass();
Expand Down
@@ -1,8 +1,7 @@
var _xDecs, _init_x, _init_extra_x;
_xDecs = dec;
var _init_x, _init_extra_x;
export class A {
static {
[_init_x, _init_extra_x] = babelHelpers.applyDecs2311(this, [], [[_xDecs, 0, "x"]]).e;
[_init_x, _init_extra_x] = babelHelpers.applyDecs2311(this, [], [[dec, 0, "x"]]).e;
}
constructor() {
_init_extra_x(this);
Expand Down
@@ -1,9 +1,8 @@
var _initClass, _classDecs;
_classDecs = [dec];
var _initClass;
let _A;
class A {
static {
[_A, _initClass] = babelHelpers.applyDecs2311(this, _classDecs, []).c;
[_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c;
}
static {
_initClass();
Expand Down
@@ -1,7 +1,4 @@
var _initProto, _aDecs, _call_a, _gDecs, _call_g, _agDecs, _call_ag, _Foo;
_aDecs = dec;
_gDecs = dec;
_agDecs = dec;
var _initProto, _call_a, _call_g, _call_ag, _Foo;
var _ag = /*#__PURE__*/new WeakMap();
var _g = /*#__PURE__*/new WeakMap();
var _a = /*#__PURE__*/new WeakMap();
Expand All @@ -14,4 +11,4 @@ class Foo {
}
}
_Foo = Foo;
[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[_aDecs, 2, "a", async function () {}], [_gDecs, 2, "g", function* () {}], [_agDecs, 2, "ag", async function* () {}]], 0, _ => _a.has(babelHelpers.checkInRHS(_))).e;
[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, "a", async function () {}], [dec, 2, "g", function* () {}], [dec, 2, "ag", async function* () {}]], 0, _ => _a.has(babelHelpers.checkInRHS(_))).e;
@@ -1,10 +1,7 @@
var _initProto, _aDecs, _call_a, _gDecs, _call_g, _agDecs, _call_ag;
_aDecs = dec;
_gDecs = dec;
_agDecs = dec;
var _initProto, _call_a, _call_g, _call_ag;
class Foo {
static {
[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(this, [], [[_aDecs, 2, "a", async function () {}], [_gDecs, 2, "g", function* () {}], [_agDecs, 2, "ag", async function* () {}]], 0, _ => #a in _).e;
[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "a", async function () {}], [dec, 2, "g", function* () {}], [dec, 2, "ag", async function* () {}]], 0, _ => #a in _).e;
}
constructor() {
_initProto(this);
Expand Down
@@ -1,7 +1,4 @@
var _initClass, _obj, _classDecs, _xDecs, _init_x, _init_extra_x, _yDecs, _init_y, _init_extra_y, _A2;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
var _initClass, _obj, _init_x, _init_extra_x, _init_y, _init_extra_y, _A2;
let _A;
class A {
constructor() {
Expand All @@ -14,5 +11,5 @@ _A2 = A;
({
e: [_init_x, _init_extra_x, _init_y, _init_extra_y],
c: [_A, _initClass]
} = babelHelpers.applyDecs2311(_A2, _classDecs, [[_xDecs, 16, "x"], [_yDecs, 16, "y"]], 1));
} = babelHelpers.applyDecs2311(_A2, [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec], [[[_obj = o2, _obj.dec, _obj = o3.o, _obj.dec], 16, "x"], [[_obj = o2, _obj.dec, void 0, dec], 16, "y"]], 1));
_initClass();
@@ -1,7 +1,5 @@
var _initProto, _initClass, _obj, _classDecs, _methodDecs, _Foo2;
var _initProto, _initClass, _obj, _Foo2;
const dec = () => {};
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
let _Foo;
var _a = /*#__PURE__*/new WeakMap();
class Foo {
Expand All @@ -23,5 +21,5 @@ _Foo2 = Foo;
({
e: [_initProto],
c: [_Foo, _initClass]
} = babelHelpers.applyDecs2311(_Foo2, _classDecs, [[_methodDecs, 18, "method"]], 1));
} = babelHelpers.applyDecs2311(_Foo2, [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], [[[void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], 18, "method"]], 1));
_initClass();
Expand Up @@ -6,7 +6,7 @@ function dec(fn) {
}

@dec(() => {
expect(() => Foo).toThrow(ReferenceError);
expect(() => Foo.x).toThrow();
didRun = true;
}) class Foo {}

Expand Down
@@ -1,9 +1,8 @@
var _initProto, _methodDecs, _B, _initProto2, _methodDecs2, _B2;
var _initProto, _B, _initProto2, _B2;
const dec = () => {};
_methodDecs = deco;
class A extends (_B = B) {
static {
[_initProto] = babelHelpers.applyDecs2311(this, [], [[_methodDecs, 2, "method"]], 0, void 0, _B).e;
[_initProto] = babelHelpers.applyDecs2311(this, [], [[deco, 2, "method"]], 0, void 0, _B).e;
}
constructor() {
if (Math.random() > 0.5) {
Expand All @@ -14,10 +13,9 @@ class A extends (_B = B) {
}
method() {}
}
_methodDecs2 = deco;
class C extends (_B2 = B) {
static {
[_initProto2] = babelHelpers.applyDecs2311(this, [], [[_methodDecs2, 2, "method"]], 0, void 0, _B2).e;
[_initProto2] = babelHelpers.applyDecs2311(this, [], [[deco, 2, "method"]], 0, void 0, _B2).e;
}
constructor() {
try {
Expand Down
@@ -1,14 +1,11 @@
var _initClass, _obj, _classDecs, _xDecs, _init_x, _init_extra_x, _yDecs, _init_y, _init_extra_y;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec, _obj = o4.o(), _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec, _obj = o4.o(), _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
var _initClass, _obj, _init_x, _init_extra_x, _init_y, _init_extra_y;
let _A;
class A {
static {
({
e: [_init_x, _init_extra_x, _init_y, _init_extra_y],
c: [_A, _initClass]
} = babelHelpers.applyDecs2311(this, _classDecs, [[_xDecs, 16, "x"], [_yDecs, 16, "y"]], 1));
} = babelHelpers.applyDecs2311(this, [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec, _obj = o4.o(), _obj.dec], [[[_obj = o2, _obj.dec, _obj = o3.o, _obj.dec, _obj = o4.o(), _obj.dec], 16, "x"], [[_obj = o2, _obj.dec, void 0, dec], 16, "y"]], 1));
}
constructor() {
_init_extra_y(this);
Expand Down

0 comments on commit 245367a

Please sign in to comment.