Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r77491 - trunk/tools/build/v2/engine
From: steven_at_[hidden]
Date: 2012-03-22 19:26:50


Author: steven_watanabe
Date: 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
New Revision: 77491
URL: http://svn.boost.org/trac/boost/changeset/77491

Log:
Optimize variable lookup to bypass hash for constant variable names.
Text files modified:
   trunk/tools/build/v2/engine/builtins.c | 3
   trunk/tools/build/v2/engine/class.c | 5
   trunk/tools/build/v2/engine/compile.c | 36 +
   trunk/tools/build/v2/engine/constants.c | 6
   trunk/tools/build/v2/engine/constants.h | 2
   trunk/tools/build/v2/engine/function.c | 575 ++++++++++++++++++++++++++++++++++++++-
   trunk/tools/build/v2/engine/function.h | 3
   trunk/tools/build/v2/engine/modules.c | 130 +++++++++
   trunk/tools/build/v2/engine/modules.h | 17 +
   trunk/tools/build/v2/engine/rules.c | 18 +
   trunk/tools/build/v2/engine/rules.h | 1
   trunk/tools/build/v2/engine/variable.c | 53 ++
   12 files changed, 801 insertions(+), 48 deletions(-)

Modified: trunk/tools/build/v2/engine/builtins.c
==============================================================================
--- trunk/tools/build/v2/engine/builtins.c (original)
+++ trunk/tools/build/v2/engine/builtins.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -1127,7 +1127,7 @@
 
         imported = import_rule( r, target_module, list_item( target_iter ) );
         if ( !list_empty( localize ) )
- imported->module = target_module;
+ rule_localize( imported, target_module );
         /* This rule is really part of some other module. Just refer to it here,
          * but do not let it out.
          */
@@ -1459,6 +1459,7 @@
     module_t * const instance = bindmodule( list_front( arg1 ) );
     module_t * const class_module = bindmodule( list_front( arg2 ) );
     instance->class_module = class_module;
+ module_set_fixed_variables( instance, class_module->num_fixed_variables );
     return L0;
 }
 

Modified: trunk/tools/build/v2/engine/class.c
==============================================================================
--- trunk/tools/build/v2/engine/class.c (original)
+++ trunk/tools/build/v2/engine/class.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -80,7 +80,10 @@
     /* If we are importing a class method, localize it. */
     if ( ( r->module == d->base_module ) || ( r->module->class_module &&
         ( r->module->class_module == d->base_module ) ) )
- ir1->module = ir2->module = d->class_module;
+ {
+ rule_localize( ir1, d->class_module );
+ rule_localize( ir2, d->class_module );
+ }
 
     string_free( qualified_name );
 }

Modified: trunk/tools/build/v2/engine/compile.c
==============================================================================
--- trunk/tools/build/v2/engine/compile.c (original)
+++ trunk/tools/build/v2/engine/compile.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -115,7 +115,7 @@
 }
 
 
