Closed Bug 658638 Opened 9 years ago Closed 9 years ago

TI: generalize lazy arguments

Categories

(Core :: JavaScript Engine, defect)

x86
macOS
defect
Not set

Tracking

()

RESOLVED FIXED

People

(Reporter: bhackett, Assigned: bhackett)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

There are a few places we currently can make arguments object construction lazy.  In the bytecode emitter we transform arguments[i] to ARGSUB and arguments.length to ARGCNT, which will avoid making an arguments object if possible.  In JM we pattern match x.apply(y, arguments).  Neither of these is robust enough to deal with code patterns that, say, assign arguments to a local and then use it later in GETELEM or APPLY (this pattern is in earley-boyer, bug 642001), nor can they be extended for other ways we might want to lazy the arguments, such as for Array.slice (bug 656813).

With SSA and type information, we can determine fairly precisely how arguments are used within a function, and do so in a robust and extensible way that handles copying into locals and more complicated uses than the apply case.  Take the earley-boyer example:

  787  function sc_list() {
  788      var res = null;
  789      var a = arguments;
  790      for (var i = a.length-1; i >= 0; i--)
  791          res = new sc_Pair(a[i], res);
  792      return res;
  793  }

With SSA, we can look at all the places where 'arguments' can flow to through transitive copies (we know that 'a' is not closed and is only accessed within sc_list), and then check if each of those uses can be regarded as a non-escaping, non-mutating use of the variable.  JSOP_GETELEM and JSOP_LENGTH are straightforward cases, handling x.apply or Array.slice would  need type information.

If we can prove the arguments of a script do not escape, then JSOP_ARGUMENTS can be replaced with a special lazy arguments value, which would need to be handled by any ops or natives which the analysis treats as a non-escaping use of the arguments.

For the cleanest behavior and best performance, we would want this to happen in both JIT code and the interpreter.  We wouldn't have to do anything weird when transitioning between the two, and the JIT could make assumptions regarding frames which have never had arguments objects constructed.  Doing analysis and type inference is fine when done in the interpreter, as long as it is only done occasionally, e.g. just on scripts that use ARGUMENTS (we already do SSA and type inference from the interpreter on scripts called with 'new', to determine properties the new objects definitely have).

For invalidation (e.g. some side effect happens that makes us think 'x.apply' may no longer be the apply native), we would need to walk the stack to look for frames on the expected script, make the arguments object and then walk the stack and slots to replace the lazy value with the actual value.
Blocks: 619423
No longer blocks: TypeInference
Attached patch patchSplinter Review
Analyze escaping arguments, and use a LAZY_ARGUMENTS magic value in both the interpreter and the method JIT when we can prove the arguments will only be used in LENGTH and GETELEM, even after copying into locals.  Can extend this to allow particular natives to manipulate lazy arguments (Array.slice, Function.apply, should not be hard) later.  GETELEM-like paths added to JM to handle lazy argument LENGTH and GETELEM, including loop hoisting and bounds check elimination for these accesses.  earley-boyer improves by about 25%.

function count() {
  var res = 0;
  var a = arguments;
  for (var i = 0; i < a.length; i++) {
    res += a[i];
  }
}
function foo() {
  for (var i = 0; i < 800000; i++)
    count(1,2,3,4,5,6,7,8,9,10);
}
foo();

js -m -n (old): 670
js -m -n (new): 47
d8: 37
js -m: 564
js -j: 344

All the times are the same if 'arguments' is not copied into a local first.  The difference between us and V8 is more than accounted for by the base overhead of making these calls, i.e. we do the inner loop faster but v8 does the call faster.  If I remove the body of 'count', I get these times:

js -m -n: 31
d8: 14
Assignee: general → bhackett1024
Forgot to test on x64, it was angry at me for mixing neg32 with addPtr.

http://hg.mozilla.org/projects/jaegermonkey/rev/6ad7f6da94cb
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Depends on: 660538
You need to log in before you can comment on or make changes to this bug.