1
0
Fork 0

Various argument handling optimizations

Permits more aggressive v8 optimization.
perfodd
Mike Gerwitz 2014-03-29 00:40:36 -04:00
parent e7f0f2ffc1
commit 77efd515de
6 changed files with 95 additions and 77 deletions

View File

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

View File

@ -5,7 +5,7 @@
* flag to allow abstract methods within a class, forcing users to clearly * flag to allow abstract methods within a class, forcing users to clearly
* state that a class is abstract. * state that a class is abstract.
* *
* Copyright (C) 2010, 2011, 2013, 2014 Mike Gerwitz * Copyright (C) 2010, 2011, 2013 Mike Gerwitz
* *
* This file is part of GNU ease.js. * This file is part of GNU ease.js.
* *
@ -33,7 +33,7 @@ var Class = require( __dirname + '/class' );
*/ */
module.exports = exports = function() module.exports = exports = function()
{ {
markAbstract( arguments ); markAbstract( arguments[ arguments.length - 1 ] );
// forward everything to Class // forward everything to Class
var result = Class.apply( this, arguments ); var result = Class.apply( this, arguments );
@ -56,7 +56,7 @@ module.exports = exports = function()
*/ */
exports.extend = function() exports.extend = function()
{ {
markAbstract( arguments ); markAbstract( arguments[ arguments.length - 1 ] );
return Class.extend.apply( this, arguments ); return Class.extend.apply( this, arguments );
}; };
@ -92,18 +92,12 @@ exports.implement = function()
/** /**
* Causes a definition to be flagged as abstract * Causes a definition to be flagged as abstract
* *
* This function assumes the last argument to be the definition, which is the * @param {*} dfn suspected definition object
* common case, and modifies the object referenced by that argument.
*
* @param {Arguments} args arguments to parse
* *
* @return {undefined} * @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' ) if ( typeof dfn === 'object' )
{ {
// mark as abstract // mark as abstract
@ -141,7 +135,7 @@ function abstractOverride( obj )
// wrap extend, applying the abstract flag // wrap extend, applying the abstract flag
obj.extend = function() obj.extend = function()
{ {
markAbstract( arguments ); markAbstract( arguments[ arguments.length - 1 ] );
return extend.apply( this, arguments ); return extend.apply( this, arguments );
}; };

View File

@ -29,7 +29,7 @@ var Class = require( __dirname + '/class' );
*/ */
exports = module.exports = function() exports = module.exports = function()
{ {
markFinal( arguments ); markFinal( arguments[ arguments.length - 1 ] );
// forward everything to Class // forward everything to Class
var result = Class.apply( this, arguments ); var result = Class.apply( this, arguments );
@ -50,7 +50,7 @@ exports = module.exports = function()
*/ */
exports.extend = function() exports.extend = function()
{ {
markFinal( arguments ); markFinal( arguments[ arguments.length - 1 ] );
return Class.extend.apply( this, arguments ); return Class.extend.apply( this, arguments );
}; };
@ -58,18 +58,12 @@ exports.extend = function()
/** /**
* Causes a definition to be flagged as final * Causes a definition to be flagged as final
* *
* This function assumes the last argument to be the definition, which is the * @param {!Arguments} dfn suspected definition object
* common case, and modifies the object referenced by that argument.
*
* @param {!Arguments} args arguments to parse
* *
* @return {undefined} * @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' ) if ( typeof dfn === 'object' )
{ {
// mark as abstract // mark as abstract
@ -92,7 +86,7 @@ function finalOverride( obj )
// wrap extend, applying the abstract flag // wrap extend, applying the abstract flag
obj.extend = function() obj.extend = function()
{ {
markFinal( arguments ); markFinal( arguments[ arguments.length - 1 ] );
return extend.apply( this, arguments ); 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 // ensure we'll be permitted to instantiate interfaces for the base
extending = true; extending = true;
var args = Array.prototype.slice.call( arguments ), var a = arguments,
props = args.pop() || {}, an = a.length,
base = args.pop() || Interface, props = ( ( an > 0 ) ? a[ an - 1 ] : 0 ) || {},
base = ( ( an > 1 ) ? a[ an - 2 ] : 0 ) || Interface,
prototype = new base(), prototype = new base(),
iname = '', iname = '',

View File

@ -399,7 +399,10 @@ function verifyAbstractNames( name, params )
*/ */
exports.createAbstractMethod = function( def ) 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() var method = function()
{ {
@ -407,7 +410,7 @@ exports.createAbstractMethod = function( def )
}; };
exports.defineSecureProp( method, 'abstractFlag', true ); exports.defineSecureProp( method, 'abstractFlag', true );
exports.defineSecureProp( method, 'definition', definition ); exports.defineSecureProp( method, 'definition', dfn );
exports.defineSecureProp( method, '__length', arguments.length ); exports.defineSecureProp( method, '__length', arguments.length );
return method; return method;