perf(compiler): Avoid unnecessary List concats

Update `BindingRecordsCreator#getBindingRecords` and `ProtoRecordBuilder#addAst`
to avoid unnecessary calls to `ListWrapper.concat`.

Closes #1905
This commit is contained in:
Tim Blasi
2015-05-14 10:26:19 -07:00
committed by Misko Hevery
parent 534cbb4bf5
commit 05a1c6c183
2 changed files with 49 additions and 54 deletions

View File

@ -1,4 +1,4 @@
import {isPresent, isBlank, BaseException, Type, isString} from 'angular2/src/facade/lang'; import {BaseException, Type, isBlank, isPresent, isString} from 'angular2/src/facade/lang';
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import { import {
@ -109,37 +109,30 @@ class ProtoRecordBuilder {
constructor() { this.records = []; } constructor() { this.records = []; }
addAst(b: BindingRecord, variableNames: List < string >= null) { addAst(b: BindingRecord, variableNames: List < string >= null) {
var last = ListWrapper.last(this.records); var oldLast = ListWrapper.last(this.records);
if (isPresent(last) && last.bindingRecord.directiveRecord == b.directiveRecord) { if (isPresent(oldLast) && oldLast.bindingRecord.directiveRecord == b.directiveRecord) {
last.lastInDirective = false; oldLast.lastInDirective = false;
} }
var pr = _ConvertAstIntoProtoRecords.convert(b, this.records.length, variableNames); _ConvertAstIntoProtoRecords.append(this.records, b, variableNames);
if (!ListWrapper.isEmpty(pr)) { var newLast = ListWrapper.last(this.records);
var last = ListWrapper.last(pr); if (isPresent(newLast) && newLast !== oldLast) {
last.lastInBinding = true; newLast.lastInBinding = true;
last.lastInDirective = true; newLast.lastInDirective = true;
this.records = ListWrapper.concat(this.records, pr);
} }
} }
} }
class _ConvertAstIntoProtoRecords { class _ConvertAstIntoProtoRecords {
protoRecords: List<any>; constructor(private _records: List<ProtoRecord>, private _bindingRecord: BindingRecord,
private _expressionAsString: string, private _variableNames: List<any>) {}
constructor(private bindingRecord: BindingRecord, private contextIndex: number, static append(records: List<ProtoRecord>, b: BindingRecord, variableNames: List<any>) {
private expressionAsString: string, private variableNames: List<any>) { var c = new _ConvertAstIntoProtoRecords(records, b, b.ast.toString(), variableNames);
this.protoRecords = [];
}
static convert(b: BindingRecord, contextIndex: number, variableNames: List<any>) {
var c = new _ConvertAstIntoProtoRecords(b, contextIndex, b.ast.toString(), variableNames);
b.ast.visit(c); b.ast.visit(c);
return c.protoRecords;
} }
visitImplicitReceiver(ast: ImplicitReceiver) { return this.bindingRecord.implicitReceiver; } visitImplicitReceiver(ast: ImplicitReceiver) { return this._bindingRecord.implicitReceiver; }
visitInterpolation(ast: Interpolation) { visitInterpolation(ast: Interpolation) {
var args = this._visitAll(ast.expressions); var args = this._visitAll(ast.expressions);
@ -153,7 +146,7 @@ class _ConvertAstIntoProtoRecords {
visitAccessMember(ast: AccessMember) { visitAccessMember(ast: AccessMember) {
var receiver = ast.receiver.visit(this); var receiver = ast.receiver.visit(this);
if (isPresent(this.variableNames) && ListWrapper.contains(this.variableNames, ast.name) && if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name) &&
ast.receiver instanceof ast.receiver instanceof
ImplicitReceiver) { ImplicitReceiver) {
return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver);
@ -163,10 +156,9 @@ class _ConvertAstIntoProtoRecords {
} }
visitMethodCall(ast: MethodCall) { visitMethodCall(ast: MethodCall) {
;
var receiver = ast.receiver.visit(this); var receiver = ast.receiver.visit(this);
var args = this._visitAll(ast.args); var args = this._visitAll(ast.args);
if (isPresent(this.variableNames) && ListWrapper.contains(this.variableNames, ast.name)) { if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name)) {
var target = this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); var target = this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver);
return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target); return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target);
} else { } else {
@ -236,17 +228,15 @@ class _ConvertAstIntoProtoRecords {
} }
_addRecord(type, name, funcOrValue, args, fixedArgs, context) { _addRecord(type, name, funcOrValue, args, fixedArgs, context) {
var selfIndex = ++this.contextIndex; var selfIndex = this._records.length + 1;
if (context instanceof DirectiveIndex) { if (context instanceof DirectiveIndex) {
ListWrapper.push( ListWrapper.push(this._records, new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1,
this.protoRecords, context, selfIndex, this._bindingRecord,
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context, selfIndex, this._expressionAsString, false, false));
this.bindingRecord, this.expressionAsString, false, false));
} else { } else {
ListWrapper.push( ListWrapper.push(this._records, new ProtoRecord(type, name, funcOrValue, args, fixedArgs,
this.protoRecords, context, null, selfIndex, this._bindingRecord,
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null, selfIndex, this._expressionAsString, false, false));
this.bindingRecord, this.expressionAsString, false, false));
} }
return selfIndex; return selfIndex;
} }

View File

@ -29,10 +29,10 @@ class BindingRecordsCreator {
for (var boundElementIndex = 0; boundElementIndex < elementBinders.length; boundElementIndex++) { for (var boundElementIndex = 0; boundElementIndex < elementBinders.length; boundElementIndex++) {
var renderElementBinder = elementBinders[boundElementIndex]; var renderElementBinder = elementBinders[boundElementIndex];
bindings = ListWrapper.concat(bindings, this._createTextNodeRecords(renderElementBinder)); this._createTextNodeRecords(bindings, renderElementBinder);
bindings = ListWrapper.concat(bindings, this._createElementPropertyRecords(boundElementIndex, renderElementBinder)); this._createElementPropertyRecords(bindings, boundElementIndex, renderElementBinder);
bindings = ListWrapper.concat(bindings, this._createDirectiveRecords(boundElementIndex, this._createDirectiveRecords(bindings, boundElementIndex,
renderElementBinder.directives, allDirectiveMetadatas)); renderElementBinder.directives, allDirectiveMetadatas);
} }
return bindings; return bindings;
@ -46,29 +46,35 @@ class BindingRecordsCreator {
for (var elementIndex = 0; elementIndex < elementBinders.length; ++elementIndex) { for (var elementIndex = 0; elementIndex < elementBinders.length; ++elementIndex) {
var dirs = elementBinders[elementIndex].directives; var dirs = elementBinders[elementIndex].directives;
for (var dirIndex = 0; dirIndex < dirs.length; ++dirIndex) { for (var dirIndex = 0; dirIndex < dirs.length; ++dirIndex) {
ListWrapper.push(directiveRecords, this._getDirectiveRecord(elementIndex, dirIndex, allDirectiveMetadatas[dirs[dirIndex].directiveIndex])); ListWrapper.push(directiveRecords,
this._getDirectiveRecord(
elementIndex, dirIndex, allDirectiveMetadatas[dirs[dirIndex].directiveIndex]));
} }
} }
return directiveRecords; return directiveRecords;
} }
_createTextNodeRecords(renderElementBinder:renderApi.ElementBinder) { _createTextNodeRecords(bindings: List<BindingRecord>,
if (isBlank(renderElementBinder.textBindings)) return []; renderElementBinder: renderApi.ElementBinder) {
return ListWrapper.map(renderElementBinder.textBindings, b => BindingRecord.createForTextNode(b, this._textNodeIndex++)); if (isBlank(renderElementBinder.textBindings)) return;
}
_createElementPropertyRecords(boundElementIndex:number, renderElementBinder:renderApi.ElementBinder) { ListWrapper.forEach(renderElementBinder.textBindings, (b) => {
var res = []; ListWrapper.push(bindings, BindingRecord.createForTextNode(b, this._textNodeIndex++));
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
ListWrapper.push(res, BindingRecord.createForElement(astWithSource, boundElementIndex, propertyName));
}); });
return res;
} }
_createDirectiveRecords(boundElementIndex:number, directiveBinders:List<renderApi.DirectiveBinder>, _createElementPropertyRecords(bindings: List<BindingRecord>,
boundElementIndex:number, renderElementBinder:renderApi.ElementBinder) {
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
ListWrapper.push(bindings,
BindingRecord.createForElement(astWithSource, boundElementIndex, propertyName));
});
}
_createDirectiveRecords(bindings: List<BindingRecord>,
boundElementIndex:number, directiveBinders:List<renderApi.DirectiveBinder>,
allDirectiveMetadatas:List<renderApi.DirectiveMetadata>) { allDirectiveMetadatas:List<renderApi.DirectiveMetadata>) {
var res = [];
for (var i = 0; i < directiveBinders.length; i++) { for (var i = 0; i < directiveBinders.length; i++) {
var directiveBinder = directiveBinders[i]; var directiveBinder = directiveBinders[i];
var directiveMetadata = allDirectiveMetadatas[directiveBinder.directiveIndex]; var directiveMetadata = allDirectiveMetadatas[directiveBinder.directiveIndex];
@ -79,18 +85,17 @@ class BindingRecordsCreator {
// it monomorphic! // it monomorphic!
var setter = reflector.setter(propertyName); var setter = reflector.setter(propertyName);
var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, directiveMetadata); var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, directiveMetadata);
var b = BindingRecord.createForDirective(astWithSource, propertyName, setter, directiveRecord); ListWrapper.push(bindings,
ListWrapper.push(res, b); BindingRecord.createForDirective(astWithSource, propertyName, setter, directiveRecord));
}); });
// host properties // host properties
MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => { MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => {
var dirIndex = new DirectiveIndex(boundElementIndex, i); var dirIndex = new DirectiveIndex(boundElementIndex, i);
var b = BindingRecord.createForHostProperty(dirIndex, astWithSource, propertyName); ListWrapper.push(bindings,
ListWrapper.push(res, b); BindingRecord.createForHostProperty(dirIndex, astWithSource, propertyName));
}); });
} }
return res;
} }
_getDirectiveRecord(boundElementIndex:number, directiveIndex:number, directiveMetadata:renderApi.DirectiveMetadata): DirectiveRecord { _getDirectiveRecord(boundElementIndex:number, directiveIndex:number, directiveMetadata:renderApi.DirectiveMetadata): DirectiveRecord {