1
0
Fork 0

Various argument handling optimizations

Permits more aggressive v8 optimization.
newmaster
Mike Gerwitz 2014-03-29 00:40:36 -04:00
parent a52fcfa1d9
commit c76178516e
6 changed files with 94 additions and 76 deletions

View File

@ -299,9 +299,10 @@ exports.prototype.build = function extend( _, __ )
// ensure we'll be permitted to instantiate abstract classes for the base
this._extending = true;
var args = Array.prototype.slice.call( arguments ),
props = args.pop() || {},
base = args.pop() || exports.ClassBase,
var a = arguments,
an = a.length,
props = ( ( an > 0 ) ? a[ an - 1 ] : 0 ) || {},
base = ( ( an > 1 ) ? a[ an - 2 ] : 0 ) || exports.ClassBase,
prototype = this._getBase( base ),
cname = '',
autoa = false,
@ -508,7 +509,10 @@ exports.prototype.buildMembers = function buildMembers(
{
handlers[ name ] = function()
{
var args = Array.prototype.slice.call( arguments );
var args = [],
i = arguments.length;
while ( i-- ) args[ i ] = arguments[ i ];
// invoke the custom handler with the original handler as
// its last argument (which the custom handler may choose

View File

@ -64,19 +64,24 @@ var _nullf = function() { return null; }
module.exports = function( namedef, def )
{
var type = ( typeof namedef ),
result = null
result = null,
args = [],
i = arguments.length
;
// passing arguments object prohibits optimizations in v8
while ( i-- ) args[ i ] = arguments[ i ];
switch ( type )
{
// anonymous class
case 'object':
result = createAnonymousClass.apply( null, arguments );
result = createAnonymousClass.apply( null, args );
break;
// named class
case 'string':
result = createNamedClass.apply( null, arguments );
result = createNamedClass.apply( null, args );
break;
default:
@ -99,10 +104,7 @@ module.exports = function( namedef, def )
*
* @return {Function} extended class
*/
module.exports.extend = function( baseordfn, dfn )
{
return extend.apply( this, arguments );
};
module.exports.extend = extend;
/**
@ -138,11 +140,11 @@ module.exports.implement = function( interfaces )
*/
module.exports.use = function( traits )
{
var args = [], i = arguments.length;
while( i-- ) args[ i ] = arguments[ i ];
// consume traits onto an empty base
return createUse(
_nullf,
Array.prototype.slice.call( arguments )
);
return createUse( _nullf, args );
};
@ -292,7 +294,10 @@ function createStaging( cname )
return {
extend: function()
{
var args = Array.prototype.slice.apply( arguments );
var args = [],
i = arguments.length;
while ( i-- ) args[ i ] = arguments[ i ];
// extend() takes a maximum of two arguments. If only one
// argument is provided, then it is to be the class definition.
@ -308,21 +313,24 @@ function createStaging( cname )
implement: function()
{
var args = [],
i = arguments.length;
while ( i-- ) args[ i ] = arguments[ i ];
// implement on empty base, providing the class name to be used once
// extended
return createImplement(
null,
Array.prototype.slice.call( arguments ),
cname
);
return createImplement( null, args, cname );
},
use: function()
{
return createUse(
_nullf,
Array.prototype.slice.call( arguments )
);
var args = [],
i = arguments.length;
while ( i-- ) args[ i ] = arguments[ i ];
return createUse( _nullf, args );
},
};
}
@ -349,14 +357,14 @@ function createImplement( base, ifaces, cname )
var partial = {
extend: function()
{
var args = Array.prototype.slice.call( arguments ),
def = args.pop(),
ext_base = args.pop()
var an = arguments.length,
def = arguments[ an - 1 ],
ext_base = ( an > 1 ) ? arguments[ an - 2 ] : null
;
// if any arguments remain, then they likely misunderstood what this
// method does
if ( args.length > 0 )
if ( an > 2 )
{
throw Error(
"Expecting no more than two arguments for extend()"
@ -394,7 +402,12 @@ function createImplement( base, ifaces, cname )
// much more performant (it creates a subtype before mixing in)
use: function()
{
var traits = Array.prototype.slice.call( arguments );
var traits = [],
i = arguments.length;
// passing arguments object prohibits optimizations in v8
while ( i-- ) traits[ i ] = arguments[ i ];
return createUse(
function() { return partial.__createBase(); },
traits
@ -468,9 +481,9 @@ function createUse( basef, traits, nonbase )
// given during the extend operation
partial.extend = function()
{
var args = Array.prototype.slice.call( arguments ),
dfn = args.pop(),
ext_base = args.pop(),
var an = arguments.length,
dfn = arguments[ an - 1 ],
ext_base = ( an > 1 ) ? arguments[ an - 2 ] : null,
base = basef();
// extend the mixed class, which ensures that all super references
@ -485,12 +498,17 @@ function createUse( basef, traits, nonbase )
// call simply to mix in another trait
partial.use = function()
{
var args = [],
i = arguments.length;
while ( i-- ) args[ i ] = arguments[ i ];
return createUse(
function()
{
return partial.__createBase();
},
Array.prototype.slice.call( arguments ),
args,
nonbase
);
};
@ -557,8 +575,14 @@ function createMixedClass( base, traits )
*/
function extend( _, __ )
{
var args = [],
i = arguments.length;
// passing arguments object prohibits optimizations in v8
while ( i-- ) args[ i ] = arguments[ i ];
// set up the new class
var new_class = class_builder.build.apply( class_builder, arguments );
var new_class = class_builder.build.apply( class_builder, args );
// set up some additional convenience props
setupProps( new_class );
@ -584,10 +608,9 @@ function extend( _, __ )
*/
var implement = function( baseobj, interfaces )
{
var args = Array.prototype.slice.call( arguments ),
var an = arguments.length,
dest = {},
base = args.pop(),
len = args.length,
base = arguments[ an - 1 ],
arg = null,
implemented = [],
@ -595,9 +618,9 @@ var implement = function( baseobj, interfaces )
;
// add each of the interfaces
for ( var i = 0; i < len; i++ )
for ( var i = 0; i < ( an - 1 ); i++ )
{
arg = args[ i ];
arg = arguments[ i ];
// copy all interface methods to the class (does not yet deep copy)
util.propParse( arg.prototype, {
@ -678,10 +701,10 @@ function attachImplement( func )
{
util.defineSecureProp( func, 'implement', function()
{
return createImplement(
func,
Array.prototype.slice.call( arguments )
);
var args = [], i = arguments.length;
while( i-- ) args[ i ] = arguments[ i ];
return createImplement( func, args );
});
}
@ -699,11 +722,10 @@ function attachUse( func )
{
util.defineSecureProp( func, 'use', function()
{
return createUse(
function() { return func; },
Array.prototype.slice.call( arguments ),
true
);
var args = [], i = arguments.length;
while( i-- ) args[ i ] = arguments[ i ];
return createUse( function() { return func; }, args, true );
} );
}

View File

@ -33,7 +33,7 @@ var Class = require( __dirname + '/class' );
*/
module.exports = exports = function()
{
markAbstract( arguments );
markAbstract( arguments[ arguments.length - 1 ] );
// forward everything to Class
var result = Class.apply( this, arguments );
@ -56,7 +56,7 @@ module.exports = exports = function()
*/
exports.extend = function()
{
markAbstract( arguments );
markAbstract( arguments[ arguments.length - 1 ] );
return Class.extend.apply( this, arguments );
};
@ -92,18 +92,12 @@ exports.implement = function()
/**
* Causes a definition to be flagged as abstract
*
* This function assumes the last argument to be the definition, which is the
* common case, and modifies the object referenced by that argument.
*
* @param {Arguments} args arguments to parse
* @param {*} dfn suspected definition object
*
* @return {undefined}
*/
function markAbstract( args )
function markAbstract( dfn )
{
// the last argument _should_ be the definition
var dfn = args[ args.length - 1 ];
if ( typeof dfn === 'object' )
{
// mark as abstract
@ -141,7 +135,7 @@ function abstractOverride( obj )
// wrap extend, applying the abstract flag
obj.extend = function()
{
markAbstract( arguments );
markAbstract( arguments[ arguments.length - 1 ] );
return extend.apply( this, arguments );
};

View File

@ -29,7 +29,7 @@ var Class = require( __dirname + '/class' );
*/
exports = module.exports = function()
{
markFinal( arguments );
markFinal( arguments[ arguments.length - 1 ] );
// forward everything to Class
var result = Class.apply( this, arguments );
@ -50,7 +50,7 @@ exports = module.exports = function()
*/
exports.extend = function()
{
markFinal( arguments );
markFinal( arguments[ arguments.length - 1 ] );
return Class.extend.apply( this, arguments );
};
@ -58,18 +58,12 @@ exports.extend = function()
/**
* Causes a definition to be flagged as final
*
* This function assumes the last argument to be the definition, which is the
* common case, and modifies the object referenced by that argument.
*
* @param {!Arguments} args arguments to parse
* @param {!Arguments} dfn suspected definition object
*
* @return {undefined}
*/
function markFinal( args )
function markFinal( dfn )
{
// the last argument _should_ be the definition
var dfn = args[ args.length - 1 ];
if ( typeof dfn === 'object' )
{
// mark as abstract
@ -92,7 +86,7 @@ function finalOverride( obj )
// wrap extend, applying the abstract flag
obj.extend = function()
{
markFinal( arguments );
markFinal( arguments[ arguments.length - 1 ] );
return extend.apply( this, arguments );
};
}

View File

@ -184,9 +184,10 @@ var extend = ( function( extending )
// ensure we'll be permitted to instantiate interfaces for the base
extending = true;
var args = Array.prototype.slice.call( arguments ),
props = args.pop() || {},
base = args.pop() || Interface,
var a = arguments,
an = a.length,
props = ( ( an > 0 ) ? a[ an - 1 ] : 0 ) || {},
base = ( ( an > 1 ) ? a[ an - 2 ] : 0 ) || Interface,
prototype = new base(),
iname = '',

View File

@ -399,7 +399,10 @@ function verifyAbstractNames( name, params )
*/
exports.createAbstractMethod = function( def )
{
var definition = Array.prototype.slice.call( arguments );
var dfn = [],
i = arguments.length;
while ( i-- ) dfn[ i ] = arguments[ i ];
var method = function()
{
@ -407,7 +410,7 @@ exports.createAbstractMethod = function( def )
};
exports.defineSecureProp( method, 'abstractFlag', true );
exports.defineSecureProp( method, 'definition', definition );
exports.defineSecureProp( method, 'definition', dfn );
exports.defineSecureProp( method, '__length', arguments.length );
return method;