Here are the cases from most knowledge about f to least knowledge about f.
If f is statically known at the call site, then a direct jump to f_correct_params (or f_undefined_0, or f_undefined_1, ...) can be done because the values of N and M are known at the call site. The parameter count does not have to be stored in %CL and checked.
If f is a property of the global object, then the jump instruction in f's caller can be
jmp f_as_function
If I understand correctly how it could be implemented, as you generate code for all global properties read, write and update, you reserve a new slot in the global object for each different property name and you resolve the exact address of "f_as_function" at linking time, once you know the exact position of the global object in memory.
However, how do we know the exact address of "f_as_function" on the global object in the presence of possible property deletions?
Suppose:
var foo = function () { return 123; }; // Add 'foo' property on global as a function var bar = function () { return 456; }; // Add 'bar' property on global as a function foo(); // (1) delete foo; // Remove 'foo' property from global bar(); // What is the address of "bar_as_function"?
Also:
var foo = function () { return 42; }; // Second add of 'foo' property on global foo(); // Is "foo_as_function" address the same as (1)?
We might keep the slot of deleted values so that all other slot's addresses stay the same, assuming deletion of global object properties is not sufficiently frequent as to waste a significant amount of space.
While thinking about the global object handling I came accross other issues we need to take into account:
1. What about a nested function whose 'this' property is being used
var obj = {}; obj.foo = function () { function bar () { this.x = 42; }; bar(); }; obj.foo(); // global now has a x property!
2. Or a constructor called without the 'new' operator?
function Constr () { this.y = 42; return this; }; var a = new Constr(); // a has a y property! var b = Constr(); // global now has a y property! var C = Constr; var d = C(); // the constructor might be called with an additional level of // indirection
3. Or a variable in a function?
// Suppose global doesn't have a z property function biz() { z = 42; }; biz(); // global now has a z property
Cases 1, 2 and 3 forces the global object to allow new properties to be added at runtime on the global object. A delete might also occurs in those same cases and the corresponding property on the global object should be deleted. To make things more fun, let's recall that an access to a non-existing property on the global object throws an exception but not an existing property assigned to 'undefined':
// Suppose that global doesn't have a z property print(z); // Uncaught ReferenceError: z is not defined
z = undefined; print(z); // prints undefined
4. What about multiple nesting of objects?
var foo = {}; // Declaration of a foo namespace foo.bar = function () { return 42; }; // module function
Case 4 is a style advocated by Douglas Crockford in "Javascript: The Good Parts" to limit interferences between different "modules" in the absence of a proper module system, therefore I would expect this style to be used more and more by real web applications. This style might limit the usefulness of the original optimization since an object lookup must still be performed on 'foo' to find 'bar'. I think we should try to also optimize multiple levels of lookup in the cases where the structure of intermediate objects is known at compile time and/or stable at runtime.
Otherwise a property lookup of property f must be performed on the object in %ESI and control must be transferred to the value if it is a function. This can be done by calling a handler. So the code would simply be
call prop_lookup_and_call_handler .data "f"
Runtime optimization of property lookup and method calls on objects in general were not discussed in your previous mail and might be fast enough to accelerate function calls on the global object without having to treat it as a special case. Maybe we should try to implement those first?
Erick