diff --git a/src/code/README.txt b/src/code/README.txt index 4b2db2073d0ab29b12d16dcb0de12d7bb8299f5f..8ed093ab40cbdc0f55ffed6c3044a3493e46821a 100644 --- a/src/code/README.txt +++ b/src/code/README.txt @@ -192,6 +192,13 @@ OPCODE_INLINE_BRANCH value for those opcodes and jump iff it's nonzero. This is to facilitate easier inlining of branches in the machine code. +OPCODE_INLINE_RETURN + If defined, opcode functions that perform INTER_RETURN will + return (void *)(ptrdiff_t)-1 when they want to exit from + the running interpreter. These opcodes also have the I_RETURN + flag set. This is to facilitate easier use of and clean up + of INS_ENTRY(). + OPCODE_RETURN_JUMPADDR If defined, jump functions that return the address to jump to will be generated for I_JUMP instructions, so the ins_f_byte* diff --git a/src/interpret.c b/src/interpret.c index 71de6b44ebf7ec50cc5a95f7944c5d46dffb582b..d67f21fcd08db971b568d2bb58af45777f44e597 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -1107,10 +1107,177 @@ static int catching_eval_instruction (PIKE_OPCODE_T *pc); #ifdef PIKE_USE_MACHINE_CODE +#ifdef OPCODE_INLINE_RETURN +/* Catch notes: + * + * Typical F_CATCH use: + * + * F_CATCH + * F_PTR continue_label + * + * ENTRY + * + * catch body + * + * F_EXIT_CATCH + * + * F_BRANCH + * F_PTR continue_label + * + * ENTRY + * + * continue_label: + * + * rest of code. + */ + +/* Modified calling-conventions to simplify code-generation when + * INTER_RETURN is inlined. + * + * cf interpret_functions.h:F_CATCH + * + * Arguments: + * addr: + * Entry-point for the catch block. + * + * continue_addr: + * Offset from addr for code after the catch (and after ENTRY). + * + * Returns: + * (PIKE_OPCODE_T *)-1 on INTER_RETURN. + * jump_destination otherwise. + */ +PIKE_OPCODE_T *inter_return_opcode_F_CATCH(PIKE_OPCODE_T *addr, + INT32 continue_addr) +{ + if (d_flag || Pike_interpreter.trace_level > 2) { + low_debug_instr_prologue (F_CATCH - F_OFFSET); + if (Pike_interpreter.trace_level>3) { + sprintf(trace_buffer, + "- Addr = %p\n" + "- Continue = 0x%ld\n", + addr, continue_addr); + write_to_stderr(trace_buffer,strlen(trace_buffer)); + } + } + { + struct catch_context *new_catch_ctx = alloc_catch_context(); +#ifdef PIKE_DEBUG + new_catch_ctx->frame = Pike_fp; + init_recovery (&new_catch_ctx->recovery, 0, 0, PERR_LOCATION()); +#else + init_recovery (&new_catch_ctx->recovery, 0); +#endif + new_catch_ctx->save_expendible = Pike_fp->expendible; + new_catch_ctx->continue_reladdr = continue_addr + /* We need to run the entry prologue... */ + - ENTRY_PROLOGUE_SIZE; + + new_catch_ctx->next_addr = addr; + new_catch_ctx->prev = Pike_interpreter.catch_ctx; + Pike_interpreter.catch_ctx = new_catch_ctx; + DO_IF_DEBUG({ + TRACE((3,"- Pushed catch context %p\n", new_catch_ctx)); + }); + } + + Pike_fp->expendible = Pike_fp->locals + Pike_fp->num_locals; + +#if 0 + /* Need to adjust next_addr by sizeof(INT32) to skip past the jump + * address to the continue position after the catch block. */ + addr = (PIKE_OPCODE_T *) ((INT32 *) addr + 1); +#endif + + if (Pike_interpreter.catching_eval_jmpbuf) { + /* There's already a catching_eval_instruction around our + * eval_instruction, so we can just continue. */ + debug_malloc_touch_named (Pike_interpreter.catch_ctx, "(1)"); + /* Skip past the entry prologue... */ + addr += ENTRY_PROLOGUE_SIZE; + DO_IF_DEBUG({ + TRACE((3,"- In active catch; continuing at %p\n", addr)); + }); + return addr; + } + else { + debug_malloc_touch_named (Pike_interpreter.catch_ctx, "(2)"); + + while (1) { + /* Loop here every time an exception is caught. Once we've + * gotten here and set things up to run eval_instruction from + * inside catching_eval_instruction, we keep doing it until it's + * time to return. */ + + int res; + + DO_IF_DEBUG({ + TRACE((3,"- Activating catch; calling %p in context %p\n", + addr, Pike_interpreter.catch_ctx)); + }); + + res = catching_eval_instruction (addr); + + DO_IF_DEBUG({ + TRACE((3,"- catching_eval_instruction(%p) returned %d\n", + addr, res)); + }); + + if (res != -3) { + /* There was an inter return inside the evaluated code. Just + * propagate it. */ + DO_IF_DEBUG ({ + TRACE((3,"- Returning from catch.\n")); + if (res != -1) Pike_fatal ("Unexpected return value from " + "catching_eval_instruction: %d\n", res); + }); + break; + } + + else { + /* Caught an exception. */ + struct catch_context *cc = Pike_interpreter.catch_ctx; + + DO_IF_DEBUG ({ + TRACE((3,"- Caught exception. catch context: %p\n", cc)); + if (!cc) Pike_fatal ("Catch context dropoff.\n"); + if (cc->frame != Pike_fp) + Pike_fatal ("Catch context doesn't belong to this frame.\n"); + }); + + debug_malloc_touch_named (cc, "(3)"); + UNSETJMP (cc->recovery); + Pike_fp->expendible = cc->save_expendible; + move_svalue (Pike_sp++, &throw_value); + mark_free_svalue (&throw_value); + low_destruct_objects_to_destruct(); + + if (cc->continue_reladdr < 0) + FAST_CHECK_THREADS_ON_BRANCH(); + addr = cc->next_addr + cc->continue_reladdr; + + DO_IF_DEBUG({ + TRACE((3,"- Popping catch context %p ==> %p\n", + cc, cc->prev)); + if (!addr) Pike_fatal ("Unexpected null continue addr.\n"); + }); + + Pike_interpreter.catch_ctx = cc->prev; + really_free_catch_context (cc); + } + } + + return (PIKE_OPCODE_T *)(ptrdiff_t)-1; /* INTER_RETURN; */ + } +} + +void *do_inter_return_label = (void*)(ptrdiff_t)-1; +#else /* Labels to jump to to cause eval_instruction to return */ /* FIXME: Replace these with assembler lables */ void *do_inter_return_label = NULL; void *dummy_label = NULL; +#endif #ifndef CALL_MACHINE_CODE #define CALL_MACHINE_CODE(pc) \ @@ -1280,8 +1447,8 @@ C } #if defined(OPCODE_INLINE_BRANCH) || defined(PIKE_SMALL_EVAL_INSTRUCTION) #define TEST_OPCODE0(O,N,F,C) \ -int PIKE_CONCAT(test_opcode_,O)(void) { \ - int branch_taken = 0; \ +ptrdiff_t PIKE_CONCAT(test_opcode_,O)(void) { \ + ptrdiff_t branch_taken = 0; \ DEF_PROG_COUNTER; \ DEBUG_PROLOGUE (O, ;); \ C; \ @@ -1289,8 +1456,8 @@ int PIKE_CONCAT(test_opcode_,O)(void) { \ } #define TEST_OPCODE1(O,N,F,C) \ -int PIKE_CONCAT(test_opcode_,O)(INT32 arg1) {\ - int branch_taken = 0; \ +ptrdiff_t PIKE_CONCAT(test_opcode_,O)(INT32 arg1) {\ + ptrdiff_t branch_taken = 0; \ DEF_PROG_COUNTER; \ DEBUG_PROLOGUE (O, DEBUG_LOG_ARG (arg1)); \ C; \ @@ -1299,8 +1466,8 @@ int PIKE_CONCAT(test_opcode_,O)(INT32 arg1) {\ #define TEST_OPCODE2(O,N,F,C) \ -int PIKE_CONCAT(test_opcode_,O)(INT32 arg1, INT32 arg2) { \ - int branch_taken = 0; \ +ptrdiff_t PIKE_CONCAT(test_opcode_,O)(INT32 arg1, INT32 arg2) { \ + ptrdiff_t branch_taken = 0; \ DEF_PROG_COUNTER; \ DEBUG_PROLOGUE (O, DEBUG_LOG_ARG (arg1); DEBUG_LOG_ARG2 (arg2)); \ C; \ @@ -1326,9 +1493,9 @@ int PIKE_CONCAT(test_opcode_,O)(INT32 arg1, INT32 arg2) { \ #define OPCODE1_TAILPTRJUMP(O,N,F,C) OPCODE1_PTRJUMP(O,N,F,C) #define OPCODE2_TAILPTRJUMP(O,N,F,C) OPCODE2_PTRJUMP(O,N,F,C) -#define OPCODE0_RETURN(O,N,F,C) OPCODE0_JUMP(O,N,F,C) -#define OPCODE1_RETURN(O,N,F,C) OPCODE1_JUMP(O,N,F,C) -#define OPCODE2_RETURN(O,N,F,C) OPCODE2_JUMP(O,N,F,C) +#define OPCODE0_RETURN(O,N,F,C) OPCODE0_JUMP(O,N,F | I_RETURN,C) +#define OPCODE1_RETURN(O,N,F,C) OPCODE1_JUMP(O,N,F | I_RETURN,C) +#define OPCODE2_RETURN(O,N,F,C) OPCODE2_JUMP(O,N,F | I_RETURN,C) #define OPCODE0_TAILRETURN(O,N,F,C) OPCODE0_RETURN(O,N,F,C) #define OPCODE1_TAILRETURN(O,N,F,C) OPCODE1_RETURN(O,N,F,C) #define OPCODE2_TAILRETURN(O,N,F,C) OPCODE2_RETURN(O,N,F,C) @@ -1427,6 +1594,7 @@ static int eval_instruction_low(PIKE_OPCODE_T *pc) { if(pc == NULL) { +#ifndef OPCODE_INLINE_RETURN if(do_inter_return_label != NULL) Pike_fatal("eval_instruction called with NULL (twice).\n"); @@ -1458,6 +1626,7 @@ static int eval_instruction_low(PIKE_OPCODE_T *pc) /* Trick optimizer */ if(!dummy_label) return 0; +#endif /* !OPCODE_INLINE_RETURN */ } /* This else is important to avoid an overoptimization bug in (at @@ -1475,6 +1644,7 @@ static int eval_instruction_low(PIKE_OPCODE_T *pc) #endif } +#ifndef OPCODE_INLINE_RETURN #ifdef __GNUC__ goto *dummy_label; #endif @@ -1487,6 +1657,7 @@ static int eval_instruction_low(PIKE_OPCODE_T *pc) } #endif +#endif /* !OPCODE_INLINE_RETURN */ inter_return_label: EXIT_MACHINE_CODE(); #ifdef PIKE_DEBUG diff --git a/src/interpret.h b/src/interpret.h index aac3f258a70a796b302cd2ba3af79631637949ea..bc10d6cbee364e736ac13bdb2a2cb43903c42d3e 100644 --- a/src/interpret.h +++ b/src/interpret.h @@ -775,6 +775,10 @@ void call_check_threads_etc(); defined(INS_F_JUMP_WITH_ARG) || defined(INS_F_JUMP_WITH_TWO_ARGS) void branch_check_threads_etc(); #endif +#ifdef OPCODE_INLINE_RETURN +PIKE_OPCODE_T *inter_return_opcode_F_CATCH(PIKE_OPCODE_T *addr, + INT32 continue_addr); +#endif #ifdef PIKE_DEBUG void simple_debug_instr_prologue_0 (PIKE_INSTR_T instr); void simple_debug_instr_prologue_1 (PIKE_INSTR_T instr, INT32 arg); diff --git a/src/interpret_functions.h b/src/interpret_functions.h index 8c08df44a7d556e316209cdc492c332739f4fb78..e995a1887d1e8f8ccf75a063708892ef391ad5f4 100644 --- a/src/interpret_functions.h +++ b/src/interpret_functions.h @@ -1312,7 +1312,7 @@ OPCODE0_BRANCH(F_EQ_AND, "==&&", I_UPDATE_SP, { /* Ideally this ought to be an OPCODE0_PTRRETURN but I don't fancy * adding that variety to this macro hell. At the end of the day there * wouldn't be any difference anyway afaics. /mast */ -OPCODE0_PTRJUMP(F_CATCH, "catch", I_UPDATE_ALL, { +OPCODE0_PTRJUMP(F_CATCH, "catch", I_UPDATE_ALL|I_RETURN, { PIKE_OPCODE_T *addr; { diff --git a/src/interpreter.h b/src/interpreter.h index 93578542f448b621b7416bf835794b7f9b67a41c..388bcbb55468f56a6288e9467372d18fe60b9f26 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -191,12 +191,12 @@ static int eval_instruction(PIKE_OPCODE_T *pc) #define OPCODE1_TAILJUMP OPCODE1_TAIL #define OPCODE2_TAILJUMP OPCODE2_TAIL -#define OPCODE0_RETURN(OP, DESC, FLAGS, CODE) OPCODE0(OP, DESC, FLAGS, CODE) -#define OPCODE1_RETURN(OP, DESC, FLAGS, CODE) OPCODE1(OP, DESC, FLAGS, CODE) -#define OPCODE2_RETURN(OP, DESC, FLAGS, CODE) OPCODE2(OP, DESC, FLAGS, CODE) -#define OPCODE0_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE0_TAIL(OP, DESC, FLAGS, CODE) -#define OPCODE1_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE1_TAIL(OP, DESC, FLAGS, CODE) -#define OPCODE2_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE2_TAIL(OP, DESC, FLAGS, CODE) +#define OPCODE0_RETURN(OP, DESC, FLAGS, CODE) OPCODE0(OP, DESC, FLAGS | I_RETURN, CODE) +#define OPCODE1_RETURN(OP, DESC, FLAGS, CODE) OPCODE1(OP, DESC, FLAGS | I_RETURN, CODE) +#define OPCODE2_RETURN(OP, DESC, FLAGS, CODE) OPCODE2(OP, DESC, FLAGS | I_RETURN, CODE) +#define OPCODE0_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE0_TAIL(OP, DESC, FLAGS | I_RETURN, CODE) +#define OPCODE1_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE1_TAIL(OP, DESC, FLAGS | I_RETURN, CODE) +#define OPCODE2_TAILRETURN(OP, DESC, FLAGS, CODE) OPCODE2_TAIL(OP, DESC, FLAGS | I_RETURN, CODE) #define OPCODE0_PTRJUMP(OP, DESC, FLAGS, CODE) CASE(OP); CODE; DONE #define OPCODE0_TAILPTRJUMP(OP, DESC, FLAGS, CODE) CASE(OP); CODE diff --git a/src/opcodes.c b/src/opcodes.c index f16d09cffd2ff789416aa02e6ab329461a9f5831..f5f327bbf134fc21e6b4e221321f84d9536908d1 100644 --- a/src/opcodes.c +++ b/src/opcodes.c @@ -114,18 +114,18 @@ void present_runned(struct instr_counter *d, int depth, int maxdepth) #define OPCODE1_PTRJUMP(OP,DESC,FLAGS) OPCODE1_JUMP(OP, DESC, FLAGS) #define OPCODE2_PTRJUMP(OP,DESC,FLAGS) OPCODE2_JUMP(OP, DESC, FLAGS) -#define OPCODE0_RETURN(OP,DESC,FLAGS) OPCODE0_JUMP(OP, DESC, FLAGS) -#define OPCODE1_RETURN(OP,DESC,FLAGS) OPCODE1_JUMP(OP, DESC, FLAGS) -#define OPCODE2_RETURN(OP,DESC,FLAGS) OPCODE2_JUMP(OP, DESC, FLAGS) +#define OPCODE0_RETURN(OP,DESC,FLAGS) OPCODE0_JUMP(OP, DESC, FLAGS | I_RETURN) +#define OPCODE1_RETURN(OP,DESC,FLAGS) OPCODE1_JUMP(OP, DESC, FLAGS | I_RETURN) +#define OPCODE2_RETURN(OP,DESC,FLAGS) OPCODE2_JUMP(OP, DESC, FLAGS | I_RETURN) #define OPCODE0_ALIAS(OP, DESC, FLAGS, ADDR) #define OPCODE1_ALIAS(OP, DESC, FLAGS, ADDR) #define OPCODE2_ALIAS(OP, DESC, FLAGS, ADDR) #ifdef OPCODE_INLINE_BRANCH -#define OPCODE0_BRANCH(OP,DESC,FLAGS) int PIKE_CONCAT(test_opcode_,OP)(void); -#define OPCODE1_BRANCH(OP,DESC,FLAGS) int PIKE_CONCAT(test_opcode_,OP)(INT32); -#define OPCODE2_BRANCH(OP,DESC,FLAGS) int PIKE_CONCAT(test_opcode_,OP)(INT32,INT32); +#define OPCODE0_BRANCH(OP,DESC,FLAGS) ptrdiff_t PIKE_CONCAT(test_opcode_,OP)(void); +#define OPCODE1_BRANCH(OP,DESC,FLAGS) ptrdiff_t PIKE_CONCAT(test_opcode_,OP)(INT32); +#define OPCODE2_BRANCH(OP,DESC,FLAGS) ptrdiff_t PIKE_CONCAT(test_opcode_,OP)(INT32,INT32); #define BRANCHADDR(X) , (void *)PIKE_CONCAT(test_opcode_,X) #else /* !OPCODE_INLINE_BRANCH */ #define OPCODE0_BRANCH OPCODE0_PTRJUMP @@ -220,9 +220,9 @@ void present_runned(struct instr_counter *d, int depth, int maxdepth) #define OPCODE1_TAILJUMP(OP, DESC, FLAGS) OPCODE1_JUMP(OP,DESC,FLAGS) #define OPCODE2_TAILJUMP(OP, DESC, FLAGS) OPCODE2_JUMP(OP,DESC,FLAGS) -#define OPCODE0_RETURN(OP, DESC, FLAGS) OPCODE0_JUMP(OP,DESC,FLAGS) -#define OPCODE1_RETURN(OP, DESC, FLAGS) OPCODE1_JUMP(OP,DESC,FLAGS) -#define OPCODE2_RETURN(OP, DESC, FLAGS) OPCODE2_JUMP(OP,DESC,FLAGS) +#define OPCODE0_RETURN(OP, DESC, FLAGS) OPCODE0_JUMP(OP,DESC,FLAGS | I_RETURN) +#define OPCODE1_RETURN(OP, DESC, FLAGS) OPCODE1_JUMP(OP,DESC,FLAGS | I_RETURN) +#define OPCODE2_RETURN(OP, DESC, FLAGS) OPCODE2_JUMP(OP,DESC,FLAGS | I_RETURN) #define OPCODE0_TAILRETURN(OP, DESC, FLAGS) OPCODE0_RETURN(OP,DESC,FLAGS) #define OPCODE1_TAILRETURN(OP, DESC, FLAGS) OPCODE1_RETURN(OP,DESC,FLAGS) #define OPCODE2_TAILRETURN(OP, DESC, FLAGS) OPCODE2_RETURN(OP,DESC,FLAGS) diff --git a/src/opcodes.h b/src/opcodes.h index 4d4f801768f9bf1156cba014fc617ff34d5c297c..956ef539f656ce1065317eddb87e1a16a6947f99 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -50,6 +50,8 @@ struct keyword #define I_UPDATE_FP 512 /* Opcode modifies Pike_fp */ #define I_UPDATE_M_SP 1024 /* Opcode modifies Pike_mark_sp */ +#define I_RETURN 2048 /* Opcode may return to the previous frame. */ + /* Convenience variants */ #define I_TWO_ARGS (I_HASARG | I_HASARG2) #define I_DATA (I_HASARG | I__DATA)