-static void argument_error( const char * message, RULE * rule, FRAME * frame, OBJECT * arg )
+void argument_error( const char * message, RULE * rule, FRAME * frame, OBJECT * arg )
 {
     LOL * actual = frame->args;
     assert( rule->procedure != 0 );
@@ -144,7 +144,7 @@
  * specification.
  */
 
-static int is_type_name( const char * s )
+int is_type_name( const char * s )
 {
     return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
         ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
@@ -183,20 +183,20 @@
  * checked
  */
 
-static void type_check
+void type_check_range
 (
     OBJECT * type_name,
- LIST * values,
+ LISTITER iter,
+ LISTITER end,
     FRAME * caller,
     RULE * called,
     OBJECT * arg_name
 )
 {
     static module_t * typecheck = 0;
- LISTITER iter, end;
 
     /* If nothing to check, bail now. */
- if ( !values || !type_name )
+ if ( iter == end || !type_name )
         return;
 
     if ( !typecheck )
@@ -208,7 +208,7 @@
     if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
         return;
 
- for ( iter = list_begin( values ), end = list_end( values ); iter != end; iter = list_next( iter ) )
+ for ( ; iter != end; iter = list_next( iter ) )
     {
         LIST *error;
         FRAME frame[1];
@@ -228,6 +228,19 @@
     }
 }
 
+void type_check
+(
+ OBJECT * type_name,
+ LIST * values,
+ FRAME * caller,
+ RULE * called,
+ OBJECT * arg_name
+)
+{
+ type_check_range( type_name, list_begin( values ), list_end( values ), caller, called, arg_name );
+}
+
+
 /*
  * collect_arguments() - local argument checking and collection
  */
@@ -485,6 +498,7 @@
 
 #endif
 
+LIST * function_run_with_args( FUNCTION * function_, FRAME * frame, STACK * s, RULE * rule );
 
 /*
  * evaluate_rule() - execute a rule invocation.
@@ -637,16 +651,10 @@
      */
     if ( rule->procedure )
     {
- SETTINGS * local_args = collect_arguments( rule, frame );
         FUNCTION * function = rule->procedure;
 
         function_refer( function );
-
- pushsettings( frame->module, local_args );
- result = function_run( function, frame, stack_global() );
- popsettings( frame->module, local_args );
- freesettings( local_args );
-
+ result = function_run_with_args( function, frame, stack_global(), rule );
         function_free( function );
     }
 

Modified: trunk/tools/build/v2/engine/constants.c
==============================================================================
--- trunk/tools/build/v2/engine/constants.c (original)
+++ trunk/tools/build/v2/engine/constants.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -23,6 +23,8 @@
     constant_dot = object_new( "." );
     constant_percent = object_new( "%" );
     constant_plus = object_new( "+" );
+ constant_star = object_new( "*" );
+ constant_question_mark = object_new( "?" );
     constant_ok = object_new( "ok" );
     constant_true = object_new( "true" );
     constant_name = object_new( "__name__" );
@@ -77,6 +79,8 @@
     object_free( constant_dot );
     object_free( constant_percent );
     object_free( constant_plus );
+ object_free( constant_star );
+ object_free( constant_question_mark );
     object_free( constant_ok );
     object_free( constant_true );
     object_free( constant_name );
@@ -129,6 +133,8 @@
 OBJECT * constant_dot;
 OBJECT * constant_percent;
 OBJECT * constant_plus;
+OBJECT * constant_star;
+OBJECT * constant_question_mark;
 OBJECT * constant_ok;
 OBJECT * constant_true;
 OBJECT * constant_name;

Modified: trunk/tools/build/v2/engine/constants.h
==============================================================================
--- trunk/tools/build/v2/engine/constants.h (original)
+++ trunk/tools/build/v2/engine/constants.h 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -20,6 +20,8 @@
 extern OBJECT * constant_dot; /* "." */
 extern OBJECT * constant_percent; /* "%" */
 extern OBJECT * constant_plus; /* "+" */
+extern OBJECT * constant_star; /* "*" */
+extern OBJECT * constant_question_mark; /* "?" */
 extern OBJECT * constant_ok; /* "ok" */
 extern OBJECT * constant_true; /* "true" */
 extern OBJECT * constant_name; /* "__name__" */

Modified: trunk/tools/build/v2/engine/function.c
==============================================================================
--- trunk/tools/build/v2/engine/function.c (original)
+++ trunk/tools/build/v2/engine/function.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -36,6 +36,7 @@
 #define INSTR_PUSH_CONSTANT 1
 #define INSTR_PUSH_ARG 2
 #define INSTR_PUSH_VAR 3
+#define INSTR_PUSH_VAR_FIXED 57
 #define INSTR_PUSH_GROUP 4
 #define INSTR_PUSH_RESULT 5
 #define INSTR_PUSH_APPEND 6
@@ -69,6 +70,12 @@
 #define INSTR_APPEND 27
 #define INSTR_DEFAULT 28
 
+#define INSTR_PUSH_LOCAL_FIXED 58
+#define INSTR_POP_LOCAL_FIXED 59
+#define INSTR_SET_FIXED 60
+#define INSTR_APPEND_FIXED 61
+#define INSTR_DEFAULT_FIXED 62
+
 #define INSTR_PUSH_LOCAL_GROUP 29
 #define INSTR_POP_LOCAL_GROUP 30
 #define INSTR_SET_GROUP 31
@@ -97,6 +104,7 @@
 #define INSTR_PUSH_MODULE 50
 #define INSTR_POP_MODULE 51
 #define INSTR_CLASS 52
+#define INSTR_BIND_MODULE_VARIABLES 63
 
 #define INSTR_APPEND_STRINGS 53
 #define INSTR_WRITE_FILE 54
@@ -131,6 +139,8 @@
     int type;
     int reference_count;
     OBJECT * rulename;
+ struct arg_list * formal_arguments;
+ int num_formal_arguments;
 };
 
 typedef struct _builtin_function
@@ -143,6 +153,7 @@
 typedef struct _jam_function
 {
     FUNCTION base;
+ int code_size;
     instruction * code;
     int num_constants;
     OBJECT * * constants;
@@ -150,6 +161,7 @@
     SUBFUNCTION * functions;
     int num_subactions;
     SUBACTION * actions;
+ FUNCTION * generic;
     OBJECT * file;
     int line;
 } JAM_FUNCTION;
@@ -1192,9 +1204,12 @@
     int i;
     result->base.type = FUNCTION_JAM;
     result->base.reference_count = 1;
+ result->base.formal_arguments = 0;
+ result->base.num_formal_arguments = 0;
 
     result->base.rulename = 0;
 
+ result->code_size = c->code->size;
     result->code = BJAM_MALLOC( c->code->size * sizeof(instruction) );
     memcpy( result->code, c->code->data, c->code->size * sizeof(instruction) );
 
@@ -1217,6 +1232,8 @@
     memcpy( result->actions, c->actions->data, c->actions->size * sizeof(SUBACTION) );
     result->num_subactions = c->actions->size;
 
+ result->generic = 0;
+
     result->file = 0;
     result->line = -1;
 
@@ -2242,6 +2259,7 @@
     {
         compile_parse( parse->left, c, RESULT_STACK );
         compile_emit( c, INSTR_INCLUDE, 0 );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
         adjust_result( c, RESULT_NONE, result_location );
     }
     else if ( parse->type == PARSE_MODULE )
@@ -2268,6 +2286,7 @@
         }
         compile_emit( c, INSTR_CLASS, 0 );
         compile_parse( parse->right, c, RESULT_NONE );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
         compile_emit( c, INSTR_POP_MODULE, 0 );
 
         adjust_result( c, RESULT_NONE, result_location );
