[UPDATED: patch actually attached this time] All -- I am attaching a revised op tracing patch based on the feedback I got. Its features are: * Provides macros in interp_guts.h for setting up arrays with op names and op arg counts (done via build_interp_starter.pl). These are used in the op tracing * The functions in bytecode.[hc] pass around a pointer to the length of the bytecode so that later when we get to runops, we know how much bytecode we've got and we can detect out-of-bounds jumping. The documentation is updated, too. * runops in interpreter.c now looks at interpreter->flags to decide if the core of runops should be runops_trace_core or runops_notrace_core. These new functions contain just the while-loop portion of runops. A new function runops_generic does any other setup (such as checking the bytecode fingerprint) or wrapup (such as complaining if we ended up out-of-bounds). NOTE: I didn't know what we should do for functions in here that are not part of the api, so I gave them docs with 'TODO' marks mentioning they really aren't part of the api. Guidance appreciated. * test_main.c now checks for '-t' arg and sets the tracing flag on its interpreter instance as appropriate. I'd like to commit this soon to clear out my sandbox so I can go back and re-commit the constant comparison ops. So, if there aren't any objections... Regards, -- Gregor _____________________________________________________________________ / perl -e 'srand(-2091643526); print chr rand 90 for (0..4)' \ Gregor N. Purdy [EMAIL PROTECTED] Focus Research, Inc. http://www.focusresearch.com/ 8080 Beckett Center Drive #203 513-860-3570 vox West Chester, OH 45069 513-860-3579 fax \_____________________________________________________________________/
Index: build_interp_starter.pl =================================================================== RCS file: /home/perlcvs/parrot/build_interp_starter.pl,v retrieving revision 1.6 diff -u -r1.6 build_interp_starter.pl --- build_interp_starter.pl 2001/09/15 16:05:40 1.6 +++ build_interp_starter.pl 2001/09/17 16:25:56 @@ -26,7 +26,39 @@ } print INTERP "} while (0);\n"; + +# +# BUILD_NAME_TABLE macro: +# + +print INTERP <<CONST; +#define BUILD_NAME_TABLE(x) do { \\ +CONST + +for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) { + print INTERP "\tx[$opcodes{$name}{CODE}] = \"$name\"; \\\n"; +} +print INTERP "} while (0);\n"; + + +# +# BUILD_ARG_TABLE macro: +# + +print INTERP <<CONST; +#define BUILD_ARG_TABLE(x) do { \\ +CONST + +for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) { + print INTERP "\tx[$opcodes{$name}{CODE}] = $opcodes{$name}{ARGS}; \\\n"; +} +print INTERP "} while (0);\n"; + + +# # Spit out the DO_OP function +# + print INTERP <<EOI; #define DO_OP(w,x,y,z) do { \\ Index: bytecode.c =================================================================== RCS file: /home/perlcvs/parrot/bytecode.c,v retrieving revision 1.9 diff -u -r1.9 bytecode.c --- bytecode.c 2001/09/16 01:45:50 1.9 +++ bytecode.c 2001/09/17 16:25:57 @@ -37,19 +37,21 @@ =item C<check_magic> - Args: void** program_code + Args: void** program_code, long* program_size -Check to see if the first C<long> in C<*program_code> +Check to see if the first C<IV> in C<*program_code> matches the Parrot magic number for bytecode; return 1 if so, and 0 if not. This function is expected to advance -the C<*program_code> pointer beyond the magic number. +the C<*program_code> pointer beyond the magic number. It +also decrements C<*program_size> by the same amount. =cut */ static int -check_magic(void** program_code) { +check_magic(void** program_code, long* program_size) { + program_size -= sizeof(IV); return (GRAB_IV(program_code) == PARROT_MAGIC); } @@ -57,24 +59,27 @@ =item C<read_constants_table> - Args: void** program_code + Args: void** program_code, long* program_size Reads the constants segment from C<*program_code>, and creates the referenced constants. See L<parrotbyte/Constants Segment> for the structure of the constants segment. Advances -C<*program_code> beyond the constants segment. +C<*program_code> beyond the constants segment and decrements +C<*program_size> byt the amount consumed. =cut */ static void -read_constants_table(void** program_code) +read_constants_table(void** program_code, long* program_size) { IV len = GRAB_IV(program_code); IV num; IV i = 0; + *program_size -= sizeof(IV); + Parrot_num_string_constants = len; if (len == 0) { return; @@ -82,6 +87,7 @@ num = GRAB_IV(program_code); len -= sizeof(IV); + *program_size -= sizeof(IV); Parrot_string_constants = mem_allocate_aligned(num * sizeof(STRING*)); @@ -93,10 +99,12 @@ int pad; len -= 4 * sizeof(IV); + *program_size -= 4 * sizeof(IV); Parrot_string_constants[i++] = string_make(*program_code /* ouch */, buflen, encoding, flags, type); (char*)*program_code += buflen; len -= buflen; + *program_size -= buflen; /* Padding */ pad=buflen % sizeof(IV); @@ -104,6 +112,7 @@ pad=sizeof(IV)-pad; len -= pad; (char*)*program_code += pad; + *program_size -= pad; } num--; if (len < 0 || (len > 0 && num == 0)) { @@ -129,18 +138,20 @@ */ static void -read_fixup_table(void** program_code) +read_fixup_table(void** program_code, long* program_size) { IV len = GRAB_IV(program_code); + *program_size -= sizeof(IV); /* For now, just skip over it */ ((IV*)*program_code) += len; + *program_size -= len; } /* =item C<init_bytecode> - Args: void* program_code + Args: void* program_code, long* program_size This function is responsible for calling the above three functions, exiting if the Parrot magic is not found, and @@ -152,15 +163,15 @@ */ void * -init_bytecode(void* program_code) +init_bytecode(void* program_code, long* program_size) { - if (!check_magic(&program_code)) { + if (!check_magic(&program_code, program_size)) { printf("This isn't Parrot bytecode!\n"); exit(1); } - read_fixup_table(&program_code); - read_constants_table(&program_code); + read_fixup_table(&program_code, program_size); + read_constants_table(&program_code, program_size); return program_code; } Index: bytecode.h =================================================================== RCS file: /home/perlcvs/parrot/bytecode.h,v retrieving revision 1.5 diff -u -r1.5 bytecode.h --- bytecode.h 2001/09/17 14:51:33 1.5 +++ bytecode.h 2001/09/17 16:25:57 @@ -14,7 +14,7 @@ #define PARROT_BYTECODE_H_GUARD void* -init_bytecode(void* program_code); +init_bytecode(void* program_code, long* program_size); VAR_SCOPE IV Parrot_num_string_constants; VAR_SCOPE STRING** Parrot_string_constants; Index: interpreter.c =================================================================== RCS file: /home/perlcvs/parrot/interpreter.c,v retrieving revision 1.12 diff -u -r1.12 interpreter.c --- interpreter.c 2001/09/17 12:56:55 1.12 +++ interpreter.c 2001/09/17 16:25:57 @@ -13,18 +13,17 @@ #include "parrot/parrot.h" #include "parrot/interp_guts.h" -/*=for api interpreter runops - * run parrot operations until the program is complete +char *op_names[2048]; +int op_args[2048]; + +/*=for api interpreter check_fingerprint + * TODO: Not really part of the API, but here's the docs. + * Check the bytecode's opcode table fingerprint. */ void -runops (struct Parrot_Interp *interpreter, IV *code) { - /* Move these out of the inner loop. No need to redeclare 'em each - time through */ - IV *(*func)(); - void **temp; - +check_fingerprint(void) { if (Parrot_num_string_constants == 0) { - printf("Warning: Bytecode does not include opcode table fingerprint!\n"); + fprintf(stderr, "Warning: Bytecode does not include opcode table +fingerprint!\n"); } else { const char * fp_data; IV fp_len; @@ -33,18 +32,120 @@ fp_len = Parrot_string_constants[0]->buflen; if (strncmp(OPCODE_FINGERPRINT, fp_data, fp_len)) { - printf("Error: Opcode table fingerprint in bytecode does not match interpreter!\n"); - printf(" Bytecode: %*s\n", -fp_len, fp_data); - printf(" Interpreter: %s\n", OPCODE_FINGERPRINT); + fprintf(stderr, "Error: Opcode table fingerprint in bytecode does not +match interpreter!\n"); + fprintf(stderr, " Bytecode: %*s\n", -fp_len, fp_data); + fprintf(stderr, " Interpreter: %s\n", OPCODE_FINGERPRINT); exit(1); } } +} - while (*code) { +/*=for api interpreter runops + * run parrot operations until the program is complete + */ +IV * +runops_notrace_core (struct Parrot_Interp *interpreter, IV *code, IV code_size) { + /* Move these out of the inner loop. No need to redeclare 'em each + time through */ + IV *(*func)(); + void **temp; + IV *code_start; + + code_start = code; + + while (code >= code_start && code < (code_start + code_size) && *code) { DO_OP(code, temp, func, interpreter); } + + return code; } +/* + *=for api interpreter trace_op + * TODO: This isn't really part of the API, but here's its documentation. Prints the +PC, OP + * and ARGS. Used by runops_trace. + */ +void +trace_op(IV * code_start, long code_size, IV *code) { + int i; + + if (code >= code_start && code < (code_start + code_size)) { + fprintf(stderr, "PC=%ld; OP=%ld (%s)", code - code_start, *code, +op_names[*code]); + if (op_args[*code]) { + fprintf(stderr, "; ARGS=("); + for(i = 0; i < op_args[*code]; i++) { + if (i) { fprintf(stderr, ", "); } + fprintf(stderr, "%ld", *(code + i + 1)); + } + fprintf(stderr, ")"); + } + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "PC=%ld; OP=<err>\n", code - code_start); + } +} + +/*=for api interpreter runops_trace_core + * TODO: Not really part of the API, but here's the docs. + * Passed to runops_generic() by runops_trace(). + */ +IV * +runops_trace_core (struct Parrot_Interp *interpreter, IV *code, IV code_size) { + /* Move these out of the inner loop. No need to redeclare 'em each + time through */ + IV *(*func)(); + void **temp; + IV *code_start; + + code_start = code; + + trace_op(code_start, code_size, code); + + while (code >= code_start && code < (code_start + code_size) && *code) { + DO_OP(code, temp, func, interpreter); + + trace_op(code_start, code_size, code); + } + + return code; +} + +/*=for api interpreter runops_generic + * TODO: Not really part of the API, but here's the docs. + * Generic runops, which takes a function pointer for the core. + */ +void +runops_generic (IV * (*core)(struct Parrot_Interp *, IV *, IV), struct Parrot_Interp +*interpreter, IV *code, IV code_size) { + IV * code_start; + + check_fingerprint(); + + code_start = code; + code = core(interpreter, code, code_size); + + if (code < code_start || code >= (code_start + code_size)) { + fprintf(stderr, "Error: Control left bounds of byte-code block (now at +location %d)!\n", code - code_start); + exit(1); + } +} + + +/*=for api interpreter runops + * run parrot operations until the program is complete + */ +void +runops (struct Parrot_Interp *interpreter, IV *code, IV code_size) { + IV * (*core)(struct Parrot_Interp *, IV *, IV); + + if (interpreter->flags & PARROT_TRACE_FLAG) { + core = runops_trace_core; + } else { + core = runops_notrace_core; + } + + runops_generic(core, interpreter, code, code_size); +} + /*=for api interpreter make_interpreter * Create the Parrot interpreter. Allocate memory and clear the registers. */ @@ -111,6 +212,9 @@ BUILD_TABLE(foo); interpreter->opcode_funcs = (void*)foo; + + BUILD_NAME_TABLE(op_names); + BUILD_ARG_TABLE(op_args); } /* In case the I/O system needs something */ Index: interpreter.h =================================================================== RCS file: /home/perlcvs/parrot/interpreter.h,v retrieving revision 1.7 diff -u -r1.7 interpreter.h --- interpreter.h 2001/09/17 15:15:31 1.7 +++ interpreter.h 2001/09/17 16:25:57 @@ -46,7 +46,7 @@ make_interpreter(); void -runops(struct Parrot_Interp *, IV *); +runops(struct Parrot_Interp *, IV *, IV); #endif Index: test_main.c =================================================================== RCS file: /home/perlcvs/parrot/test_main.c,v retrieving revision 1.8 diff -u -r1.8 test_main.c --- test_main.c 2001/09/16 22:05:21 1.8 +++ test_main.c 2001/09/17 16:25:57 @@ -27,14 +27,29 @@ int main(int argc, char **argv) { + int i; + int tracing; + struct Parrot_Interp *interpreter; init_world(); interpreter = make_interpreter(); + /* Look for the '-t' tracing switch. We really should use getopt, but are we +allowed? */ + + if (argc > 1 && strcmp(argv[1], "-t") == 0) { + tracing = 1; + for(i = 2; i < argc; i++) { + argv[i-1] = argv[i]; + } + argc--; + } else { + tracing = 0; + } + /* If we got only the program name, run the test program */ if (argc == 1) { - runops(interpreter, opcodes); + runops(interpreter, opcodes, sizeof(opcodes)); } else if (argc == 2 && !strcmp(argv[1], "-s")) { /* String tests */ STRING *s = string_make("foo", 3, enc_native, 0, 0); @@ -60,8 +75,10 @@ /* Otherwise load in the program they gave and try that */ else { void *program_code; + long program_size; struct stat file_stat; int fd; + if (stat(argv[1], &file_stat)) { printf("can't stat %s, code %i\n", argv[1], errno); return 1; @@ -72,20 +89,27 @@ return 1; } + program_size = file_stat.st_size; + #ifndef HAS_HEADER_SYSMMAN - program_code = mem_sys_allocate(file_stat.st_size); - _read(fd, program_code, file_stat.st_size); + program_code = mem_sys_allocate(program_size); + _read(fd, program_code, program_size); #else - program_code = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED, fd, 0); + program_code = mmap(0, program_size, PROT_READ, MAP_SHARED, fd, 0); #endif + if (!program_code) { printf("Can't mmap, code %i\n", errno); return 1; } - program_code = init_bytecode(program_code); + program_code = init_bytecode(program_code, &program_size); - runops(interpreter, program_code); + if (tracing) { + interpreter->flags |= PARROT_TRACE_FLAG; + } + + runops(interpreter, program_code, program_size); } return 0;