From 12f5f672f880cbfae726139cf48b6ba80c408ff0 Mon Sep 17 00:00:00 2001 From: Kasper Lund Date: Wed, 11 Dec 2013 12:44:57 +0100 Subject: [PATCH] perf(bracket): Optimize calling methods on objects. Optimize the closures used for calling methods on objects by getting rid of an intermediate "field access" that loads the function from the object. This allows us to use InstanceMirror.invoke more directly. Performance =========== The performance implications of this change look good. On the native Dart VM, calling methods through the reflective path becomes 4.5x faster. When compiled to JavaScript, the difference is even bigger and it is 6.7x faster. Dart VM: new: o.f() => g: 18,885,385.384 ops/sec r: 2,252,149.057 ops/sec h: 2,233,514.96 ops/sec i: 32,662,458.941 ops/sec old: o.f() => g: 18,118,349.692 ops/sec r: 496,119.238 ops/sec h: 6,234,893.68 ops/sec i: 31,472,943.499 ops/sec Dart2js: new: o.f() => g: 2,618,328.337 ops/sec r: 1,234,723.632 ops/sec h: 1,234,745.10 ops/sec i: 7,507,441.131 ops/sec old: o.f() => g: 2,427,133.253 ops/sec r: 184,727.903 ops/sec h: 500,226.70 ops/sec i: 7,461,638.467 ops/sec Conflicts: lib/core/parser/backend.dart --- lib/core/parser/backend.dart | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/core/parser/backend.dart b/lib/core/parser/backend.dart index 95f205a5c..d5961eecc 100644 --- a/lib/core/parser/backend.dart +++ b/lib/core/parser/backend.dart @@ -205,6 +205,15 @@ class ParserBackend { }; } + List evalList(List list, self) { + int length = list.length; + List result = new List(length); + for (int i = 0; i < length; i++) { + result[i] = list[i].eval(self); + } + return result; + } + _op(opKey) => OPERATORS[opKey]; Expression ternaryFn(Expression cond, Expression _true, Expression _false) => @@ -237,16 +246,23 @@ class ParserBackend { return value; }); - Expression functionCall(fn, fnName, argsFn, evalError) => - new Expression((self){ - List args = []; - for ( var i = 0; i < argsFn.length; i++) { - args.add(argsFn[i].eval(self)); - } + Expression functionCall(fn, fnName, argsFn, evalError) { + if (fn.isFieldAccess) { + Symbol key = new Symbol(fn.fieldName); + return new Expression((self) { + List args = evalList(argsFn, self); + var holder = fn.fieldHolder.eval(self); + InstanceMirror instanceMirror = reflect(holder); + return instanceMirror.invoke(key, args).reflectee; + }); + } else { + return new Expression((self) { + List args = evalList(argsFn, self); var userFn = safeFunctionCall(fn.eval(self), fnName, evalError); - return relaxFnApply(userFn, args); }); + } + } Expression arrayDeclaration(elementFns) => new Expression((self){ @@ -276,7 +292,9 @@ class ParserBackend { var getterFn = getter(field); return new Expression( (self) => getterFn(object.eval(self)), - (self, value) => setterFn(object.eval(self), value)); + (self, value) => setterFn(object.eval(self), value)) + ..fieldHolder = object + ..fieldName = field; } Expression object(keyValues) =>