@@ -2533,6 +2552,8 @@
     result->base.type = FUNCTION_BUILTIN;
     result->base.reference_count = 1;
     result->base.rulename = 0;
+ result->base.formal_arguments = 0;
+ result->base.num_formal_arguments = 0;
     result->func = func;
     result->flags = flags;
     return (FUNCTION *)result;
@@ -2571,6 +2592,429 @@
     return (FUNCTION *)result;
 }
 
+void argument_error( const char * message, RULE * rule, FRAME * frame, OBJECT * arg );
+int is_type_name( const char * s );
+
+void type_check_range
+(
+ OBJECT * type_name,
+ LISTITER iter,
+ LISTITER end,
+ FRAME * caller,
+ RULE * called,
+ OBJECT * arg_name
+);
+
+void type_check
+(
+ OBJECT * type_name,
+ LIST * values,
+ FRAME * caller,
+ RULE * called,
+ OBJECT * arg_name
+);
+
+struct argument {
+ int flags;
+#define ARG_ONE 0
+#define ARG_OPTIONAL 1
+#define ARG_PLUS 2
+#define ARG_STAR 3
+#define ARG_VARIADIC 4
+ OBJECT * type_name;
+ OBJECT * arg_name;
+ int index;
+};
+
+struct arg_list {
+ int size;
+ struct argument * args;
+};
+
+void argument_list_check( struct arg_list * formal, int formal_count, RULE * rule, FRAME * frame )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", rule, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, rule, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, rule, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", rule, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, rule, formal_arg->arg_name );
+ actual_iter = actual_end;
+ case ARG_VARIADIC:
+ return;
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", rule, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", rule, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_push( struct arg_list * formal, int formal_count, RULE * rule, FRAME * frame, STACK * s )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", rule, frame, formal_arg->arg_name );
+ value = list_new( L0, object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ value = list_new( L0, object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", rule, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ value = list_copy_range( actual, actual_iter, actual_end );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ type_check( formal_arg->type_name, value, frame, rule, formal_arg->arg_name );
+
+ if ( formal_arg->index != -1 )
+ {
+ LIST * * old = &frame->module->fixed_variables[ formal_arg->index ];
+ stack_push( s, *old );
+ *old = value;
+ }
+ else
+ {
+ stack_push( s, var_swap( frame->module, formal_arg->arg_name, value ) );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", rule, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", rule, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_pop( struct arg_list * formal, int formal_count, FRAME * frame, STACK * s )
+{
+ int i, j;
+
+ for ( i = formal_count - 1; i >= 0; --i )
+ {
+ for ( j = formal[i].size - 1; j >= 0 ; --j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+
+ if ( formal_arg->flags == ARG_VARIADIC )
+ {
+ continue;
+ }
+ else if ( formal_arg->index != -1 )
+ {
+ LIST * old = stack_pop( s );
+ LIST * * pos = &frame->module->fixed_variables[ formal_arg->index ];
+ list_free( *pos );
+ *pos = old;
+ }
+ else
+ {
+ var_set( frame->module, formal_arg->arg_name, stack_pop( s ), VAR_SET );
+ }
+ }
+ }
+}
+
+
+struct arg_list * argument_list_compile( LOL * all_formal, RULE * rule )
+{
+ struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof( struct arg_list ) * all_formal->count );
+
+ int n;
+ struct dynamic_array args[1];
+ dynamic_array_init( args );
+ for ( n = 0; n < all_formal->count ; ++n )
+ {
+ LIST *formal;
+ LISTITER formal_iter, formal_end;
+ for ( formal = lol_get( all_formal, n ),
+ formal_iter = list_begin( formal ), formal_end = list_end( formal );
+ formal_iter != formal_end; )
+ {
+ struct argument arg;
+ arg.type_name = 0;
+ arg.arg_name = list_item( formal_iter );
+ arg.index = -1;
+
+ if ( is_type_name( object_str( arg.arg_name ) ) )
+ {
+
+ formal_iter = list_next( formal_iter );
+
+ if ( formal_iter == formal_end )
+ argument_error( "missing argument name after type name:", rule, 0, arg.arg_name );
+
+ arg.type_name = arg.arg_name;
+ arg.arg_name = list_item( formal_iter );
+
+ if ( is_type_name( object_str( arg.arg_name ) ) )
+ argument_error( "missing argument name before type name:", rule, 0, arg.arg_name );
+ }
+
+ formal_iter = list_next( formal_iter );
+
+ if ( object_equal( arg.arg_name, constant_star ) )
+ {
+ arg.flags = ARG_VARIADIC;
+ }
+ else if ( formal_iter != formal_end )
+ {
+ if ( object_equal( list_item( formal_iter ), constant_question_mark ) )
+ {
+ arg.flags = ARG_OPTIONAL;
+ formal_iter = list_next( formal_iter );
+ }
+ else if ( object_equal( list_item( formal_iter ), constant_plus ) )
+ {
+ arg.flags = ARG_PLUS;
+ formal_iter = list_next( formal_iter );
+ }
+ else if ( object_equal( list_item( formal_iter ), constant_star ) )
+ {
+ arg.flags = ARG_STAR;
+ formal_iter = list_next( formal_iter );
+ }
+ else
+ arg.flags = ARG_ONE;
+ }
+ else
+ {
+ arg.flags = ARG_ONE;
+ }
+
+ dynamic_array_push( args, arg );
+ }
+
+ result[ n ].args = BJAM_MALLOC( args[ 0 ].size * sizeof( struct argument ) );
+ result[ n ].size = args[ 0 ].size;
+ memcpy( result[n].args, args[ 0 ].data, args[ 0 ].size * sizeof( struct argument ) );
+ args[ 0 ].size = 0;
+ }
+ dynamic_array_free( args );
+
+ return result;
+}
+
+
+struct arg_list * argument_list_bind_variables( struct arg_list * formal, int formal_count, module_t * module, int * counter )
+{
+ if ( formal )
+ {
+ struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof( struct arg_list ) * formal_count );
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ struct argument * args = (struct argument *)BJAM_MALLOC( sizeof( struct argument ) * formal[ i ].size );
+ for ( j = 0; j < formal[ i ].size; ++j )
+ {
+ args[ j ] = formal[ i ].args[ j ];
+ if ( args[ j ].flags != ARG_VARIADIC )
+ {
+ args[ j ].index = module_add_fixed_var( module, args[ j ].arg_name, counter );
+ }
+ }
+ result[ i ].args = args;
+ result[ i ].size = formal[ i ].size;
+ }
+
+ return result;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void argument_list_free( struct arg_list * args, int args_count )
+{
+ int i;
+ for ( i = 0; i < args_count; ++i )
+ {
+ BJAM_FREE( args[ i ].args );
+ }
+ BJAM_FREE( args );
+}
+
+
+void function_set_argument_list( FUNCTION * f, LOL * formal, RULE * rule )
+{
+ if ( !f->formal_arguments && formal )
+ {
+ f->formal_arguments = argument_list_compile( formal, rule );
+ f->num_formal_arguments = formal->count;
+ }
+}
+
+
+FUNCTION * function_unbind_variables( FUNCTION * f )
+{
+ if ( f->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ if ( func->generic )
+ return func->generic;
+ else
+ return (FUNCTION *)func;
+ }
+ else
+ {
+ return f;
+ }
+}
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter )
+{
+ if ( f->type == FUNCTION_BUILTIN )
+ {
+ return f;
+ }
+ else
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
+ instruction * code;
+ int i;
+ memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
+ new_func->base.reference_count = 1;
+ new_func->base.formal_arguments = argument_list_bind_variables( f->formal_arguments, f->num_formal_arguments, module, counter );
+ new_func->code = BJAM_MALLOC( func->code_size * sizeof( instruction ) );
+ memcpy( new_func->code, func->code, func->code_size * sizeof( instruction ) );
+ new_func->generic = (FUNCTION *)func;
+ func = new_func;
+ for ( i = 0; ; ++i )
+ {
+ OBJECT * key;
+ int op_code;
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_VAR: op_code = INSTR_PUSH_VAR_FIXED; break;
+ case INSTR_PUSH_LOCAL: op_code = INSTR_PUSH_LOCAL_FIXED; break;
+ case INSTR_POP_LOCAL: op_code = INSTR_POP_LOCAL_FIXED; break;
+ case INSTR_SET: op_code = INSTR_SET_FIXED; break;
+ case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break;
+ case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break;
+ case INSTR_RETURN: return (FUNCTION *)new_func;
+ case INSTR_CALL_RULE: ++i; continue;
+ case INSTR_PUSH_MODULE:
+ {
+ int depth = 1;
+ ++i;
+ while ( depth > 0 )
+ {
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_MODULE:
+ case INSTR_CLASS:
+ ++depth;
+ break;
+ case INSTR_POP_MODULE:
+ --depth;
+ break;
+ case INSTR_CALL_RULE:
+ ++i;
+ break;
+ }
+ ++i;
+ }
+ --i;
+ }
+ default: continue;
+ }
+ key = func->constants[ code->arg ];
+ if ( !( object_equal( key, constant_TMPDIR ) ||
+ object_equal( key, constant_TMPNAME ) ||
+ object_equal( key, constant_TMPFILE ) ||
+ object_equal( key, constant_STDOUT ) ||
+ object_equal( key, constant_STDERR ) ) )
+ {
+ code->op_code = op_code;
+ code->arg = module_add_fixed_var( module, key, counter );
+ }
+ }
+ }
+}
+
 void function_refer( FUNCTION * func )
 {
     ++func->reference_count;
@@ -2581,35 +3025,47 @@
     int i;
 
     if ( --function_->reference_count != 0 ) return;
-
- if ( function_->rulename ) object_free( function_->rulename );
+
+ if ( function_->formal_arguments ) argument_list_free( function_->formal_arguments, function_->num_formal_arguments );
 
     if ( function_->type == FUNCTION_JAM )
     {
         JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
 
         BJAM_FREE( func->code );
- for ( i = 0; i < func->num_constants; ++i )
- {
- object_free( func->constants[i] );
- }
- BJAM_FREE( func->constants );
 
- for ( i = 0; i < func->num_subfunctions; ++i )
+ if ( func->generic )
+ function_free( func->generic );
+ else
         {
- object_free( func->functions[i].name );
- function_free( func->functions[i].code );
- }
- BJAM_FREE( func->functions );
+ if ( function_->rulename ) object_free( function_->rulename );
 
- for ( i = 0; i < func->num_subactions; ++i )
- {
- object_free( func->actions[i].name );
- function_free( func->actions[i].command );
- }
- BJAM_FREE( func->actions );
+ for ( i = 0; i < func->num_constants; ++i )
+ {
+ object_free( func->constants[i] );
+ }
+ BJAM_FREE( func->constants );
 
- object_free( func->file );
+ for ( i = 0; i < func->num_subfunctions; ++i )
+ {
+ object_free( func->functions[i].name );
+ function_free( func->functions[i].code );
+ }
+ BJAM_FREE( func->functions );
+
+ for ( i = 0; i < func->num_subactions; ++i )
+ {
+ object_free( func->actions[i].name );
+ function_free( func->actions[i].command );
+ }
+ BJAM_FREE( func->actions );
+
+ object_free( func->file );
+ }
+ }
+ else
+ {
+ if ( function_->rulename ) object_free( function_->rulename );
     }
 
     BJAM_FREE( function_ );
