2006-02-27
2006-02-27 12:07:10 by Martin Stjernholm <mast@lysator.liu.se>
-
ca176b0af90a346195639cc885cbe558a13e9cf6
(159 lines)
(+98/-61)
[
Show
| Annotate
]
Branch: 7.9
Avoid C stack recursion in catch blocks.
Rev: src/docode.c:1.185
Rev: src/error.c:1.144
Rev: src/interpret.c:1.368
Rev: src/interpret.h:1.165
Rev: src/interpret_functions.h:1.187
Rev: src/pike_embed.c:1.7
Rev: src/pike_error.h:1.37
Rev: src/version.h:1.383
2:
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
- || $Id: interpret.c,v 1.367 2006/01/24 12:03:19 mast Exp $
+ || $Id: interpret.c,v 1.368 2006/02/27 12:07:10 mast Exp $
*/
#include "global.h"
179:
*
* Returns -1 if the code terminated due to a RETURN.
*
- * Returns -2 if the code terminated due to EXIT_CATCH or ESCAPE_CATCH.
+ * Note: All callers except catching_eval_instruction need to save
+ * Pike_interpreter.catching_eval_jmpbuf, zero it, and restore it
+ * afterwards.
*/
static int eval_instruction(PIKE_OPCODE_T *pc);
266:
interpreter->stack_pointer = interpreter->evaluator_stack;
interpreter->mark_stack_pointer = interpreter->mark_stack;
interpreter->frame_pointer = 0;
+ interpreter->catch_ctx = NULL;
+ interpreter->catching_eval_jmpbuf = NULL;
interpreter->svalue_stack_margin = SVALUE_STACK_MARGIN;
interpreter->c_stack_margin = C_STACK_MARGIN;
825:
{
Pike_fp=0;
pop_n_elems(Pike_sp - Pike_interpreter.evaluator_stack);
+
+ #ifdef PIKE_DEBUG
+ if (Pike_interpreter.catch_ctx)
+ Pike_fatal ("Catch context spillover.\n");
+ if (Pike_interpreter.catching_eval_jmpbuf)
+ Pike_fatal ("Got an active catching_eval_jmpbuf.\n");
+ #endif
}
#ifdef PIKE_DEBUG
1059:
#endif /* !PIKE_DEBUG */
- static int o_catch(PIKE_OPCODE_T *pc);
+ #undef BLOCK_ALLOC_NEXT
+ #define BLOCK_ALLOC_NEXT prev
-
+ BLOCK_ALLOC_FILL_PAGES (catch_context, 1)
- #ifdef PIKE_DEBUG
- #define EVAL_INSTR_RET_CHECK(x) \
- if (x == -2) \
- Pike_fatal("Return value -2 from eval_instruction is not handled here.\n"\
- "Probable cause: F_ESCAPE_CATCH outside catch block.\n")
- #else
- #define EVAL_INSTR_RET_CHECK(x)
- #endif
+ #define POP_CATCH_CONTEXT do { \
+ struct catch_context *cc = Pike_interpreter.catch_ctx; \
+ DO_IF_DEBUG ( \
+ if (!Pike_interpreter.catching_eval_jmpbuf) \
+ Pike_fatal ("Not in catching eval.\n"); \
+ if (!cc) \
+ Pike_fatal ("Catch context dropoff.\n"); \
+ if (cc->frame != Pike_fp) \
+ Pike_fatal ("Catch context doesn't belong to this frame.\n"); \
+ if (Pike_mark_sp != cc->recovery.mark_sp + Pike_interpreter.mark_stack) \
+ Pike_fatal ("Mark sp diff in catch context pop.\n"); \
+ ); \
+ debug_malloc_touch (cc); \
+ UNSETJMP (cc->recovery); \
+ Pike_fp->expendible = cc->save_expendible; \
+ Pike_interpreter.catch_ctx = cc->prev; \
+ really_free_catch_context (cc); \
+ } while (0)
-
+ static int catching_eval_instruction (PIKE_OPCODE_T *pc);
-
+
#ifdef PIKE_USE_MACHINE_CODE
/* Labels to jump to to cause eval_instruction to return */
/* FIXME: Replace these with assembler lables */
void *do_inter_return_label = NULL;
- void *do_escape_catch_label;
+
void *dummy_label = NULL;
#ifndef CALL_MACHINE_CODE
1146:
#endif /* PIKE_USE_MACHINE_CODE */
+ /* These don't change when eval_instruction_without_debug is compiled. */
+ #ifdef PIKE_DEBUG
+ #define REAL_PIKE_DEBUG
+ #define DO_IF_REAL_DEBUG(X) X
+ #define DO_IF_NOT_REAL_DEBUG(X)
+ #else
+ #define DO_IF_REAL_DEBUG(X)
+ #define DO_IF_NOT_REAL_DEBUG(X) X
+ #endif
+
#ifdef PIKE_SMALL_EVAL_INSTRUCTION
#undef PROG_COUNTER
#define PROG_COUNTER Pike_fp->pc+1
1309:
#undef DONE
#undef FETCH
#undef INTER_RETURN
- #undef INTER_ESCAPE_CATCH
+
#define DONE return
#define FETCH
#define INTER_RETURN {SET_PROG_COUNTER(do_inter_return_label);JUMP_DONE;}
- #define INTER_ESCAPE_CATCH {SET_PROG_COUNTER(do_escape_catch_label);JUMP_DONE;}
+
#if defined(PIKE_USE_MACHINE_CODE) && defined(_M_IX86)
/* Disable frame pointer optimization */
1380: Inside #if defined(__GNUC__)
#ifdef __GNUC__
do_inter_return_label = && inter_return_label;
- do_escape_catch_label = && inter_escape_catch_label;
+
#elif defined (_M_IX86)
/* MSVC. */
_asm
{
lea eax,inter_return_label
mov do_inter_return_label,eax
- lea eax,inter_escape_catch_label
- mov do_escape_catch_label,eax
+
}
#else
#error Machine code not supported with this compiler.
#endif
-
+ #if 0
/* Paranoia.
*
* This can happen on systems with delay slots if the labels aren't
1403:
Pike_fatal("Inter return and escape catch labels are equal: %p\n",
do_inter_return_label);
}
+ #endif
/* Trick optimizer */
if(!dummy_label)
1423:
goto *dummy_label;
#endif
+ #if 0
if (dummy_label) {
inter_escape_catch_label:
EXIT_MACHINE_CODE();
return -2;
}
-
+ #endif
inter_return_label:
EXIT_MACHINE_CODE();
1490:
#endif /* PIKE_USE_MACHINE_CODE */
+ #undef REAL_PIKE_DEBUG
+ #undef DO_IF_REAL_DEBUG
+ #undef DO_IF_NOT_REAL_DEBUG
+
+
static void do_trace_call(INT32 args, dynamic_buffer *old_buf)
{
struct pike_string *filep = NULL;
1620:
}
+ #undef BLOCK_ALLOC_NEXT
+ #define BLOCK_ALLOC_NEXT next
+
#undef INIT_BLOCK
#define INIT_BLOCK(X) do { \
X->refs=0; \
2100:
#endif /* 0 */
}
+ static void restore_catching_eval_jmpbuf (LOW_JMP_BUF *p)
+ {
+ Pike_interpreter.catching_eval_jmpbuf = p;
+ }
void mega_apply(enum apply_type type, INT32 args, void *arg1, void *arg2)
{
2111:
if(low_mega_apply(type, args, arg1, arg2))
{
+ /* Save and clear Pike_interpreter.catching_eval_jmpbuf so that the
+ * following eval_instruction will install a LOW_JMP_BUF of its
+ * own to handle catches. */
+ LOW_JMP_BUF *saved_jmpbuf = Pike_interpreter.catching_eval_jmpbuf;
+ ONERROR uwp;
+ Pike_interpreter.catching_eval_jmpbuf = NULL;
+ SET_ONERROR (uwp, restore_catching_eval_jmpbuf, saved_jmpbuf);
+
eval_instruction(Pike_fp->pc
#ifdef ENTRY_PROLOGUE_SIZE
- ENTRY_PROLOGUE_SIZE
#endif /* ENTRY_PROLOGUE_SIZE */
);
low_return();
-
+
+ Pike_interpreter.catching_eval_jmpbuf = saved_jmpbuf;
+ UNSET_ONERROR (uwp);
}
}
-
- /* Put catch outside of eval_instruction, so
- * the setjmp won't affect the optimization of
- * eval_instruction
- *
- * Returns 0 on throw.
- *
- * Returns 1 if the code performed a RETURN.
- *
- * Returns 2 if the code performed EXIT_CATCH or ESCAPE_CATCH.
+ /* Put catch outside of eval_instruction, so the setjmp won't affect
+ * the optimization of eval_instruction.
*/
- static int o_catch(PIKE_OPCODE_T *pc)
+ static int catching_eval_instruction (PIKE_OPCODE_T *pc)
{
- JMP_BUF tmp;
- struct svalue *expendible=Pike_fp->expendible;
- int flags=Pike_fp->flags;
-
- debug_malloc_touch(Pike_fp);
- if(SETJMP(tmp))
- {
- *Pike_sp=throw_value;
- throw_value.type=T_INT;
- Pike_sp++;
- dmalloc_touch_svalue(Pike_sp-1);
- UNSETJMP(tmp);
- Pike_fp->expendible=expendible;
- Pike_fp->flags=flags;
- low_destruct_objects_to_destruct();
- return 0;
- }else{
- struct svalue **save_mark_sp=Pike_mark_sp;
- int x;
- Pike_fp->expendible=Pike_fp->locals + Pike_fp->num_locals;
-
- Pike_fp->flags&=~PIKE_FRAME_RETURN_INTERNAL;
-
- x=eval_instruction(pc);
+ LOW_JMP_BUF jmpbuf;
#ifdef PIKE_DEBUG
- if(Pike_mark_sp < save_mark_sp)
- Pike_fatal("mark Pike_sp underflow in catch.\n");
+ if (Pike_interpreter.catching_eval_jmpbuf)
+ Pike_fatal ("catching_eval_jmpbuf already active.\n");
#endif
- Pike_mark_sp=save_mark_sp;
- Pike_fp->expendible=expendible;
- Pike_fp->flags=flags;
- if(x>=0) mega_apply(APPLY_STACK, x, 0,0); /* Should never happen */
- UNSETJMP(tmp);
- return x == -2 ? 2 : 1;
+ Pike_interpreter.catching_eval_jmpbuf = &jmpbuf;
+ if (LOW_SETJMP (jmpbuf))
+ {
+ Pike_interpreter.catching_eval_jmpbuf = NULL;
+ return -3;
+ }else{
+ int x = eval_instruction(pc);
+ Pike_interpreter.catching_eval_jmpbuf = NULL;
+ return x;
}
}
2265:
int ret;
int use_dummy_reference = !o->prog->num_identifier_references;
int p_flags = o->prog->flags;
+ LOW_JMP_BUF *saved_jmpbuf;
/* This is needed for opcodes that use INHERIT_FROM_*
* (eg F_EXTERN) to work.
2304:
add_ref(new_frame->current_object);
add_ref(new_frame->context.prog);
+ saved_jmpbuf = Pike_interpreter.catching_eval_jmpbuf;
+ Pike_interpreter.catching_eval_jmpbuf = NULL;
+
if(SETJMP(tmp))
{
ret=1;
2311:
int tmp;
new_frame->mark_sp_base=new_frame->save_mark_sp=Pike_mark_sp;
tmp=eval_instruction(o->prog->program + offset);
- EVAL_INSTR_RET_CHECK(tmp);
+
Pike_mark_sp=new_frame->save_mark_sp;
#ifdef PIKE_DEBUG
-
+ if (tmp != -1)
+ Pike_fatal ("Unexpected return value from eval_instruction: %d\n", tmp);
if(Pike_sp<Pike_interpreter.evaluator_stack)
Pike_fatal("Stack error (simple).\n");
#endif
2322:
}
UNSETJMP(tmp);
+ Pike_interpreter.catching_eval_jmpbuf = saved_jmpbuf;
+
if (use_dummy_reference) {
Pike_compiler->new_program->num_identifier_references--;
o->prog->flags = p_flags;
2947: Inside #if defined(DO_PIKE_CLEANUP)
#endif
free_callback_list (&evaluator_callbacks);
free_all_pike_frame_blocks();
+ free_all_catch_context_blocks();
#endif
}