From 061f998f43604fd5b96e4a64de4e47f331d7d597 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 16 Apr 2013 23:54:54 +0000 Subject: [PATCH] Optimize member function calls to use less string manipulation. [SVN r83937] --- src/engine/compile.c | 29 +++---- src/engine/compile.h | 3 +- src/engine/function.c | 142 ++++++++++++++++++++++++++++++++-- src/engine/headers.c | 3 +- src/engine/make1.c | 6 +- src/engine/modules/sequence.c | 3 +- src/engine/search.c | 5 +- test/core-language/test.jam | 21 +++++ 8 files changed, 181 insertions(+), 31 deletions(-) diff --git a/src/engine/compile.c b/src/engine/compile.c index ae66dc0db..db46937ca 100644 --- a/src/engine/compile.c +++ b/src/engine/compile.c @@ -54,35 +54,28 @@ void unknown_rule( FRAME *, char const * key, module_t *, OBJECT * rule_name ); * evaluate_rule() - execute a rule invocation */ -LIST * evaluate_rule( OBJECT * rulename, FRAME * frame ) +LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame ) { LIST * result = L0; - RULE * rule; profile_frame prof[ 1 ]; module_t * prev_module = frame->module; - rule = bindrule( rulename, frame->module ); - if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute. */ - if ( rule->module != frame->module && rule->procedure && !object_equal( - rulename, function_rulename( rule->procedure ) ) ) + char buf[ 256 ] = ""; + if ( rule->module->name ) { - char buf[ 256 ] = ""; - if ( rule->module->name ) + strncat( buf, object_str( rule->module->name ), sizeof( buf ) - + 1 ); + strncat( buf, ".", sizeof( buf ) - 1 ); + if ( strncmp( buf, object_str( rule->name ), strlen( buf ) ) == 0 ) { - strncat( buf, object_str( rule->module->name ), sizeof( buf ) - - 1 ); - strncat( buf, ".", sizeof( buf ) - 1 ); + buf[ 0 ] = 0; } - strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 ); - debug_compile( 1, buf, frame ); - } - else - { - debug_compile( 1, object_str( rulename ), frame ); } + strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 ); + debug_compile( 1, buf, frame ); lol_print( frame->args ); printf( "\n" ); @@ -238,7 +231,7 @@ LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... ) } va_end( va ); - result = evaluate_rule( rulename, inner ); + result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner ); frame_free( inner ); diff --git a/src/engine/compile.h b/src/engine/compile.h index a1cb100fb..c70f98b9e 100644 --- a/src/engine/compile.h +++ b/src/engine/compile.h @@ -20,10 +20,11 @@ #include "frames.h" #include "lists.h" #include "object.h" +#include "rules.h" void compile_builtins(); -LIST * evaluate_rule( OBJECT * rulename, FRAME * ); +LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * ); LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... ); /* Flags for compile_set(), etc */ diff --git a/src/engine/function.c b/src/engine/function.c index ca187a1be..690855e14 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -96,6 +96,7 @@ void backtrace_line( FRAME * ); #define INSTR_GET_ON 65 #define INSTR_CALL_RULE 39 +#define INSTR_CALL_MEMBER_RULE 66 #define INSTR_APPLY_MODIFIERS 40 #define INSTR_APPLY_INDEX 41 @@ -472,12 +473,111 @@ static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, } } - result = evaluate_rule( rulename, inner ); + result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner ); frame_free( inner ); object_free( rulename ); return result; } +static LIST * function_call_member_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, OBJECT * rulename, OBJECT * file, int line ) +{ + FRAME inner[ 1 ]; + int i; + LIST * first = stack_pop( s ); + LIST * result = L0; + LIST * trailing; + RULE * rule; + module_t * module; + OBJECT * real_rulename = 0; + + frame->file = file; + frame->line = line; + + if ( list_empty( first ) ) + { + backtrace_line( frame ); + printf( "warning: object is empty\n" ); + backtrace( frame ); + + list_free( first ); + + for( i = 0; i < n_args; ++i ) + { + list_free( stack_pop( s ) ); + } + + return result; + } + + /* FIXME: handle generic case */ + assert( list_length( first ) == 1 ); + + module = bindmodule( list_front( first ) ); + if ( module->class_module ) + { + rule = bindrule( rulename, module ); + real_rulename = object_copy( function_rulename( rule->procedure ) ); + } + else + { + string buf[ 1 ]; + string_new( buf ); + string_append( buf, object_str( list_front( first ) ) ); + string_push_back( buf, '.' ); + string_append( buf, object_str( rulename ) ); + real_rulename = object_new( buf->value ); + string_free( buf ); + rule = bindrule( real_rulename, frame->module ); + } + + frame_init( inner ); + + inner->prev = frame; + inner->prev_user = frame->module->user_module ? frame : frame->prev_user; + inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */ + + for( i = 0; i < n_args; ++i ) + { + lol_add( inner->args, stack_at( s, n_args - i - 1 ) ); + } + + for( i = 0; i < n_args; ++i ) + { + stack_pop( s ); + } + + if ( list_length( first ) > 1 ) + { + string buf[ 1 ]; + LIST * trailing = L0; + LISTITER iter = list_begin( first ), end = list_end( first ); + iter = list_next( iter ); + string_new( buf ); + for ( ; iter != end; iter = list_next( iter ) ) + { + string_append( buf, object_str( list_item( iter ) ) ); + string_push_back( buf, '.' ); + string_append( buf, object_str( rulename ) ); + trailing = list_push_back( trailing, object_new( buf->value ) ); + string_truncate( buf, 0 ); + } + string_free( buf ); + if ( inner->args->count == 0 ) + lol_add( inner->args, trailing ); + else + { + LIST * * const l = &inner->args->list[ 0 ]; + *l = list_append( trailing, *l ); + } + } + + result = evaluate_rule( rule, real_rulename, inner ); + frame_free( inner ); + object_free( rulename ); + object_free( real_rulename ); + return result; +} + /* Variable expansion */ @@ -2557,11 +2657,29 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) current_file = object_str( parse->file ); current_line = parse->line; group = parse_expansion( &s ); - var_parse_group_compile( group, c ); - var_parse_group_free( group ); - compile_emit( c, INSTR_CALL_RULE, n ); - compile_emit( c, compile_emit_constant( c, parse->string ), parse->line - ); + + if ( group->elems->size == 2 && + dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_VAR && + dynamic_array_at( VAR_PARSE *, group->elems, 1 )->type == VAR_PARSE_TYPE_STRING && + ( object_str( ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 ) )->s )[ 0 ] == '.' ) ) + { + VAR_PARSE_STRING * access = (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 ); + OBJECT * member = object_new( object_str( access->s ) + 1 ); + /* Emit the object */ + var_parse_var_compile( (VAR_PARSE_VAR *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ), c ); + var_parse_group_free( group ); + compile_emit( c, INSTR_CALL_MEMBER_RULE, n ); + compile_emit( c, compile_emit_constant( c, member ), parse->line ); + object_free( member ); + } + else + { + var_parse_group_compile( group, c ); + var_parse_group_free( group ); + compile_emit( c, INSTR_CALL_RULE, n ); + compile_emit( c, compile_emit_constant( c, parse->string ), parse->line ); + } + adjust_result( c, RESULT_STACK, result_location ); } else if ( parse->type == PARSE_RULES ) @@ -2840,7 +2958,7 @@ static void type_check_range( OBJECT * type_name, LISTITER iter, LISTITER end, /* Prepare the argument list */ lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) ); - error = evaluate_rule( type_name, frame ); + error = evaluate_rule( bindrule( type_name, frame->module ), type_name, frame ); if ( !list_empty( error ) ) argument_error( object_str( list_front( error ) ), called, caller, @@ -3396,6 +3514,7 @@ FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, 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_MEMBER_RULE: case INSTR_CALL_RULE: ++i; continue; case INSTR_PUSH_MODULE: { @@ -4114,6 +4233,15 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) break; } + case INSTR_CALL_MEMBER_RULE: + { + OBJECT * rule_name = function_get_constant( function, code[1].op_code ); + LIST * result = function_call_member_rule( function, frame, s, code->arg, rule_name, function->file, code[1].arg ); + stack_push( s, result ); + ++code; + break; + } + case INSTR_RULE: function_set_rule( function, frame, s, code->arg ); break; diff --git a/src/engine/headers.c b/src/engine/headers.c index 5dacd1c11..0d9558d5d 100644 --- a/src/engine/headers.c +++ b/src/engine/headers.c @@ -96,9 +96,10 @@ void headers( TARGET * t ) if ( lol_get( frame->args, 1 ) ) { + OBJECT * rulename = list_front( hdrrule ); /* The third argument to HDRRULE is the bound name of $(<). */ lol_add( frame->args, list_new( object_copy( t->boundname ) ) ); - list_free( evaluate_rule( list_front( hdrrule ), frame ) ); + list_free( evaluate_rule( bindrule( rulename, frame->module ), rulename, frame ) ); } /* Clean up. */ diff --git a/src/engine/make1.c b/src/engine/make1.c index 3daa03ab8..71eee1231 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -739,6 +739,7 @@ static void call_timing_rule( TARGET * target, timing_info const * const time ) /* Prepare the argument list. */ FRAME frame[ 1 ]; + OBJECT * rulename = list_front( timing_rule ); frame_init( frame ); /* args * :: $(__TIMING_RULE__[2-]) */ @@ -756,7 +757,7 @@ static void call_timing_rule( TARGET * target, timing_info const * const time ) outf_double( time->system ) ) ); /* Call the rule. */ - evaluate_rule( list_front( timing_rule ), frame ); + evaluate_rule( bindrule( rulename , root_module() ), rulename, frame ); /* Clean up. */ frame_free( frame ); @@ -795,6 +796,7 @@ static void call_action_rule /* Prepare the argument list. */ FRAME frame[ 1 ]; + OBJECT * rulename = list_front( action_rule ); frame_init( frame ); /* args * :: $(__ACTION_RULE__[2-]) */ @@ -822,7 +824,7 @@ static void call_action_rule lol_add( frame->args, L0 ); /* Call the rule. */ - evaluate_rule( list_front( action_rule ), frame ); + evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ); /* Clean up. */ frame_free( frame ); diff --git a/src/engine/modules/sequence.c b/src/engine/modules/sequence.c index f5c4a0378..08ed30599 100644 --- a/src/engine/modules/sequence.c +++ b/src/engine/modules/sequence.c @@ -62,6 +62,7 @@ LIST * sequence_transform( FRAME * frame, int flags ) OBJECT * function_name = list_front( function ); LISTITER args_begin = list_next( list_begin( function ) ), args_end = list_end( function ); LISTITER iter = list_begin( sequence ), end = list_end( sequence ); + RULE * rule = bindrule( function_name, frame->prev->module ); for ( ; iter != end; iter = list_next( iter ) ) { @@ -73,7 +74,7 @@ LIST * sequence_transform( FRAME * frame, int flags ) inner->module = frame->prev->module; lol_add( inner->args, list_push_back( list_copy_range( function, args_begin, args_end ), object_copy( list_item( iter ) ) ) ); - result = list_append( result, evaluate_rule( function_name, inner ) ); + result = list_append( result, evaluate_rule( rule, function_name, inner ) ); frame_free( inner ); } diff --git a/src/engine/search.c b/src/engine/search.c index d363c0453..b2beadaaa 100644 --- a/src/engine/search.c +++ b/src/engine/search.c @@ -54,7 +54,10 @@ void call_bind_rule( OBJECT * target_, OBJECT * boundname_ ) lol_add( frame->args, list_new( boundname ) ); if ( lol_get( frame->args, 1 ) ) - list_free( evaluate_rule( list_front( bind_rule ), frame ) ); + { + OBJECT * rulename = list_front( bind_rule ); + list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) ); + } /* Clean up */ frame_free( frame ); diff --git a/test/core-language/test.jam b/test/core-language/test.jam index c34c3c792..4198dd720 100644 --- a/test/core-language/test.jam +++ b/test/core-language/test.jam @@ -250,6 +250,27 @@ rule bar-x ( new-value ) $(x)-x [ mark-order r1 : [ reset-x reset ] ] : [ mark-order r2 ] ; check-order rule-order : r1 r2 ; +# Cases that look like member calls +rule looks.like-a-member ( args * ) +{ + return $(args) ; +} + +rule call-non-member ( rule + ) +{ + return [ $(rule).like-a-member ] ; +} + +rule call-non-member-with-args ( rule + ) +{ + return [ $(rule).like-a-member a2 ] ; +} + +check-equal rule-non-member : [ call-non-member looks ] : ; +#check-equal rule-non-member-a1 : [ call-non-member looks a1 ] : looks.a1 ; +check-equal rule-non-member-args : [ call-non-member-with-args looks ] : a2 ; +#check-equal rule-non-member-args-a1 : [ call-non-member-with-args looks a1 ] : looks.a1 a2 ; + } # Check append