JavaScript is complex enough that pretty much any code inside of the loop could end up doing an array push. Even `console.log(myCompletelyUnrelatedObject.x)` (given an evil property descriptor).
I don't know a whole lot about JIT compilers, but would it be possible to emit code with length optimized, and trap changes to it to fall back to a slow path in a way that wouldn't hurt the fast path? For example, you might mark the array so that when other code mutates it, that code also modifies the return address on the stack to point to some fixup code that puts you onto the slow path.
I don't know much about this, either, but I don't think that is a feasible approach.
- where are you going to 'mark the array'? Does that mean every array gets the overhead of having room for that mark or do these marks live elsewhere? If so, where, and how is code checking it going to be performant?
- in nested calls, are you going to allow multiple marks? (Solvable, I think, as you can get away with an integer mark count)
- that would mean that all code that modifies any array must check whether such a mark is present and then find the return address on the stack (and nested return addresses)
- even if you do all of the above, the simple checking for presence of such a mark can kill performance in tight loops, even if you do that with branch prediction hints.
- how do you know what mutating changes are important for the calling code? You can use a function pointer as the 'mark' and call that so that it can figure it out by itself, but that surely will kill performance in tight loops.
I think the normal way is for compiled functions to detect when their own assumptions (may) no longer hold, not for other code to signal any compiled code on the stack that its assumptions (may) no longer hold. In tight frequently run code, you may be able to inline calls and recompile, but that is costly, too.
EDIT: I just realize that it is possible to do something in the spirit of this without needing any marks. The really bad calls, such as those to eval, will have to tell the JIT compiler that the current game is over, and that they can start over. It is too costly to do that from any innocuous call, such as that which adds an item to an array, though.
As to that length optimization: it use to say that C doesn't have a for loop; because it evaluates the end condition through every iteration, its 'for' is a 'while' in disguise. Pascal, on the other hand, has a for loop.
Not if the function is inlineable or an intrinsic (console.log will likely be either), which is the most basic trick of any JIT.
Unless you can specifically measure caching the length is faster, I wouldn't do it. Most of the time it doesn't matter anyway (won't cause a bump in performance), and even then most of the time the compiler will be able to figure it out for you.
Maybe my comment was misleading - the important part is the property read, not the `console.log`. The following code might be an infinite loop in JavaScript:
function adder(arr, obj) {
for (var i = 0; i < arr.length; ++i) {
obj.x += i;
}
}
var arr = [1];
var obj = Object.defineProperties({}, {
x: {
get: function() { return 1; },
set: function(v) { arr.push(v); }
}
};
adder(arr, obj);
for(var i=0;i<a.length;i++) if(check(a[i])) a.push('foo');