@@ -2643,6 +3099,28 @@
     stack_deallocate( s, sizeof( string * ) );
 }
 
+LIST * function_run_with_args( FUNCTION * function_, FRAME * frame, STACK * s, RULE * rule )
+{
+ LIST * result;
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ if ( function_->formal_arguments )
+ argument_list_check( function_->formal_arguments, function_->num_formal_arguments, rule, frame );
+ return f->func( frame, f->flags );
+ }
+
+ if ( function_->formal_arguments )
+ argument_list_push( function_->formal_arguments, function_->num_formal_arguments, rule, frame, s );
+
+ result = function_run( function_, frame, s );
+
+ if ( function_->formal_arguments )
+ argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
+
+ return result;
+}
+
 /*
  * WARNING: The instruction set is tuned for Jam and
  * is not really generic. Be especially careful about
@@ -2700,6 +3178,12 @@
             break;
         }
 
+ case INSTR_PUSH_VAR_FIXED:
+ {
+ stack_push( s, list_copy( L0, frame->module->fixed_variables[ code->arg ] ) );
+ break;
+ }
+
         case INSTR_PUSH_GROUP:
         {
             LIST * value = L0;
@@ -2952,6 +3436,26 @@
             break;
         }
 
+ case INSTR_PUSH_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ stack_push( s, *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_POP_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = value;
+ break;
+ }
+
         case INSTR_PUSH_LOCAL_GROUP:
         {
             LIST * value = stack_pop( s );
@@ -3101,12 +3605,39 @@
             function_append_variable( function, frame, code->arg, list_copy( L0, stack_top( s ) ) );
             break;
         }
+
         case INSTR_DEFAULT:
         {
             function_default_variable( function, frame, code->arg, list_copy( L0, stack_top( s ) ) );
             break;
         }
 
+ case INSTR_SET_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = list_copy( L0, stack_top( s ) );
+ break;
+ }
+
+ case INSTR_APPEND_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ *ptr = list_append( *ptr, list_copy( L0, stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ if ( list_empty( *ptr ) )
+ *ptr = list_copy( L0, stack_top( s ) );
+ break;
+ }
+
         case INSTR_SET_GROUP:
         {
             LIST * value = stack_pop( s );
@@ -3374,6 +3905,12 @@
 
             break;
         }
+
+ case INSTR_BIND_MODULE_VARIABLES:
+ {
+ module_bind_variables( frame->module );
+ break;
+ }
         
         case INSTR_APPEND_STRINGS:
         {

Modified: trunk/tools/build/v2/engine/function.h
==============================================================================
--- trunk/tools/build/v2/engine/function.h (original)
+++ trunk/tools/build/v2/engine/function.h 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -32,6 +32,9 @@
 FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line );
 void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out );
 
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
 void function_done( void );
 
 #endif

Modified: trunk/tools/build/v2/engine/modules.c
==============================================================================
--- trunk/tools/build/v2/engine/modules.c (original)
+++ trunk/tools/build/v2/engine/modules.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -42,6 +42,9 @@
         {
             m->name = object_copy( name );
             m->variables = 0;
+ m->variable_indices = 0;
+ m->num_fixed_variables = 0;
+ m->fixed_variables = 0;
             m->rules = 0;
             m->imported_modules = 0;
             m->class_module = 0;
@@ -116,6 +119,19 @@
         m->variables = 0;
     }
 
+ if ( m->fixed_variables )
+ {
+ int i;
+ for ( i = 0; i < m->num_fixed_variables; ++i )
+ {
+ list_free( m->fixed_variables[ i ] );
+ }
+ BJAM_FREE( m->fixed_variables );
+ m->fixed_variables = 0;
+ hashdone( m->variable_indices );
+ m->variable_indices = 0;
+ }
+
     if ( m->imported_modules )
     {
         hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
@@ -190,3 +206,117 @@
         hashenumerate( module->imported_modules, add_module_name, &result );
     return result;
 }
+
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+struct fixed_variable
+{
+ OBJECT * key;
+ int n;
+};
+
+struct bind_vars_t
+{
+ module_t * module;
+ int counter;
+};
+
+static void bind_variables_for_rule( void * xrule, void * xdata )
+{
+ RULE * rule = (RULE *)xrule;
+ struct bind_vars_t * data = (struct bind_vars_t *)xdata;
+ if ( rule->procedure && rule->module == data->module )
+ rule->procedure = function_bind_variables( rule->procedure, data->module, &data->counter );
+}
+
+void module_bind_variables( struct module_t * m )
+{
+ if ( m != root_module() && m->rules )
+ {
+ struct bind_vars_t data = { m, m->num_fixed_variables };
+ hashenumerate( m->rules, &bind_variables_for_rule, &data );
+ module_set_fixed_variables( m, data.counter );
+ }
+}
+
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
+{
+ struct fixed_variable * v;
+ int found;
+
+ assert( !m->class_module );
+
+ if ( !m->variable_indices )
+ m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
+
+ v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
+ if ( !found )
+ {
+ v->key = object_copy( name );
+ v->n = (*counter)++;
+ }
+
+ return v->n;
+}
+
+LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
+
+static void load_fixed_variable( void * xvar, void * data )
+{
+ struct fixed_variable * var = (struct fixed_variable *)xvar;
+ struct module_t * m = (struct module_t *)data;
+ if ( var->n >= m->num_fixed_variables )
+ {
+ m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
+ }
+}
+
+void module_set_fixed_variables( struct module_t * m, int n_variables )
+{
+ /* Reallocate */
+ struct hash * variable_indices;
+ LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) );
+ if ( m->fixed_variables )
+ {
+ memcpy( fixed_variables, m->fixed_variables, n_variables * sizeof( LIST * ) );
+ BJAM_FREE( m->fixed_variables );
+ }
+ m->fixed_variables = fixed_variables;
+ if ( m->class_module )
+ {
+ variable_indices = m->class_module->variable_indices;
+ }
+ else
+ {
+ variable_indices = m->variable_indices;
+ }
+ if ( variable_indices )
+ hashenumerate( variable_indices, &load_fixed_variable, m );
+ m->num_fixed_variables = n_variables;
+}
+
+int module_get_fixed_var( struct module_t * m_, OBJECT * name )
+{
+ struct fixed_variable * v;
+ struct module_t * m = m_;
+
+ if ( m->class_module )
+ {
+ m = m->class_module;
+ }
+
+ if ( !m->variable_indices )
+ return -1;
+
+ v = (struct fixed_variable *)hash_find( m->variable_indices, name );
+ if ( v && v->n < m_->num_fixed_variables )
+ {
+ return v->n;
+ }
+ else
+ {
+ return -1;
+ }
+}

