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

perf(compiler): +6% Pre-compute ViewFactories, styles for components. #1134

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 8 additions & 24 deletions lib/core_dom/element_binder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ class TemplateElementBinder extends ElementBinder {
return _directiveCache = [template];
}

TemplateElementBinder(perf, expando, parser, config, componentFactory,
transcludingComponentFactory, shadowDomComponentFactory,
TemplateElementBinder(perf, expando, parser, config,
this.template, this.templateBinder,
onEvents, bindAttrs, childMode)
: super(perf, expando, parser, config, componentFactory,
transcludingComponentFactory, shadowDomComponentFactory,
: super(perf, expando, parser, config,
null, null, onEvents, bindAttrs, childMode);

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

// The default component factory
final ComponentFactory _componentFactory;
final TranscludingComponentFactory _transcludingComponentFactory;
final ShadowDomComponentFactory _shadowDomComponentFactory;
final Map onEvents;
final Map bindAttrs;

// Member fields
final decorators;

final DirectiveRef component;
final BoundComponentData componentData;

// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
final String childMode;

ElementBinder(this._perf, this._expando, this._parser, this._config,
this._componentFactory,
this._transcludingComponentFactory,
this._shadowDomComponentFactory,
this.component, this.decorators,
this.componentData, this.decorators,
this.onEvents, this.bindAttrs, this.childMode);

final bool hasTemplate = false;
Expand All @@ -77,7 +68,7 @@ class ElementBinder {
var _directiveCache;
List<DirectiveRef> get _usableDirectiveRefs {
if (_directiveCache != null) return _directiveCache;
if (component != null) return _directiveCache = new List.from(decorators)..add(component);
if (componentData != null) return _directiveCache = new List.from(decorators)..add(componentData.ref);
return _directiveCache = decorators;
}

Expand Down Expand Up @@ -260,16 +251,9 @@ class ElementBinder {
}
nodesAttrsDirectives.add(ref);
} else if (ref.annotation is Component) {
var factory;
var annotation = ref.annotation as Component;
if (annotation.useShadowDom == true) {
factory = _shadowDomComponentFactory;
} else if (annotation.useShadowDom == false) {
factory = _transcludingComponentFactory;
} else {
factory = _componentFactory;
}
nodeModule.bindByKey(ref.typeKey, toFactory: factory.call(node, ref), visibility: visibility);
assert(ref == componentData.ref);

nodeModule.bindByKey(ref.typeKey, toFactory: componentData.factory.call(node), visibility: visibility);
} else {
nodeModule.bindByKey(ref.typeKey, visibility: visibility);
}
Expand Down
79 changes: 56 additions & 23 deletions lib/core_dom/element_binder_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,25 @@ class ElementBinderFactory {
final Profiler _perf;
final CompilerConfig _config;
final Expando _expando;
final ComponentFactory _componentFactory;
final TranscludingComponentFactory _transcludingComponentFactory;
final ShadowDomComponentFactory _shadowDomComponentFactory;
final ASTParser _astParser;
final ASTParser astParser;
final ComponentFactory componentFactory;
final ShadowDomComponentFactory shadowDomComponentFactory;
final TranscludingComponentFactory transcludingComponentFactory;

ElementBinderFactory(this._parser, this._perf, this._config, this._expando,
this._componentFactory,
this._transcludingComponentFactory,
this._shadowDomComponentFactory,
this._astParser);
this.astParser, this.componentFactory, this.shadowDomComponentFactory, this.transcludingComponentFactory);

// TODO: Optimize this to re-use a builder.
ElementBinderBuilder builder(FormatterMap formatters) =>
new ElementBinderBuilder(this, _astParser, formatters);
ElementBinderBuilder builder(FormatterMap formatters, DirectiveMap directives) =>
new ElementBinderBuilder(this,formatters, directives);

ElementBinder binder(ElementBinderBuilder b) =>
new ElementBinder(_perf, _expando, _parser, _config, _componentFactory,
_transcludingComponentFactory, _shadowDomComponentFactory,
b.component, b.decorators, b.onEvents, b.bindAttrs, b.childMode);

new ElementBinder(_perf, _expando, _parser, _config,
b.componentData, b.decorators, b.onEvents, b.bindAttrs, b.childMode);

TemplateElementBinder templateBinder(ElementBinderBuilder b, ElementBinder transclude) =>
new TemplateElementBinder(_perf, _expando, _parser, _config, _componentFactory,
_transcludingComponentFactory, _shadowDomComponentFactory,
new TemplateElementBinder(_perf, _expando, _parser, _config,
b.template, transclude, b.onEvents, b.bindAttrs, b.childMode);
}

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

ElementBinderFactory _factory;
ASTParser _astParser;
FormatterMap _formatters;
final ElementBinderFactory _factory;
final DirectiveMap _directives;
final FormatterMap _formatters;

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

final decorators = <DirectiveRef>[];
DirectiveRef template;
DirectiveRef component;
BoundComponentData componentData;

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

ElementBinderBuilder(this._factory, this._astParser, this._formatters);
ElementBinderBuilder(this._factory, this._formatters, this._directives);

/**
* Adds [DirectiveRef]s to this [ElementBinderBuilder].
Expand All @@ -73,7 +69,17 @@ class ElementBinderBuilder {
if (annotation.children == Directive.TRANSCLUDE_CHILDREN) {
template = ref;
} else if (annotation is Component) {
component = ref;
ComponentFactory factory;
var annotation = ref.annotation as Component;
if (annotation.useShadowDom == true) {
factory = _factory.shadowDomComponentFactory;
} else if (annotation.useShadowDom == false) {
factory = _factory.transcludingComponentFactory;
} else {
factory = _factory.componentFactory;
}

componentData = new BoundComponentData(ref, () => factory.bind(ref, _directives));
} else {
decorators.add(ref);
}
Expand All @@ -92,14 +98,14 @@ class ElementBinderBuilder {
var dstPath = match[2];

String dstExpression = dstPath.isEmpty ? attrName : dstPath;
AST dstAST = _astParser(dstExpression); // no formatters
AST dstAST = _factory.astParser(dstExpression); // no formatters

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

ref.mappings.add(new MappingParts(attrName, ast, mode, dstAST, mapping));
Expand All @@ -113,3 +119,30 @@ class ElementBinderBuilder {
return template == null ? elBinder : _factory.templateBinder(this, elBinder);
}
}

/**
* Data used by the ComponentFactory to construct components.
*/
class BoundComponentData {
final DirectiveRef ref;
BoundComponentFactory _instance;
Function _gen;
BoundComponentFactory get factory {
if (_instance != null) return _instance;
_instance = _gen();
_gen = null; // Clear the gen function for GC.
return _instance;
}

Component get component => ref.annotation as Component;
@Deprecated('Use typeKey instead')
Type get type => ref.type;
Key get typeKey => ref.typeKey;


/**
* * [ref]: The components directive ref
* * [_gen]: A function which returns a [BoundComponentFactory]. Called lazily.
*/
BoundComponentData(this.ref, this._gen);
}
6 changes: 3 additions & 3 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class DirectiveSelector {
ElementBinder matchElement(dom.Node node) {
assert(node is dom.Element);

ElementBinderBuilder builder = _binderFactory.builder(_formatters);
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);
List<_ElementSelector> partialSelection;
final classes = new Set<String>();
final attrs = <String, String>{};
Expand Down Expand Up @@ -129,7 +129,7 @@ class DirectiveSelector {
}

ElementBinder matchText(dom.Node node) {
ElementBinderBuilder builder = _binderFactory.builder(_formatters);
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);

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

ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null).binder;
ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null, null).binder;
}

/**
Expand Down
Loading