$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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;
 }