Modified: trunk/tools/build/v2/engine/modules.h
==============================================================================
--- trunk/tools/build/v2/engine/modules.h (original)
+++ trunk/tools/build/v2/engine/modules.h 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -13,6 +13,9 @@
     OBJECT * name;
     struct hash * rules;
     struct hash * variables;
+ struct hash * variable_indices;
+ int num_fixed_variables;
+ LIST * * fixed_variables;
     struct hash * imported_modules;
     struct module_t * class_module;
     struct hash * native_rules;
@@ -30,6 +33,20 @@
 
 struct hash * demand_rules( module_t * );
 
+void module_bind_variables( struct module_t * m );
+
+/*
+ * After calling module_add_fixed_var, module_set_fixed_variables
+ * must be called before accessing any variables in the module.
+ */
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * n );
+void module_set_fixed_variables( struct module_t * m, int n );
+
+/*
+ * Returns the index of the variable or -1 if none exists.
+ */
+int module_get_fixed_var( struct module_t * m, OBJECT * name );
+
 void modules_done();
 
 #endif

Modified: trunk/tools/build/v2/engine/rules.c
==============================================================================
--- trunk/tools/build/v2/engine/rules.c (original)
+++ trunk/tools/build/v2/engine/rules.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -556,6 +556,7 @@
     }
 }
 
