perf(ivy): remove unused event argument in listener instructions (#35097)
Currently Ivy always generates the `$event` function argument, even if it isn't being used by the listener expressions. This can lead to unnecessary bytes being generated, because optimizers won't remove unused arguments by default. These changes add some logic to avoid adding the argument when it isn't required. PR Close #35097
This commit is contained in:

committed by
Miško Hevery

parent
39ef57971c
commit
9228d7f15d
@ -70,7 +70,8 @@ export type InterpolationFunction = (args: o.Expression[]) => o.Expression;
|
||||
export function convertActionBinding(
|
||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST,
|
||||
bindingId: string, interpolationFunction?: InterpolationFunction,
|
||||
baseSourceSpan?: ParseSourceSpan): ConvertActionBindingResult {
|
||||
baseSourceSpan?: ParseSourceSpan,
|
||||
implicitReceiverAccesses?: Set<string>): ConvertActionBindingResult {
|
||||
if (!localResolver) {
|
||||
localResolver = new DefaultLocalResolver();
|
||||
}
|
||||
@ -98,7 +99,8 @@ export function convertActionBinding(
|
||||
action);
|
||||
|
||||
const visitor = new _AstToIrVisitor(
|
||||
localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan);
|
||||
localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan,
|
||||
implicitReceiverAccesses);
|
||||
const actionStmts: o.Statement[] = [];
|
||||
flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
|
||||
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
||||
@ -313,7 +315,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
constructor(
|
||||
private _localResolver: LocalResolver, private _implicitReceiver: o.Expression,
|
||||
private bindingId: string, private interpolationFunction: InterpolationFunction|undefined,
|
||||
private baseSourceSpan?: ParseSourceSpan) {}
|
||||
private baseSourceSpan?: ParseSourceSpan, private implicitReceiverAccesses?: Set<string>) {}
|
||||
|
||||
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
||||
let op: o.BinaryOperator;
|
||||
@ -493,6 +495,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
this.usesImplicitReceiver = prevUsesImplicitReceiver;
|
||||
result = varExpr.callFn(args);
|
||||
}
|
||||
this.addImplicitReceiverAccess(ast.name);
|
||||
}
|
||||
if (result == null) {
|
||||
result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
|
||||
@ -525,6 +528,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
// receiver has been replaced with a resolved local expression.
|
||||
this.usesImplicitReceiver = prevUsesImplicitReceiver;
|
||||
}
|
||||
this.addImplicitReceiverAccess(ast.name);
|
||||
}
|
||||
if (result == null) {
|
||||
result = receiver.prop(ast.name);
|
||||
@ -549,6 +553,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
// Restore the previous "usesImplicitReceiver" state since the implicit
|
||||
// receiver has been replaced with a resolved local expression.
|
||||
this.usesImplicitReceiver = prevUsesImplicitReceiver;
|
||||
this.addImplicitReceiverAccess(ast.name);
|
||||
} else {
|
||||
// Otherwise it's an error.
|
||||
const receiver = ast.name;
|
||||
@ -780,6 +785,13 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds the name of an AST to the list of implicit receiver accesses. */
|
||||
private addImplicitReceiverAccess(name: string) {
|
||||
if (this.implicitReceiverAccesses) {
|
||||
this.implicitReceiverAccesses.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flattenStatements(arg: any, output: o.Statement[]) {
|
||||
|
@ -69,13 +69,14 @@ export function prepareEventListenerParameters(
|
||||
Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`);
|
||||
}
|
||||
|
||||
const eventArgumentName = '$event';
|
||||
const implicitReceiverAccesses = new Set<string>();
|
||||
const implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
|
||||
o.variable(CONTEXT_NAME) :
|
||||
scope.getOrCreateSharedContextVar(0);
|
||||
const bindingExpr = convertActionBinding(
|
||||
scope, implicitReceiverExpr, handler, 'b', () => error('Unexpected interpolation'),
|
||||
eventAst.handlerSpan);
|
||||
|
||||
eventAst.handlerSpan, implicitReceiverAccesses);
|
||||
const statements = [];
|
||||
if (scope) {
|
||||
statements.push(...scope.restoreViewStatement());
|
||||
@ -86,9 +87,13 @@ export function prepareEventListenerParameters(
|
||||
const eventName: string =
|
||||
type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase !) : name;
|
||||
const fnName = handlerName && sanitizeIdentifier(handlerName);
|
||||
const fnArgs = [new o.FnParam('$event', o.DYNAMIC_TYPE)];
|
||||
const handlerFn = o.fn(fnArgs, statements, o.INFERRED_TYPE, null, fnName);
|
||||
const fnArgs: o.FnParam[] = [];
|
||||
|
||||
if (implicitReceiverAccesses.has(eventArgumentName)) {
|
||||
fnArgs.push(new o.FnParam(eventArgumentName, o.DYNAMIC_TYPE));
|
||||
}
|
||||
|
||||
const handlerFn = o.fn(fnArgs, statements, o.INFERRED_TYPE, null, fnName);
|
||||
const params: o.Expression[] = [o.literal(eventName), handlerFn];
|
||||
if (target) {
|
||||
params.push(
|
||||
|
Reference in New Issue
Block a user