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

Commit

Permalink
perf(compiler): +6% Pre-compute ViewFactories, styles for components.
Browse files Browse the repository at this point in the history
This sped up the TreeComponent benchmark by 6%.

Closes #1134
  • Loading branch information
jbdeboer authored and [email protected] committed Jun 11, 2014
1 parent 2114b19 commit be3cdd4
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 240 deletions.
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

0 comments on commit be3cdd4

Please sign in to comment.