+void function_set_argument_list( FUNCTION * f, LOL * formal, RULE * rule );
 
 /*
  * set_rule_body() - set the argument list and procedure of the given rule.
@@ -569,6 +570,9 @@
         args_free( rule->arguments );
     rule->arguments = args;
 
+ if ( procedure && args )
+ function_set_argument_list( procedure, args->data, rule );
+
     if ( procedure )
         function_refer( procedure );
     if ( rule->procedure )
@@ -762,3 +766,17 @@
     set_rule_actions( dest, source->actions );
     return dest;
 }
+
+
+void rule_localize( RULE * rule, module_t * m )
+{
+ rule->module = m;
+ if ( rule->procedure )
+ {
+ FUNCTION * procedure = function_unbind_variables( rule->procedure );
+ function_refer( procedure );
+ function_free( rule->procedure );
+ rule->procedure = procedure;
+ }
+}
+

Modified: trunk/tools/build/v2/engine/rules.h
==============================================================================
--- trunk/tools/build/v2/engine/rules.h (original)
+++ trunk/tools/build/v2/engine/rules.h 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -264,6 +264,7 @@
 /* Rule related functions. */
 RULE * bindrule ( OBJECT * rulename, module_t * );
 RULE * import_rule ( RULE * source, module_t *, OBJECT * name );
