Skip to content
This repository was archived by the owner on Sep 16, 2022. It is now read-only.

Commit a0bf5e8

Browse files
committed
perf(AppView): Move host events from call sites to component implementation.
Move largetemplates codesize benchmark to codegen, fix new errors caught by codegen. Remove unused removeListener closure from EventsPlugin. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=149767415
1 parent 23813d6 commit a0bf5e8

File tree

15 files changed

+241
-81
lines changed

15 files changed

+241
-81
lines changed

lib/compiler.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ export "src/compiler/compiler.dart"
3030
CompileDirectiveMetadata,
3131
CompilePipeMetadata;
3232
export "src/compiler/template_ast.dart";
33+
export "src/compiler/view_compiler/parse_utils.dart";

lib/src/compiler/expression_parser/ast.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class ASTWithSource extends AST {
241241
}
242242

243243
@override
244-
String toString() => '''${ this . source} in ${ this . location}''';
244+
String toString() => '$source in $location';
245245
}
246246

247247
class TemplateBinding {

lib/src/compiler/expression_parser/parser.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ class TemplateBindingParseResult {
7373

7474
@Injectable()
7575
class Parser {
76-
Lexer _lexer;
76+
final Lexer _lexer;
77+
7778
Parser(this._lexer);
79+
7880
ASTWithSource parseAction(String input, dynamic location) {
7981
this._checkNoInterpolation(input, location);
80-
var tokens = this._lexer.tokenize(this._stripComments(input));
82+
var tokens = _lexer.tokenize(this._stripComments(input));
8183
var ast = new _ParseAST(input, location, tokens, true).parseChain();
8284
return new ASTWithSource(ast, input, location);
8385
}

lib/src/compiler/template_ast.dart

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import 'compile_metadata.dart'
66
CompileDirectiveMetadata,
77
CompileTokenMetadata,
88
CompileProviderMetadata;
9-
import 'expression_parser/ast.dart'
10-
show AST, ASTWithSource, ImplicitReceiver, MethodCall, PropertyRead;
11-
import 'view_compiler/constants.dart';
9+
import 'expression_parser/ast.dart' show AST;
10+
import 'package:angular2/src/compiler/view_compiler/parse_utils.dart'
11+
show handlerTypeFromExpression, HandlerType;
1212

1313
/// An Abstract Syntax Tree node representing part of a parsed Angular template.
1414
abstract class TemplateAst {
@@ -74,8 +74,6 @@ abstract class ElementProviderUsage {
7474
bool hasNonLocalRequest(ProviderAst providerAst);
7575
}
7676

77-
enum HandlerType { simpleNoArgs, simpleOneArg, notSimple }
78-
7977
/// A binding for an element event (e.g. (event)='handler()').
8078
class BoundEventAst implements TemplateAst {
8179
String name;
@@ -86,48 +84,7 @@ class BoundEventAst implements TemplateAst {
8684
return visitor.visitEvent(this, context);
8785
}
8886

89-
/// Classifies this event binding by it's form.
90-
///
91-
/// The simple form looks like
92-
///
93-
/// (event)="handler($event)"
94-
///
95-
/// or
96-
///
97-
/// (event)="handler()"
98-
///
99-
/// Since these types of handlers are so common, we can optimize the code
100-
/// generated for them.
101-
HandlerType get handlerType {
102-
var eventHandler = handler;
103-
if (eventHandler is ASTWithSource) {
104-
eventHandler = (eventHandler as ASTWithSource).ast;
105-
}
106-
if (eventHandler is! MethodCall) {
107-
return HandlerType.notSimple;
108-
}
109-
var call = eventHandler as MethodCall;
110-
if (call.receiver is! ImplicitReceiver) {
111-
return HandlerType.notSimple;
112-
}
113-
if (call.args.isEmpty) {
114-
return HandlerType.simpleNoArgs;
115-
}
116-
if (call.args.length != 1) {
117-
return HandlerType.notSimple;
118-
}
119-
var singleArg = call.args.single;
120-
if (singleArg is! PropertyRead) {
121-
return HandlerType.notSimple;
122-
}
123-
var property = singleArg as PropertyRead;
124-
if (property.name == EventHandlerVars.event.name &&
125-
property.receiver is ImplicitReceiver) {
126-
return HandlerType.simpleOneArg;
127-
} else {
128-
return HandlerType.notSimple;
129-
}
130-
}
87+
HandlerType get handlerType => handlerTypeFromExpression(handler);
13188
}
13289

13390
/// A reference declaration on an element (e.g. let someName='expression').

lib/src/compiler/view_compiler/event_binder.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import '../compile_metadata.dart' show CompileDirectiveMetadata;
22
import '../output/output_ast.dart' as o;
3-
import '../template_ast.dart' show BoundEventAst, DirectiveAst, HandlerType;
3+
import '../template_ast.dart' show BoundEventAst, DirectiveAst;
44
import 'compile_binding.dart' show CompileBinding;
55
import 'compile_element.dart' show CompileElement;
66
import 'compile_method.dart' show CompileMethod;
77
import 'constants.dart' show EventHandlerVars;
88
import 'expression_converter.dart' show convertCdStatementToIr;
9+
import 'parse_utils.dart';
910

1011
/// Generates code to listen to a single eventName on a [CompileElement].
1112
///
@@ -164,7 +165,8 @@ class CompileEventListener {
164165
}
165166

166167
List<CompileEventListener> collectEventListeners(List<BoundEventAst> hostEvents,
167-
List<DirectiveAst> dirs, CompileElement compileElement) {
168+
List<DirectiveAst> dirs, CompileElement compileElement,
169+
{bool includeComponentOutputs: true}) {
168170
List<CompileEventListener> eventListeners = [];
169171
for (var hostEvent in hostEvents) {
170172
compileElement.view.bindings
@@ -177,6 +179,10 @@ List<CompileEventListener> collectEventListeners(List<BoundEventAst> hostEvents,
177179
for (var directiveAst in dirs) {
178180
i++;
179181
var directiveInstance = compileElement.directiveInstances[i];
182+
if (includeComponentOutputs == false &&
183+
directiveAst.directive.isComponent) {
184+
continue;
185+
}
180186
for (var hostEvent in directiveAst.hostEvents) {
181187
compileElement.view.bindings
182188
.add(new CompileBinding(compileElement, hostEvent));
@@ -218,12 +224,6 @@ o.Expression convertStmtIntoExpression(o.Statement stmt) {
218224
return null;
219225
}
220226

221-
final RegExp _eventNameRegExp = new RegExp(r'[^a-zA-Z_]');
222-
223-
String sanitizeEventName(String name) {
224-
return name.replaceAll(_eventNameRegExp, '_');
225-
}
226-
227227
o.Expression _extractFunction(o.Expression returnExpr) {
228228
assert(returnExpr is o.InvokeMethodExpr);
229229
var callExpr = returnExpr as o.InvokeMethodExpr;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import '../expression_parser/ast.dart'
2+
show AST, ASTWithSource, ImplicitReceiver, MethodCall, PropertyRead;
3+
import 'constants.dart';
4+
5+
enum HandlerType { simpleNoArgs, simpleOneArg, notSimple }
6+
7+
/// Classifies this event binding by it's form.
8+
///
9+
/// The simple form looks like
10+
///
11+
/// (event)="handler($event)"
12+
///
13+
/// or
14+
///
15+
/// (event)="handler()"
16+
///
17+
/// Since these types of handlers are so common, we can optimize the code
18+
/// generated for them.
19+
HandlerType handlerTypeFromExpression(AST handler) {
20+
var eventHandler = handler;
21+
if (eventHandler is ASTWithSource) {
22+
eventHandler = (eventHandler as ASTWithSource).ast;
23+
}
24+
if (eventHandler is! MethodCall) {
25+
return HandlerType.notSimple;
26+
}
27+
var call = eventHandler as MethodCall;
28+
if (call.receiver is! ImplicitReceiver) {
29+
return HandlerType.notSimple;
30+
}
31+
if (call.args.isEmpty) {
32+
return HandlerType.simpleNoArgs;
33+
}
34+
if (call.args.length != 1) {
35+
return HandlerType.notSimple;
36+
}
37+
var singleArg = call.args.single;
38+
if (singleArg is! PropertyRead) {
39+
return HandlerType.notSimple;
40+
}
41+
var property = singleArg as PropertyRead;
42+
if (property.name == EventHandlerVars.event.name &&
43+
property.receiver is ImplicitReceiver) {
44+
return HandlerType.simpleOneArg;
45+
} else {
46+
return HandlerType.notSimple;
47+
}
48+
}
49+
50+
final RegExp _eventNameRegExp = new RegExp(r'[^a-zA-Z0-9_]');
51+
52+
/// Sanitizes event name so it can be used to construct a class member
53+
/// handler method name.
54+
String sanitizeEventName(String name) {
55+
return name.replaceAll(_eventNameRegExp, '_');
56+
}

lib/src/compiler/view_compiler/view_binder.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ class ViewBinderVisitor implements TemplateAstVisitor {
6363

6464
dynamic visitElement(ElementAst ast, dynamic context) {
6565
var compileElement = (view.nodes[_nodeIndex++] as CompileElement);
66-
var eventListeners =
67-
collectEventListeners(ast.outputs, ast.directives, compileElement);
66+
var eventListeners = collectEventListeners(
67+
ast.outputs, ast.directives, compileElement,
68+
includeComponentOutputs: false);
69+
6870
bindRenderInputs(ast.inputs, compileElement);
6971
bindRenderOutputs(eventListeners);
7072
var index = -1;

lib/src/compiler/view_compiler/view_builder.dart

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import "../template_ast.dart"
2828
DirectiveAst,
2929
BoundDirectivePropertyAst,
3030
templateVisitAll;
31+
import '../expression_parser/parser.dart' show Parser;
3132
import "compile_element.dart" show CompileElement, CompileNode;
3233
import "compile_method.dart";
3334
import "compile_view.dart" show CompileView;
@@ -36,11 +37,15 @@ import "constants.dart"
3637
ChangeDetectionStrategyEnum,
3738
ChangeDetectorStateEnum,
3839
DetectChangesVars,
40+
EventHandlerVars,
3941
InjectMethodVars,
4042
ViewConstructorVars,
4143
ViewEncapsulationEnum,
4244
ViewProperties,
4345
ViewTypeEnum;
46+
import 'expression_converter.dart';
47+
import 'event_binder.dart' show convertStmtIntoExpression;
48+
import 'parse_utils.dart';
4449
import 'property_binder.dart';
4550
import "view_compiler_utils.dart"
4651
show
@@ -69,6 +74,7 @@ class ViewCompileDependency {
6974

7075
class ViewBuilderVisitor implements TemplateAstVisitor {
7176
final CompileView view;
77+
final Parser parser;
7278
final List<ViewCompileDependency> targetDependencies;
7379
final StylesCompileResult stylesCompileResult;
7480
static Map<String, CompileIdentifierMetadata> tagNameToIdentifier;
@@ -79,8 +85,8 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
7985
static final defaultDocVarName = 'doc';
8086
String docVarName;
8187

82-
ViewBuilderVisitor(
83-
this.view, this.targetDependencies, this.stylesCompileResult) {
88+
ViewBuilderVisitor(this.view, this.parser, this.targetDependencies,
89+
this.stylesCompileResult) {
8490
tagNameToIdentifier ??= {
8591
'a': Identifiers.HTML_ANCHOR_ELEMENT,
8692
'area': Identifiers.HTML_AREA_ELEMENT,
@@ -495,7 +501,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
495501

496502
// Create a visitor for embedded view and visit all nodes.
497503
var embeddedViewVisitor = new ViewBuilderVisitor(
498-
embeddedView, targetDependencies, stylesCompileResult);
504+
embeddedView, parser, targetDependencies, stylesCompileResult);
499505
templateVisitAll(
500506
embeddedViewVisitor,
501507
ast.children,
@@ -725,10 +731,11 @@ o.Expression createStaticNodeDebugInfo(CompileNode node) {
725731

726732
/// Generates output ast for a CompileView and returns a [ClassStmt] for the
727733
/// view of embedded template.
728-
o.ClassStmt createViewClass(CompileView view, o.Expression nodeDebugInfosVar) {
734+
o.ClassStmt createViewClass(
735+
CompileView view, o.Expression nodeDebugInfosVar, Parser parser) {
729736
var viewConstructor = _createViewClassConstructor(view, nodeDebugInfosVar);
730737
var viewMethods = (new List.from([
731-
new o.ClassMethod("build", [], generateCreateMethod(view),
738+
new o.ClassMethod("build", [], generateCreateMethod(view, parser),
732739
o.importType(Identifiers.ComponentRef, null)),
733740
new o.ClassMethod(
734741
"injectorGetInternal",
@@ -922,7 +929,7 @@ o.Statement createViewFactory(CompileView view, o.ClassStmt viewClass) {
922929
.toDeclStmt(view.viewFactory.name, [o.StmtModifier.Final]);
923930
}
924931

925-
List<o.Statement> generateCreateMethod(CompileView view) {
932+
List<o.Statement> generateCreateMethod(CompileView view, Parser parser) {
926933
o.Expression parentRenderNodeExpr = o.NULL_EXPR;
927934
var parentRenderNodeStmts = <o.Statement>[];
928935
bool isComponent = view.viewType == ViewType.COMPONENT;
@@ -954,8 +961,13 @@ List<o.Statement> generateCreateMethod(CompileView view) {
954961
o.literalArr(view.subscriptions)
955962
]).toStmt());
956963

957-
if (isComponent &&
958-
view.viewIndex == 0 &&
964+
bool isComponentRoot = isComponent && view.viewIndex == 0;
965+
966+
if (isComponentRoot) {
967+
_writeComponentHostEventListeners(view, parser, statements);
968+
}
969+
970+
if (isComponentRoot &&
959971
view.component.changeDetection == ChangeDetectionStrategy.Stateful) {
960972
// Connect ComponentState callback to view.
961973
statements.add((new o.ReadClassMemberExpr('ctx')
@@ -980,6 +992,56 @@ List<o.Statement> generateCreateMethod(CompileView view) {
980992
return statements;
981993
}
982994

995+
/// Writes shared event handler wiring for events that are directly defined
996+
/// on host property of @Component annotation.
997+
void _writeComponentHostEventListeners(
998+
CompileView view, Parser parser, List<o.Statement> statements) {
999+
CompileDirectiveMetadata component = view.component;
1000+
for (String eventName in component.hostListeners.keys) {
1001+
String handlerSource = component.hostListeners[eventName];
1002+
var handlerAst = parser.parseAction(handlerSource, '');
1003+
HandlerType handlerType = handlerTypeFromExpression(handlerAst);
1004+
1005+
var context = new o.ReadClassMemberExpr('ctx');
1006+
var actionExpr = convertStmtIntoExpression(
1007+
convertCdStatementToIr(view, context, handlerAst, false).last);
1008+
if (handlerType == HandlerType.notSimple) {
1009+
List<o.Statement> stmts = <o.Statement>[
1010+
new o.InvokeMemberMethodExpr('markPathToRootAsCheckOnce', []).toStmt(),
1011+
new o.ReturnStatement(actionExpr)
1012+
];
1013+
String methodName = '_handle_${sanitizeEventName(eventName)}__';
1014+
view.eventHandlerMethods.add(new o.ClassMethod(
1015+
methodName,
1016+
[new o.FnParam(EventHandlerVars.event.name, o.importType(null))],
1017+
stmts,
1018+
o.BOOL_TYPE,
1019+
[o.StmtModifier.Private]));
1020+
1021+
o.Expression handlerExpr = new o.InvokeMemberMethodExpr(
1022+
'evt', [new o.ReadClassMemberExpr(methodName)]);
1023+
o.Expression listenExpr = new o.InvokeMemberMethodExpr('listen', [
1024+
new o.ReadClassMemberExpr(appViewRootElementName),
1025+
o.literal(eventName),
1026+
handlerExpr
1027+
]);
1028+
statements.add(listenExpr.toStmt());
1029+
} else {
1030+
assert(actionExpr is o.InvokeMethodExpr);
1031+
var callExpr = actionExpr as o.InvokeMethodExpr;
1032+
var eventListener = new o.InvokeMemberMethodExpr(
1033+
'eventHandler${handlerType == HandlerType.simpleNoArgs ? 0 : 1}',
1034+
[new o.ReadPropExpr(callExpr.receiver, callExpr.name)]);
1035+
o.Expression listenExpr = new o.InvokeMemberMethodExpr('listen', [
1036+
new o.ReadClassMemberExpr(appViewRootElementName),
1037+
o.literal(eventName),
1038+
eventListener
1039+
]);
1040+
statements.add(listenExpr.toStmt());
1041+
}
1042+
}
1043+
}
1044+
9831045
List<o.Statement> generateDetectChangesMethod(CompileView view) {
9841046
var stmts = <o.Statement>[];
9851047
if (view.detectChangesInInputsMethod.isEmpty &&

0 commit comments

Comments
 (0)