Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
perf($parse): improve performance of assignment expressions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gkalpak committed Aug 8, 2016
1 parent 49f0777 commit e8d7496
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 35 deletions.
19 changes: 9 additions & 10 deletions benchmarks/parsed-expressions-bp/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ app.directive('bmPeWatch', function() {
return function($scope, $element, $attrs) {
$scope.$watch($attrs.bmPeWatch, function(val) {
$element.text(val);

});
};
}
Expand Down Expand Up @@ -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()),
Expand Down
17 changes: 17 additions & 0 deletions benchmarks/parsed-expressions-bp/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down
56 changes: 31 additions & 25 deletions src/ng/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit e8d7496

Please sign in to comment.