+void rule_localize ( RULE * rule, module_t * module );
 RULE * new_rule_body ( module_t *, OBJECT * rulename, argument_list *, FUNCTION * func, int exprt );
 RULE * new_rule_actions( module_t *, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags );
 void rule_free ( RULE * );

Modified: trunk/tools/build/v2/engine/variable.c
==============================================================================
--- trunk/tools/build/v2/engine/variable.c (original)
+++ trunk/tools/build/v2/engine/variable.c 2012-03-22 19:26:48 EDT (Thu, 22 Mar 2012)
@@ -61,7 +61,7 @@
     LIST * value;
 };
 
-static VARIABLE * var_enter( struct module_t * module, OBJECT * symbol );
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol );
 static void var_dump( OBJECT * symbol, LIST * value, char * what );
 
 
@@ -202,8 +202,15 @@
 #endif
     {
         VARIABLE * v;
+ int n;
 
- if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ if ( DEBUG_VARGET )
+ var_dump( symbol, module->fixed_variables[ n ], "get" );
+ result = module->fixed_variables[ n ];
+ }
+ else if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
         {
             if ( DEBUG_VARGET )
                 var_dump( v->symbol, v->value, "get" );
@@ -214,6 +221,20 @@
 }
 
 
+LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
+{
+ LIST * result = L0;
+ VARIABLE * v;
+
+ if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ {
+ result = v->value;
+ v->value = L0;
+ }
+
+ return result;
+}
+
 /*
  * var_set() - set a variable in Jam's user defined symbol table.
  *
@@ -226,7 +247,7 @@
 
 void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag )
 {
- VARIABLE * v = var_enter( module, symbol );
+ LIST * * v = var_enter( module, symbol );
 
     if ( DEBUG_VARSET )
         var_dump( symbol, value, "set" );
@@ -235,19 +256,19 @@
     {
     case VAR_SET:
         /* Replace value */
