Skip to content

Commit

Permalink
Reduce decorator static property size (#16287)
Browse files Browse the repository at this point in the history
* improve

* fix new test

* fix test

* add test

* Apply suggestions from code review

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>

* lint

---------

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
liuxingbaoyu and nicolo-ribaudo committed Feb 27, 2024
1 parent 4bd1d41 commit 702f2d7
Show file tree
Hide file tree
Showing 21 changed files with 209 additions and 147 deletions.
Expand Up @@ -603,6 +603,7 @@ function extractElementLocalAssignments(decorationInfo: DecoratorInfo[]) {
}

function addCallAccessorsFor(
version: DecoratorVersionKind,
element: NodePath,
key: t.PrivateName,
getId: t.Identifier,
Expand All @@ -616,7 +617,12 @@ function addCallAccessorsFor(
[],
t.blockStatement([
t.returnStatement(
t.callExpression(t.cloneNode(getId), [t.thisExpression()]),
t.callExpression(
t.cloneNode(getId),
(process.env.BABEL_8_BREAKING || version === "2023-11") && isStatic
? []
: [t.thisExpression()],
),
),
]),
isStatic,
Expand All @@ -630,10 +636,12 @@ function addCallAccessorsFor(
[t.identifier("v")],
t.blockStatement([
t.expressionStatement(
t.callExpression(t.cloneNode(setId), [
t.thisExpression(),
t.identifier("v"),
]),
t.callExpression(
t.cloneNode(setId),
(process.env.BABEL_8_BREAKING || version === "2023-11") && isStatic
? [t.identifier("v")]
: [t.thisExpression(), t.identifier("v")],
),
),
]),
isStatic,
Expand Down Expand Up @@ -1085,7 +1093,10 @@ function transformClass(
if (kind === ACCESSOR) {
const { value } = element.node as t.ClassAccessorProperty;

const params: t.Expression[] = [t.thisExpression()];
const params: t.Expression[] =
(process.env.BABEL_8_BREAKING || version === "2023-11") && isStatic
? []
: [t.thisExpression()];

if (value) {
params.push(t.cloneNode(value));
Expand All @@ -1112,7 +1123,7 @@ function transformClass(
`set_${name}`,
);

addCallAccessorsFor(newPath, key, getId, setId, isStatic);
addCallAccessorsFor(version, newPath, key, getId, setId, isStatic);

locals = [newFieldInitId, getId, setId];
} else {
Expand All @@ -1135,12 +1146,13 @@ function transformClass(
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>
).get("value");

valuePath.replaceWith(
t.callExpression(
t.cloneNode(initId),
[t.thisExpression(), valuePath.node].filter(v => v),
),
);
const args: t.Expression[] =
(process.env.BABEL_8_BREAKING || version === "2023-11") && isStatic
? []
: [t.thisExpression()];
if (valuePath.node) args.push(valuePath.node);

valuePath.replaceWith(t.callExpression(t.cloneNode(initId), args));

locals = [initId];

Expand Down Expand Up @@ -1248,9 +1260,10 @@ function transformClass(
`init_extra_${name}`,
);
locals.push(initExtraId);
const initExtraCall = t.callExpression(t.cloneNode(initExtraId), [
t.thisExpression(),
]);
const initExtraCall = t.callExpression(
t.cloneNode(initExtraId),
isStatic ? [] : [t.thisExpression()],
);
if (!isStatic) {
fieldInitializerExpressions.push(initExtraCall);
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -48,10 +48,10 @@ export default Object.freeze({
"7.21.0",
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2305(e,t,r,n,o,a){function i(e,t,r){return function(n,o){return r&&r(n),e[t].call(n,o)}}function c(e,t){for(var r=0;r<e.length;r++)e[r].call(t);return t}function s(e,t,r,n){if("function"!=typeof e&&(n||void 0!==e))throw new TypeError(t+" must "+(r||"be")+" a function"+(n?"":" or undefined"));return e}function applyDec(e,t,r,n,o,a,c,u,l,f,p,d,h){function m(e){if(!h(e))throw new TypeError("Attempted to access private element on non-instance")}var y,v=t[0],g=t[3],b=!u;if(!b){r||Array.isArray(v)||(v=[v]);var w={},S=[],A=3===o?"get":4===o||d?"set":"value";f?(p||d?w={get:setFunctionName((function(){return g(this)}),n,"get"),set:function(e){t[4](this,e)}}:w[A]=g,p||setFunctionName(w[A],n,2===o?"":A)):p||(w=Object.getOwnPropertyDescriptor(e,n))}for(var P=e,j=v.length-1;j>=0;j-=r?2:1){var D=v[j],E=r?v[j-1]:void 0,I={},O={kind:["field","accessor","method","getter","setter","class"][o],name:n,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");s(t,"An initializer","be",!0),c.push(t)}.bind(null,I)};try{if(b)(y=s(D.call(E,P,O),"class decorators","return"))&&(P=y);else{var k,F;O.static=l,O.private=f,f?2===o?k=function(e){return m(e),w.value}:(o<4&&(k=i(w,"get",m)),3!==o&&(F=i(w,"set",m))):(k=function(e){return e[n]},(o<2||4===o)&&(F=function(e,t){e[n]=t}));var N=O.access={has:f?h.bind():function(e){return n in e}};if(k&&(N.get=k),F&&(N.set=F),P=D.call(E,d?{get:w.get,set:w.set}:w[A],O),d){if("object"==typeof P&&P)(y=s(P.get,"accessor.get"))&&(w.get=y),(y=s(P.set,"accessor.set"))&&(w.set=y),(y=s(P.init,"accessor.init"))&&S.push(y);else if(void 0!==P)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0")}else s(P,(p?"field":"method")+" decorators","return")&&(p?S.push(P):w[A]=P)}}finally{I.v=!0}}return(p||d)&&u.push((function(e,t){for(var r=S.length-1;r>=0;r--)t=S[r].call(e,t);return t})),p||b||(f?d?u.push(i(w,"get"),i(w,"set")):u.push(2===o?w[A]:i.call.bind(w[A])):Object.defineProperty(e,n,w)),P}function u(e,t){return Object.defineProperty(e,Symbol.metadata||Symbol.for("Symbol.metadata"),{configurable:!0,enumerable:!0,value:t})}if(arguments.length>=6)var l=a[Symbol.metadata||Symbol.for("Symbol.metadata")];var f=Object.create(null==l?null:l),p=function(e,t,r,n){var o,a,i=[],s=function(t){return checkInRHS(t)===e},u=new Map;function l(e){e&&i.push(c.bind(null,e))}for(var f=0;f<t.length;f++){var p=t[f];if(Array.isArray(p)){var d=p[1],h=p[2],m=p.length>3,y=16&d,v=!!(8&d),g=0==(d&=7),b=h+"/"+v;if(!g&&!m){var w=u.get(b);if(!0===w||3===w&&4!==d||4===w&&3!==d)throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: "+h);u.set(b,!(d>2)||d)}applyDec(v?e:e.prototype,p,y,m?"#"+h:toPropertyKey(h),d,n,v?a=a||[]:o=o||[],i,v,m,g,1===d,v&&m?s:r)}}return l(o),l(a),i}(e,t,o,f);return r.length||u(e,f),{e:p,get c(){var t=[];return r.length&&[u(applyDec(e,[r],n,e.name,5,f,t),f),c.bind(null,t,e)]}}}',
),
// size: 2899, gzip size: 1475
// size: 2917, gzip size: 1487
applyDecs2311: helper(
"7.23.0",
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2311(e,t,n,r,o,i){var a,c,u=Symbol.metadata||Symbol.for("Symbol.metadata"),s=Object.defineProperty,l=Object.create,f=[l(null),l(null)],p=n.length;function d(e,t,n,r){for(var o=0;o<e.length;o++)r=e[o].apply(n,t?[r]:[]);return t?r:n}function m(e,t,n,r){if("function"!=typeof e&&(r||void 0!==e))throw new TypeError(t+" must "+(n||"be")+" a function"+(r?"":" or undefined"));return e}function applyDec(e,t,n,r,o,i,u,l,p,h,y,v){function g(e){if(!v(e))throw new TypeError("Attempted to access private element on non-instance")}var b=[].concat(t[0]),w=t[3],D=!u,S=3===o,j=4===o,E=2===o;function I(e,t){return function(n,r){return t&&t(n),P[e].call(n,r)}}if(!D){var P={},k=[],F=S?"get":j||y?"set":"value";if(p?(h||y?P={get:setFunctionName((function(){return w(this)}),r,"get"),set:function(e){t[4](this,e)}}:P[F]=w,h||setFunctionName(P[F],r,E?"":F)):h||(P=Object.getOwnPropertyDescriptor(e,r)),!h&&!p){if((c=f[+l][r])&&7!=(c^o))throw new Error("Decorating two elements with the same name ("+P[F].name+") is not supported yet");f[+l][r]=o<3?1:o}}for(var N=e,O=b.length-1;O>=0;O-=n?2:1){var z=b[O],H=n?b[O-1]:void 0,K={},R={kind:["field","accessor","method","getter","setter","class"][o],name:r,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");m(t,"An initializer","be",!0),i.push(t)}.bind(null,K)};if(D)c=z.call(H,N,R),K.v=1,m(c,"class decorators","return")&&(N=c);else if(R.static=l,R.private=p,c=R.access={has:p?v.bind():function(e){return r in e}},j||(c.get=p?E?function(e){return g(e),P.value}:I("get",g):function(e){return e[r]}),E||S||(c.set=p?I("set",g):function(e,t){e[r]=t}),N=z.call(H,y?{get:P.get,set:P.set}:P[F],R),K.v=1,y){if("object"==typeof N&&N)(c=m(N.get,"accessor.get"))&&(P.get=c),(c=m(N.set,"accessor.set"))&&(P.set=c),(c=m(N.init,"accessor.init"))&&k.unshift(c);else if(void 0!==N)throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined")}else m(N,(h?"field":"method")+" decorators","return")&&(h?k.unshift(N):P[F]=N)}return o<2&&u.push(d.bind(null,k,1),d.bind(null,i,0)),h||D||(p?y?u.splice(-1,0,I("get"),I("set")):u.push(E?P[F]:d.call.bind(P[F])):s(e,r,P)),N}function h(e){return s(e,u,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[u]),a=l(null==a?null:a),c=function(){var n,r,i=[];function a(e){e&&i.push(d.bind(null,e,0))}for(var c=0;c<t.length;c++){var u=t[c],s=u[1],l=u[2],f=!!u[3],p=16&s,m=!!(8&s),h=0==(s&=7),y=1===s;applyDec(m?e:e.prototype,u,p,f?"#"+l:toPropertyKey(l),s,h||y?[]:m?r=r||[]:n=n||[],i,m,f,h,y,m&&f?function(t){return checkInRHS(t)===e}:o)}return a(n),a(r),i}(),p||h(e),{e:c,get c(){var t=[];return p&&[h(applyDec(e,[n],r,e.name,5,t)),d.bind(null,t,0,e)]}}}',
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2311(e,t,n,r,o,i){var a,c,u=Symbol.metadata||Symbol.for("Symbol.metadata"),s=Object.defineProperty,f=Object.create,l=[f(null),f(null)],p=n.length;function d(t,n,r){return function(o,i){n&&(i=o,o=e);for(var a=0;a<t.length;a++)i=t[a].apply(o,r?[i]:[]);return r?i:o}}function m(e,t,n,r){if("function"!=typeof e&&(r||void 0!==e))throw new TypeError(t+" must "+(n||"be")+" a function"+(r?"":" or undefined"));return e}function applyDec(e,t,n,r,o,i,u,f,p,h,y,v){function g(e){if(!v(e))throw new TypeError("Attempted to access private element on non-instance")}var b=[].concat(t[0]),w=t[3],D=!u,S=3===o,j=4===o,E=2===o;function I(t,n,r){return function(o,i){return n&&(i=o,o=e),r&&r(o),P[t].call(o,i)}}if(!D){var P={},k=[],F=S?"get":j||y?"set":"value";if(p?(h||y?P={get:setFunctionName((function(){return w(this)}),r,"get"),set:function(e){t[4](this,e)}}:P[F]=w,h||setFunctionName(P[F],r,E?"":F)):h||(P=Object.getOwnPropertyDescriptor(e,r)),!h&&!p){if((c=l[+f][r])&&7!=(c^o))throw new Error("Decorating two elements with the same name ("+P[F].name+") is not supported yet");l[+f][r]=o<3?1:o}}for(var N=e,O=b.length-1;O>=0;O-=n?2:1){var z=b[O],H=n?b[O-1]:void 0,K={},R={kind:["field","accessor","method","getter","setter","class"][o],name:r,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");m(t,"An initializer","be",!0),i.push(t)}.bind(null,K)};if(D)c=z.call(H,N,R),K.v=1,m(c,"class decorators","return")&&(N=c);else if(R.static=f,R.private=p,c=R.access={has:p?v.bind():function(e){return r in e}},j||(c.get=p?E?function(e){return g(e),P.value}:I("get",0,g):function(e){return e[r]}),E||S||(c.set=p?I("set",0,g):function(e,t){e[r]=t}),N=z.call(H,y?{get:P.get,set:P.set}:P[F],R),K.v=1,y){if("object"==typeof N&&N)(c=m(N.get,"accessor.get"))&&(P.get=c),(c=m(N.set,"accessor.set"))&&(P.set=c),(c=m(N.init,"accessor.init"))&&k.unshift(c);else if(void 0!==N)throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined")}else m(N,(h?"field":"method")+" decorators","return")&&(h?k.unshift(N):P[F]=N)}return o<2&&u.push(d(k,f,1),d(i,f,0)),h||D||(p?y?u.splice(-1,0,I("get",f),I("set",f)):u.push(E?P[F]:m.call.bind(P[F])):s(e,r,P)),N}function h(e){return s(e,u,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[u]),a=f(null==a?null:a),c=function(){var n,r,i=[];function a(e){e&&i.push(d(e))}for(var c=0;c<t.length;c++){var u=t[c],s=u[1],f=u[2],l=!!u[3],p=16&s,m=!!(8&s),h=0==(s&=7),y=1===s;applyDec(m?e:e.prototype,u,p,l?"#"+f:toPropertyKey(f),s,h||y?[]:m?r=r||[]:n=n||[],i,m,l,h,y,m&&l?function(t){return checkInRHS(t)===e}:o)}return a(n),a(r),i}(),p||h(e),{e:c,get c(){var t=[];return p&&[h(e=applyDec(e,[n],r,e.name,5,t)),d(t,1)]}}}',
),
// size: 187, gzip size: 167
assertClassBrand: helper(
Expand Down
56 changes: 37 additions & 19 deletions packages/babel-helpers/src/helpers/applyDecs2311.ts
Expand Up @@ -213,16 +213,21 @@ export default /* @no-mangle */ function applyDecs2311(
// This is a temporary variable for smaller helper size
var _: any;

function runInitializers(
function createRunInitializers(
initializers: Function[],
hasValue: 0 | 1,
thisArg: any,
value?: any,
useStaticThis?: 0 | 1 | boolean,
hasValue?: 0 | 1,
) {
for (var i = 0; i < initializers.length; i++) {
value = initializers[i].apply(thisArg, hasValue ? [value] : []);
}
return hasValue ? value : thisArg;
return function (thisArg: any, value?: any) {
if (useStaticThis) {
value = thisArg;
thisArg = targetClass;
}
for (var i = 0; i < initializers.length; i++) {
value = initializers[i].apply(thisArg, hasValue ? [value] : []);
}
return hasValue ? value : thisArg;
};
}

function assertCallable(
Expand Down Expand Up @@ -276,8 +281,16 @@ export default /* @no-mangle */ function applyDecs2311(
var isSetter = kind === PROP_KIND.SETTER;
var isMethod = kind === PROP_KIND.METHOD;

function _bindPropCall(name: keyof PropertyDescriptor, before?: Function) {
function _bindPropCall(
name: keyof PropertyDescriptor,
useStaticThis: 0 | 1 | boolean,
before?: Function,
) {
return function (_this: any, value?: any) {
if (useStaticThis) {
value = _this;
_this = Class;
}
if (before) {
before(_this);
}
Expand Down Expand Up @@ -395,14 +408,14 @@ export default /* @no-mangle */ function applyDecs2311(
assertInstanceIfPrivate(_this);
return desc.value;
}
: _bindPropCall("get", assertInstanceIfPrivate)
: _bindPropCall("get", 0, assertInstanceIfPrivate)
: function (target: any) {
return target[name];
};
}
if (!isMethod && !isGetter) {
_.set = isPrivate
? _bindPropCall("set", assertInstanceIfPrivate)
? _bindPropCall("set", 0, assertInstanceIfPrivate)
: function (target: any, v: any) {
target[name] = v;
};
Expand Down Expand Up @@ -456,23 +469,28 @@ export default /* @no-mangle */ function applyDecs2311(
if (kind < PROP_KIND.METHOD) {
ret.push(
// init
runInitializers.bind(null, init, 1),
createRunInitializers(init, isStatic, 1),
// init_extra
runInitializers.bind(null, initializers, 0),
createRunInitializers(initializers, isStatic, 0),
);
}

if (!isField && !isClass) {
if (isPrivate) {
if (isAccessor) {
// get and set should be returned before init_extra
ret.splice(-1, 0, _bindPropCall("get"), _bindPropCall("set"));
ret.splice(
-1,
0,
_bindPropCall("get", isStatic),
_bindPropCall("set", isStatic),
);
} else {
ret.push(
isMethod
? desc[key]
: // Equivalent to `Function.call`, just to reduce code size
runInitializers.call.bind(desc[key]),
assertCallable.call.bind(desc[key]),
);
}
} else {
Expand All @@ -490,7 +508,7 @@ export default /* @no-mangle */ function applyDecs2311(

function pushInitializers(initializers: Function[]) {
if (initializers) {
ret.push(runInitializers.bind(null, initializers, 0));
ret.push(createRunInitializers(initializers));
}
}

Expand Down Expand Up @@ -562,16 +580,16 @@ export default /* @no-mangle */ function applyDecs2311(
return (
hasClassDecs && [
defineMetadata(
applyDec(
(targetClass = applyDec(
targetClass,
[classDecs],
classDecsHaveThis,
targetClass.name,
PROP_KIND.CLASS,
initializers,
),
)),
),
runInitializers.bind(null, initializers, 0, targetClass),
createRunInitializers(initializers, 1),
]
);
},
Expand Down
Expand Up @@ -62,38 +62,38 @@ class Foo {
}
_Foo = Foo;
function _set_a2(v) {
_set_a(this, v);
_set_a(v);
}
function _get_a2() {
return _get_a(this);
return _get_a();
}
[_init_a, _init_extra_a, _init_a2, _get_a, _set_a, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _init_computedKey7, _init_extra_computedKey7] = babelHelpers.applyDecs2311(_Foo, [[dec, 9, "a"], [dec, 9, "a", o => babelHelpers.assertClassBrand(o, _Foo, _B)._, (o, v) => _B._ = babelHelpers.assertClassBrand(o, _Foo, v)], [dec, 9, "b"], [dec, 9, "c"], [dec, 9, 0], [dec, 9, 1], [dec, 9, 2n], [dec, 9, 3n], [dec, 9, _computedKey]], []).e;
var _A = {
_: _init_a(_Foo)
_: _init_a()
};
var _B = {
_: (_init_extra_a(_Foo), _init_a2(_Foo))
_: (_init_extra_a(), _init_a2())
};
var _C = {
_: (_init_extra_a2(_Foo), _init_computedKey(_Foo))
_: (_init_extra_a2(), _init_computedKey())
};
var _D = {
_: (_init_extra_computedKey(_Foo), _init_computedKey2(_Foo))
_: (_init_extra_computedKey(), _init_computedKey2())
};
var _E = {
_: (_init_extra_computedKey2(_Foo), _init_computedKey3(_Foo))
_: (_init_extra_computedKey2(), _init_computedKey3())
};
var _F = {
_: (_init_extra_computedKey3(_Foo), _init_computedKey4(_Foo))
_: (_init_extra_computedKey3(), _init_computedKey4())
};
var _G = {
_: (_init_extra_computedKey4(_Foo), _init_computedKey5(_Foo))
_: (_init_extra_computedKey4(), _init_computedKey5())
};
var _H = {
_: (_init_extra_computedKey5(_Foo), _init_computedKey6(_Foo))
_: (_init_extra_computedKey5(), _init_computedKey6())
};
var _I = {
_: (_init_extra_computedKey6(_Foo), _init_computedKey7(_Foo))
_: (_init_extra_computedKey6(), _init_computedKey7())
};
_init_extra_computedKey7(_Foo);
_init_extra_computedKey7();
expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]);
Expand Up @@ -3,22 +3,22 @@ const dec = () => {};
class Foo {}
_Foo = Foo;
function _set_a2(v) {
_set_a(this, v);
_set_a(v);
}
function _get_a2() {
return _get_a(this);
return _get_a();
}
function _set_b2(v) {
_set_b(this, v);
_set_b(v);
}
function _get_b2() {
return _get_b(this);
return _get_b();
}
[_init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b] = babelHelpers.applyDecs2311(_Foo, [[dec, 9, "a", o => babelHelpers.assertClassBrand(o, _Foo, _A)._, (o, v) => _A._ = babelHelpers.assertClassBrand(o, _Foo, v)], [dec, 9, "b", o => babelHelpers.assertClassBrand(o, _Foo, _B)._, (o, v) => _B._ = babelHelpers.assertClassBrand(o, _Foo, v)]], []).e;
var _A = {
_: _init_a(_Foo)
_: _init_a()
};
var _B = {
_: (_init_extra_a(_Foo), _init_b(_Foo, 123))
_: (_init_extra_a(), _init_b(123))
};
_init_extra_b(_Foo);
_init_extra_b();
Expand Up @@ -23,12 +23,12 @@ class Foo {
_Foo = Foo;
[_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_Foo, [[dec, 9, "a"], [dec, 9, "b"], [dec, 9, 'c']], []).e;
var _A = {
_: _init_a(_Foo)
_: _init_a()
};
var _B = {
_: (_init_extra_a(_Foo), _init_b(_Foo, 123))
_: (_init_extra_a(), _init_b(123))
};
var _C = {
_: (_init_extra_b(_Foo), _init_computedKey(_Foo, 456))
_: (_init_extra_b(), _init_computedKey(456))
};
_init_extra_computedKey(_Foo);
_init_extra_computedKey();

0 comments on commit 702f2d7

Please sign in to comment.