perf($parse): improve performance of assignment expressions

There was a ~5% improvement in the added `parsed-expressions-bp/assignment` benchmark (which only
contains assignment expressions). In real-world applications, the time spent in assignment
expressions will be a tiny fragment of the overall processing time, though.

Closes #14957
This commit is contained in:
Georgios Kalpakas
2016-07-27 19:35:48 +03:00
parent 49f077736d
commit e8d7496b62
3 changed files with 57 additions and 35 deletions
+9 -10
View File
@@ -23,7 +23,6 @@ app.directive('bmPeWatch', function() {
return function($scope, $element, $attrs) {
$scope.$watch($attrs.bmPeWatch, function(val) {
$element.text(val);
});
};
}
@@ -55,19 +54,19 @@ app.controller('DataController', function($scope, $rootScope) {
var star = '*';
$scope.func = function() { return star;};
$scope.func = function() { return star; };
for (var i = 0; i < totalRows; i++) {
data.push({
index: i,
odd: i % 2 === 0,
even: i % 2 === 1,
str0: "foo-" + Math.random() * Date.now(),
str1: "bar-" + Math.random() * Date.now(),
str2: "baz-" + Math.random() * Date.now(),
num0: Math.random() * Date.now(),
num1: Math.random() * Date.now(),
num2: Math.random() * Date.now(),
odd: i % 2 === 0,
even: i % 2 === 1,
str0: 'foo-' + Math.random() * Date.now(),
str1: 'bar-' + Math.random() * Date.now(),
str2: 'baz-' + Math.random() * Date.now(),
num0: Math.random() * Date.now(),
num1: Math.random() * Date.now(),
num2: Math.random() * Date.now(),
date0: new Date(Math.random() * Date.now()),
date1: new Date(Math.random() * Date.now()),
date2: new Date(Math.random() * Date.now()),
@@ -52,6 +52,11 @@
<label for="functionCalls">Function calls</label>
</li>
<li>
<input type="radio" ng-model="expressionType" value="assignment" id="assignment">
<label for="assignment">Assignment</label>
</li>
<li>
<input type="radio" ng-model="expressionType" value="objectLiterals" id="objectLiterals">
<label for="objectLiterals">Object Literals</label>
@@ -197,6 +202,18 @@
<span bm-pe-watch="row.func(row.func(), row.func())"></span>
</li>
<li ng-switch-when="assignment" ng-repeat="(rowIdx, row) in ::data">
<span bm-pe-watch="row.foo = row.str0"></span>
<span bm-pe-watch="row.obj.foo = row.str1"></span>
<span bm-pe-watch="row.obj.obj.foo = row.str2"></span>
<span bm-pe-watch="row['bar'] = row.num0"></span>
<span bm-pe-watch="row.obj['bar'] = row.num1"></span>
<span bm-pe-watch="row.obj.obj['bar'] = row.num2"></span>
<span bm-pe-watch="row[0] = row.date0"></span>
<span bm-pe-watch="row.obj[0] = row.date1"></span>
<span bm-pe-watch="row.obj.obj[0] = row.date2"></span>
</li>
<li ng-switch-when="objectLiterals" ng-repeat="(rowIdx, row) in ::data">
<span bm-pe-watch-literal="{foo: rowIdx}"></span>
<span bm-pe-watch-literal="{foo: row, bar: rowIdx}"></span>
+31 -25
View File
@@ -13,6 +13,25 @@
var $parseMinErr = minErr('$parse');
var ARRAY_CTOR = [].constructor;
var BOOLEAN_CTOR = (false).constructor;
var FUNCTION_CTOR = Function.constructor;
var NUMBER_CTOR = (0).constructor;
var OBJECT_CTOR = {}.constructor;
var STRING_CTOR = ''.constructor;
var ARRAY_CTOR_PROTO = ARRAY_CTOR.prototype;
var BOOLEAN_CTOR_PROTO = BOOLEAN_CTOR.prototype;
var FUNCTION_CTOR_PROTO = FUNCTION_CTOR.prototype;
var NUMBER_CTOR_PROTO = NUMBER_CTOR.prototype;
var OBJECT_CTOR_PROTO = OBJECT_CTOR.prototype;
var STRING_CTOR_PROTO = STRING_CTOR.prototype;
var CALL = FUNCTION_CTOR_PROTO.call;
var APPLY = FUNCTION_CTOR_PROTO.apply;
var BIND = FUNCTION_CTOR_PROTO.bind;
var objectValueOf = OBJECT_CTOR_PROTO.valueOf;
// Sandboxing Angular Expressions
// ------------------------------
// Angular expressions are generally considered safe because these expressions only have direct
@@ -93,10 +112,6 @@ function ensureSafeObject(obj, fullExpression) {
return obj;
}
var CALL = Function.prototype.call;
var APPLY = Function.prototype.apply;
var BIND = Function.prototype.bind;
function ensureSafeFunction(obj, fullExpression) {
if (obj) {
if (obj.constructor === obj) {
@@ -113,25 +128,18 @@ function ensureSafeFunction(obj, fullExpression) {
function ensureSafeAssignContext(obj, fullExpression) {
if (obj) {
var booleanConstructor = (false).constructor;
var numberConstructor = (0).constructor;
var stringConstructor = ''.constructor;
var objectConstructor = {}.constructor;
var arrayConstructor = [].constructor;
var functionConstructor = Function.constructor;
if (obj === booleanConstructor ||
obj === numberConstructor ||
obj === stringConstructor ||
obj === objectConstructor ||
obj === arrayConstructor ||
obj === functionConstructor ||
obj === booleanConstructor.prototype ||
obj === numberConstructor.prototype ||
obj === stringConstructor.prototype ||
obj === objectConstructor.prototype ||
obj === arrayConstructor.prototype ||
obj === functionConstructor.prototype) {
if (obj === ARRAY_CTOR ||
obj === BOOLEAN_CTOR ||
obj === FUNCTION_CTOR ||
obj === NUMBER_CTOR ||
obj === OBJECT_CTOR ||
obj === STRING_CTOR ||
obj === ARRAY_CTOR_PROTO ||
obj === BOOLEAN_CTOR_PROTO ||
obj === FUNCTION_CTOR_PROTO ||
obj === NUMBER_CTOR_PROTO ||
obj === OBJECT_CTOR_PROTO ||
obj === STRING_CTOR_PROTO) {
throw $parseMinErr('isecaf',
'Assigning to a constructor or its prototype is disallowed! Expression: {0}',
fullExpression);
@@ -1794,8 +1802,6 @@ function isPossiblyDangerousMemberName(name) {
return name === 'constructor';
}
var objectValueOf = Object.prototype.valueOf;
function getValueOf(value) {
return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
}