- list_free( v->value );
- v->value = value;
+ list_free( *v );
+ *v = value;
         break;
 
     case VAR_APPEND:
         /* Append value */
- v->value = list_append( v->value, value );
+ *v = list_append( *v, value );
         break;
 
     case VAR_DEFAULT:
         /* Set only if unset */
- if ( list_empty( v->value ) )
- v->value = value;
+ if ( list_empty( *v ) )
+ *v = value;
         else
             list_free( value );
         break;
@@ -261,11 +282,11 @@
 
 LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
 {
- VARIABLE * v = var_enter( module, symbol );
- LIST * oldvalue = v->value;
+ LIST * * v = var_enter( module, symbol );
+ LIST * oldvalue = *v;
     if ( DEBUG_VARSET )
         var_dump( symbol, value, "set" );
- v->value = value;
+ *v = value;
     return oldvalue;
 }
 
@@ -274,10 +295,16 @@
  * var_enter() - make new var symbol table entry, returning var ptr.
  */
 
-static VARIABLE * var_enter( struct module_t * module, OBJECT * symbol )
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
 {
     int found;
     VARIABLE * v;
+ int n;
+
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ return &module->fixed_variables[ n ];
+ }
 
     if ( !module->variables )
         module->variables = hashinit( sizeof( VARIABLE ), "variables" );
@@ -289,7 +316,7 @@
         v->value = L0;
     }
 
- return v;
+ return &v->value;
 }
 
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk