Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit be3cdd4

Browse files
jbdeboertravis@travis-ci.org
authored and
travis@travis-ci.org
committed
perf(compiler): +6% Pre-compute ViewFactories, styles for components.
This sped up the TreeComponent benchmark by 6%. Closes #1134
1 parent 2114b19 commit be3cdd4

8 files changed

+272
-240
lines changed

lib/core_dom/element_binder.dart

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ class TemplateElementBinder extends ElementBinder {
1414
return _directiveCache = [template];
1515
}
1616

17-
TemplateElementBinder(perf, expando, parser, config, componentFactory,
18-
transcludingComponentFactory, shadowDomComponentFactory,
17+
TemplateElementBinder(perf, expando, parser, config,
1918
this.template, this.templateBinder,
2019
onEvents, bindAttrs, childMode)
21-
: super(perf, expando, parser, config, componentFactory,
22-
transcludingComponentFactory, shadowDomComponentFactory,
20+
: super(perf, expando, parser, config,
2321
null, null, onEvents, bindAttrs, childMode);
2422

2523
String toString() => "[TemplateElementBinder template:$template]";
@@ -47,26 +45,19 @@ class ElementBinder {
4745
final Parser _parser;
4846
final CompilerConfig _config;
4947

50-
// The default component factory
51-
final ComponentFactory _componentFactory;
52-
final TranscludingComponentFactory _transcludingComponentFactory;
53-
final ShadowDomComponentFactory _shadowDomComponentFactory;
5448
final Map onEvents;
5549
final Map bindAttrs;
5650

5751
// Member fields
5852
final decorators;
5953

60-
final DirectiveRef component;
54+
final BoundComponentData componentData;
6155

6256
// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
6357
final String childMode;
6458

6559
ElementBinder(this._perf, this._expando, this._parser, this._config,
66-
this._componentFactory,
67-
this._transcludingComponentFactory,
68-
this._shadowDomComponentFactory,
69-
this.component, this.decorators,
60+
this.componentData, this.decorators,
7061
this.onEvents, this.bindAttrs, this.childMode);
7162

7263
final bool hasTemplate = false;
@@ -77,7 +68,7 @@ class ElementBinder {
7768
var _directiveCache;
7869
List<DirectiveRef> get _usableDirectiveRefs {
7970
if (_directiveCache != null) return _directiveCache;
80-
if (component != null) return _directiveCache = new List.from(decorators)..add(component);
71+
if (componentData != null) return _directiveCache = new List.from(decorators)..add(componentData.ref);
8172
return _directiveCache = decorators;
8273
}
8374

@@ -260,16 +251,9 @@ class ElementBinder {
260251
}
261252
nodesAttrsDirectives.add(ref);
262253
} else if (ref.annotation is Component) {
263-
var factory;
264-
var annotation = ref.annotation as Component;
265-
if (annotation.useShadowDom == true) {
266-
factory = _shadowDomComponentFactory;
267-
} else if (annotation.useShadowDom == false) {
268-
factory = _transcludingComponentFactory;
269-
} else {
270-
factory = _componentFactory;
271-
}
272-
nodeModule.bindByKey(ref.typeKey, toFactory: factory.call(node, ref), visibility: visibility);
254+
assert(ref == componentData.ref);
255+
256+
nodeModule.bindByKey(ref.typeKey, toFactory: componentData.factory.call(node), visibility: visibility);
273257
} else {
274258
nodeModule.bindByKey(ref.typeKey, visibility: visibility);
275259
}

lib/core_dom/element_binder_builder.dart

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,25 @@ class ElementBinderFactory {
66
final Profiler _perf;
77
final CompilerConfig _config;
88
final Expando _expando;
9-
final ComponentFactory _componentFactory;
10-
final TranscludingComponentFactory _transcludingComponentFactory;
11-
final ShadowDomComponentFactory _shadowDomComponentFactory;
12-
final ASTParser _astParser;
9+
final ASTParser astParser;
10+
final ComponentFactory componentFactory;
11+
final ShadowDomComponentFactory shadowDomComponentFactory;
12+
final TranscludingComponentFactory transcludingComponentFactory;
1313

1414
ElementBinderFactory(this._parser, this._perf, this._config, this._expando,
15-
this._componentFactory,
16-
this._transcludingComponentFactory,
17-
this._shadowDomComponentFactory,
18-
this._astParser);
15+
this.astParser, this.componentFactory, this.shadowDomComponentFactory, this.transcludingComponentFactory);
1916

2017
// TODO: Optimize this to re-use a builder.
21-
ElementBinderBuilder builder(FormatterMap formatters) =>
22-
new ElementBinderBuilder(this, _astParser, formatters);
18+
ElementBinderBuilder builder(FormatterMap formatters, DirectiveMap directives) =>
19+
new ElementBinderBuilder(this,formatters, directives);
2320

2421
ElementBinder binder(ElementBinderBuilder b) =>
25-
new ElementBinder(_perf, _expando, _parser, _config, _componentFactory,
26-
_transcludingComponentFactory, _shadowDomComponentFactory,
27-
b.component, b.decorators, b.onEvents, b.bindAttrs, b.childMode);
22+
23+
new ElementBinder(_perf, _expando, _parser, _config,
24+
b.componentData, b.decorators, b.onEvents, b.bindAttrs, b.childMode);
2825

2926
TemplateElementBinder templateBinder(ElementBinderBuilder b, ElementBinder transclude) =>
30-
new TemplateElementBinder(_perf, _expando, _parser, _config, _componentFactory,
31-
_transcludingComponentFactory, _shadowDomComponentFactory,
27+
new TemplateElementBinder(_perf, _expando, _parser, _config,
3228
b.template, transclude, b.onEvents, b.bindAttrs, b.childMode);
3329
}
3430

@@ -39,9 +35,9 @@ class ElementBinderFactory {
3935
class ElementBinderBuilder {
4036
static final RegExp _MAPPING = new RegExp(r'^(@|=>!|=>|<=>|&)\s*(.*)$');
4137

42-
ElementBinderFactory _factory;
43-
ASTParser _astParser;
44-
FormatterMap _formatters;
38+
final ElementBinderFactory _factory;
39+
final DirectiveMap _directives;
40+
final FormatterMap _formatters;
4541

4642
/// "on-*" attribute names and values, added by a [DirectiveSelector]
4743
final onEvents = <String, String>{};
@@ -50,12 +46,12 @@ class ElementBinderBuilder {
5046

5147
final decorators = <DirectiveRef>[];
5248
DirectiveRef template;
53-
DirectiveRef component;
49+
BoundComponentData componentData;
5450

5551
// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
5652
String childMode = Directive.COMPILE_CHILDREN;
5753

58-
ElementBinderBuilder(this._factory, this._astParser, this._formatters);
54+
ElementBinderBuilder(this._factory, this._formatters, this._directives);
5955

6056
/**
6157
* Adds [DirectiveRef]s to this [ElementBinderBuilder].
@@ -73,7 +69,17 @@ class ElementBinderBuilder {
7369
if (annotation.children == Directive.TRANSCLUDE_CHILDREN) {
7470
template = ref;
7571
} else if (annotation is Component) {
76-
component = ref;
72+
ComponentFactory factory;
73+
var annotation = ref.annotation as Component;
74+
if (annotation.useShadowDom == true) {
75+
factory = _factory.shadowDomComponentFactory;
76+
} else if (annotation.useShadowDom == false) {
77+
factory = _factory.transcludingComponentFactory;
78+
} else {
79+
factory = _factory.componentFactory;
80+
}
81+
82+
componentData = new BoundComponentData(ref, () => factory.bind(ref, _directives));
7783
} else {
7884
decorators.add(ref);
7985
}
@@ -92,14 +98,14 @@ class ElementBinderBuilder {
9298
var dstPath = match[2];
9399

94100
String dstExpression = dstPath.isEmpty ? attrName : dstPath;
95-
AST dstAST = _astParser(dstExpression); // no formatters
101+
AST dstAST = _factory.astParser(dstExpression); // no formatters
96102

97103
// Look up the value of attrName and compute an AST
98104
AST ast;
99105
if (mode != '@' && mode != '&') {
100106
var value = attrName == "." ? ref.value : (ref.element as dom.Element).attributes[attrName];
101107
if (value == null || value.isEmpty) { value = "''"; }
102-
ast = _astParser(value, formatters: _formatters);
108+
ast = _factory.astParser(value, formatters: _formatters);
103109
}
104110

105111
ref.mappings.add(new MappingParts(attrName, ast, mode, dstAST, mapping));
@@ -113,3 +119,30 @@ class ElementBinderBuilder {
113119
return template == null ? elBinder : _factory.templateBinder(this, elBinder);
114120
}
115121
}
122+
123+
/**
124+
* Data used by the ComponentFactory to construct components.
125+
*/
126+
class BoundComponentData {
127+
final DirectiveRef ref;
128+
BoundComponentFactory _instance;
129+
Function _gen;
130+
BoundComponentFactory get factory {
131+
if (_instance != null) return _instance;
132+
_instance = _gen();
133+
_gen = null; // Clear the gen function for GC.
134+
return _instance;
135+
}
136+
137+
Component get component => ref.annotation as Component;
138+
@Deprecated('Use typeKey instead')
139+
Type get type => ref.type;
140+
Key get typeKey => ref.typeKey;
141+
142+
143+
/**
144+
* * [ref]: The components directive ref
145+
* * [_gen]: A function which returns a [BoundComponentFactory]. Called lazily.
146+
*/
147+
BoundComponentData(this.ref, this._gen);
148+
}

lib/core_dom/selector.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class DirectiveSelector {
5959
ElementBinder matchElement(dom.Node node) {
6060
assert(node is dom.Element);
6161

62-
ElementBinderBuilder builder = _binderFactory.builder(_formatters);
62+
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);
6363
List<_ElementSelector> partialSelection;
6464
final classes = new Set<String>();
6565
final attrs = <String, String>{};
@@ -129,7 +129,7 @@ class DirectiveSelector {
129129
}
130130

131131
ElementBinder matchText(dom.Node node) {
132-
ElementBinderBuilder builder = _binderFactory.builder(_formatters);
132+
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);
133133

134134
var value = node.nodeValue;
135135
for (var k = 0; k < textSelector.length; k++) {
@@ -148,7 +148,7 @@ class DirectiveSelector {
148148
return builder.binder;
149149
}
150150

151-
ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null).binder;
151+
ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null, null).binder;
152152
}
153153

154154
/**

0 commit comments

Comments
 (0)