pike.git/src/docode.c:1:
/*\
||| This file a part of Pike, and is copyright by Fredrik Hubinette
||| Pike is distributed as GPL (General Public License)
||| See the files COPYING and DISCLAIMER for more information.
\*/
/**/
#include "global.h"
- RCSID("$Id: docode.c,v 1.96 2001/01/14 21:39:36 grubba Exp $");
+ RCSID("$Id: docode.c,v 1.97 2001/01/15 00:26:51 mast Exp $");
#include "las.h"
#include "program.h"
#include "pike_types.h"
#include "stralloc.h"
#include "interpret.h"
#include "constants.h"
#include "array.h"
#include "pike_macros.h"
#include "pike_error.h"
#include "pike_memory.h"
pike.git/src/docode.c:29:
static int do_docode2(node *n, INT16 flags);
typedef void (*cleanup_func)(void *);
struct cleanup_frame
{
struct cleanup_frame *prev;
cleanup_func cleanup;
void *cleanup_arg;
+ int stack_depth;
};
struct statement_label_name
{
struct statement_label_name *next;
struct pike_string *str;
unsigned int line_number;
};
struct statement_label
{
struct statement_label *prev;
struct statement_label_name *name;
/* -2 in break_label is used to flag "open" statement_label entries.
* If an open entry is on top of the stack, it's used instead of a
* new one. That's used to associate statement labels to the
* following statement. */
INT32 break_label, continue_label;
int emit_break_label;
-
+ int stack_depth;
struct cleanup_frame *cleanups;
};
static struct statement_label top_statement_label_dummy =
- {0, 0, -1, -1, 0, 0};
+ {0, 0, -1, -1, 0, -1, 0};
static struct statement_label *current_label = &top_statement_label_dummy;
-
+ #ifdef PIKE_DEBUG
+ static int current_stack_depth = -4711;
+ #else
+ static int current_stack_depth = 0;
+ #endif
#define PUSH_CLEANUP_FRAME(func, arg) do { \
struct cleanup_frame cleanup_frame__; \
cleanup_frame__.cleanup = (cleanup_func) (func); \
cleanup_frame__.cleanup_arg = (void *)(ptrdiff_t) (arg); \
-
+ cleanup_frame__.stack_depth = current_stack_depth; \
DO_IF_DEBUG( \
if (current_label->cleanups == (void *)(ptrdiff_t) -1) \
fatal("current_label points to an unused statement_label.\n"); \
) \
if (current_label->break_label == -2) { \
DO_IF_DEBUG( \
if (current_label->prev->break_label == -2) \
fatal("Found two open statement_label entries in a row.\n"); \
) \
cleanup_frame__.prev = current_label->prev->cleanups; \
pike.git/src/docode.c:89:
else { \
DO_IF_DEBUG( \
if (current_label->prev->cleanups != &cleanup_frame__) \
fatal("Cleanup frame lost from statement_label cleanup list.\n");\
) \
current_label->prev->cleanups = cleanup_frame__.prev; \
} \
} while (0)
#define POP_AND_DO_CLEANUP \
+ do_pop(current_stack_depth - cleanup_frame__.stack_depth); \
cleanup_frame__.cleanup(cleanup_frame__.cleanup_arg); \
POP_AND_DONT_CLEANUP
#define PUSH_STATEMENT_LABEL do { \
struct statement_label new_label__; \
new_label__.prev = current_label; \
if (current_label->break_label != -2) { \
/* Only cover the current label if it's closed. */ \
new_label__.name = 0; \
new_label__.break_label = new_label__.continue_label = -1; \
new_label__.cleanups = 0; \
-
+ new_label__.stack_depth = current_stack_depth; \
current_label = &new_label__; \
} \
- DO_IF_DEBUG(else new_label__.cleanups = (void *)(ptrdiff_t) -1;)
+ else { \
+ DO_IF_DEBUG( \
+ new_label__.cleanups = (void *)(ptrdiff_t) -1; \
+ new_label__.stack_depth = current_stack_depth; \
+ ) \
+ current_label->stack_depth = current_stack_depth; \
+ }
#define POP_STATEMENT_LABEL \
current_label = new_label__.prev; \
DO_IF_DEBUG( \
if (new_label__.cleanups && \
new_label__.cleanups != (void *)(ptrdiff_t) -1) \
fatal("Cleanup frames still left in statement_label.\n")); \
} while (0)
static INT32 current_switch_case;
pike.git/src/docode.c:202: Inside #if defined(PIKE_DEBUG)
{
#ifdef PIKE_DEBUG
if (x < 0) fatal("Cannot do pop of %d args.\n", x);
#endif
switch(x)
{
case 0: return;
case 1: emit0(F_POP_VALUE); break;
default: emit1(F_POP_N_ELEMS,x); break;
}
+ current_stack_depth -= x;
}
void do_cleanup_pop(int x)
{
#ifdef PIKE_DEBUG
if(d_flag)
emit0(F_POP_MARK);
#endif
do_pop(x);
}
-
+ void do_pop_mark()
+ {
+ emit0(F_POP_MARK);
+ }
+
+ void do_pop_to_mark()
+ {
+ emit0(F_POP_TO_MARK);
+ }
+
void do_escape_catch()
{
emit0(F_ESCAPE_CATCH);
}
#define DO_CODE_BLOCK(X) do_pop(do_docode((X),DO_NOT_COPY | DO_POP | DO_DEFER_POP))
int do_docode(node *n, INT16 flags)
{
int i;
-
+ int stack_depth_save = current_stack_depth;
int save_current_line=lex.current_line;
if(!n) return 0;
lex.current_line=n->line_number;
-
+ #ifdef PIKE_DEBUG
+ if (current_stack_depth == -4711) fatal("do_docode() used outside docode().\n");
+ #endif
i=do_docode2(check_node_hash(n), flags);
-
+ current_stack_depth = stack_depth_save + i;
lex.current_line=save_current_line;
return i;
}
static int is_efun(node *n, c_fun fun)
{
return n && n->token == F_CONSTANT &&
n->u.sval.subtype == FUNCTION_BUILTIN &&
n->u.sval.u.efun->function == fun;
pike.git/src/docode.c:301:
}
code_expression(n, (INT16)(flags | DO_NOT_COPY), "condition");
if(flags & DO_POP)
{
if(iftrue)
do_jump(F_BRANCH_WHEN_NON_ZERO, label);
else
do_jump(F_BRANCH_WHEN_ZERO, label);
+ current_stack_depth--;
}else{
if(iftrue)
do_jump(F_LOR, label);
else
do_jump(F_LAND, label);
}
}
#define do_jump_when_zero(N,L) do_cond_jump(N,L,0,DO_POP|DO_NOT_COPY)
#define do_jump_when_non_zero(N,L) do_cond_jump(N,L,1,DO_POP|DO_NOT_COPY)
pike.git/src/docode.c:350:
static inline struct compiler_frame *find_local_frame(INT32 depth)
{
struct compiler_frame *f=Pike_compiler->compiler_frame;
while(--depth>=0) f=f->previous;
return f;
}
int do_lfun_call(int id,node *args)
{
+ emit0(F_MARK);
+ PUSH_CLEANUP_FRAME(do_pop_mark, 0);
+ do_docode(args,0);
#if 1
if(id == Pike_compiler->compiler_frame->current_function_number)
{
int n=count_args(args);
if(n == Pike_compiler->compiler_frame->num_args)
{
if(Pike_compiler->compiler_frame->is_inline)
{
- emit0(F_MARK);
- do_docode(args,0);
+
Pike_compiler->compiler_frame->recur_label=do_jump(F_RECUR,
Pike_compiler->compiler_frame->recur_label);
- return 1;
+
}else{
- emit0(F_MARK);
- do_docode(args,0);
+
emit1(F_COND_RECUR,id);
Pike_compiler->compiler_frame->recur_label=do_jump(F_POINTER,
Pike_compiler->compiler_frame->recur_label);
- return 1;
+
}
}
}
-
+ else
#endif
- emit0(F_MARK);
- do_docode(args,0);
+
emit1(F_CALL_LFUN, id);
-
+ POP_AND_DONT_CLEANUP;
return 1;
}
static int do_docode2(node *n, INT16 flags)
{
ptrdiff_t tmp1,tmp2,tmp3;
if(!n) return 0;
if(flags & DO_LVALUE)
pike.git/src/docode.c:492:
}
}
}
break;
case F_UNDEFINED:
yyerror("Undefined identifier");
emit1(F_NUMBER,0);
return 1;
- case F_PUSH_ARRAY:
+ case F_PUSH_ARRAY: {
+ if (current_label != &top_statement_label_dummy || current_label->cleanups) {
+ /* Might not have a surrounding apply node if evaluated as a
+ * constant by the optimizer. */
+ #ifdef PIKE_DEBUG
+ if (!current_label->cleanups ||
+ (current_label->cleanups->cleanup != do_pop_mark &&
+ current_label->cleanups->cleanup != do_pop_to_mark))
+ fatal("F_PUSH_ARRAY unexpected in this context.\n");
+ #endif
+ current_label->cleanups->cleanup = do_pop_to_mark;
+ }
code_expression(CAR(n), 0, "`@");
emit0(F_PUSH_ARRAY);
- return -0x7ffffff;
+ return 0;
+ }
case '?':
{
INT32 *prev_switch_jumptable = current_switch_jumptable;
int adroppings , bdroppings;
current_switch_jumptable=0;
if(!CDDR(n))
{
pike.git/src/docode.c:797:
return 0;
}
case ' ':
return do_docode(CAR(n),0)+do_docode(CDR(n),DO_LVALUE);
case F_FOREACH:
{
node *arr;
INT32 *prev_switch_jumptable = current_switch_jumptable;
- PUSH_CLEANUP_FRAME(do_cleanup_pop, 4);
- PUSH_STATEMENT_LABEL;
+
- current_switch_jumptable=0;
- current_label->break_label=alloc_label();
- current_label->continue_label=alloc_label();
-
+
arr=CAR(n);
if(arr->token==F_RANGE)
{
node **a1=my_get_arg(&_CDR(n),0);
node **a2=my_get_arg(&_CDR(n),1);
if(a1 && a2 && a2[0]->token==F_CONSTANT &&
a2[0]->u.sval.type==T_INT &&
a2[0]->u.sval.type==0x7fffffff &&
a1[0]->type == int_type_string)
{
tmp2=do_docode(CAR(arr),DO_NOT_COPY);
do_docode(*a1,DO_NOT_COPY);
goto foreach_arg_pushed;
}
}
tmp2=do_docode(CAR(n),DO_NOT_COPY);
emit0(F_CONST0);
-
+ current_stack_depth++;
foreach_arg_pushed:
#ifdef PIKE_DEBUG
/* This is really ugly because there is always a chance that the bug
* will disappear when new instructions are added to the code, but
* think it is worth it.
*/
if(d_flag)
emit0(F_MARK);
#endif
-
+ PUSH_CLEANUP_FRAME(do_cleanup_pop, 4);
+
+ PUSH_STATEMENT_LABEL;
+ current_switch_jumptable=0;
+ current_label->break_label=alloc_label();
+ current_label->continue_label=alloc_label();
+
tmp3=do_branch(-1);
tmp1=ins_label(-1);
DO_CODE_BLOCK(CDR(n));
ins_label(current_label->continue_label);
low_insert_label( DO_NOT_WARN((INT32)tmp3));
do_jump(n->token, DO_NOT_WARN((INT32)tmp1));
ins_label(current_label->break_label);
current_switch_jumptable = prev_switch_jumptable;
POP_STATEMENT_LABEL;
POP_AND_DO_CLEANUP;
return 0;
}
case F_INC_NEQ_LOOP:
case F_DEC_NEQ_LOOP:
case F_INC_LOOP:
case F_DEC_LOOP:
{
INT32 *prev_switch_jumptable = current_switch_jumptable;
- PUSH_CLEANUP_FRAME(do_cleanup_pop, 3);
- PUSH_STATEMENT_LABEL;
+
- current_switch_jumptable=0;
- current_label->break_label=alloc_label();
- current_label->continue_label=alloc_label();
-
+
tmp2=do_docode(CAR(n),0);
#ifdef PIKE_DEBUG
/* This is really ugly because there is always a chance that the bug
* will disappear when new instructions are added to the code, but
* think it is worth it.
*/
if(d_flag)
emit0(F_MARK);
#endif
-
+ PUSH_CLEANUP_FRAME(do_cleanup_pop, 3);
+
+ PUSH_STATEMENT_LABEL;
+ current_switch_jumptable=0;
+ current_label->break_label=alloc_label();
+ current_label->continue_label=alloc_label();
tmp3=do_branch(-1);
tmp1=ins_label(-1);
DO_CODE_BLOCK(CDR(n));
ins_label(current_label->continue_label);
low_insert_label( DO_NOT_WARN((INT32)tmp3));
do_jump(n->token, DO_NOT_WARN((INT32)tmp1));
ins_label(current_label->break_label);
current_switch_jumptable = prev_switch_jumptable;
pike.git/src/docode.c:967:
if(CAR(n)->token == F_CONSTANT)
{
if(CAR(n)->u.sval.type == T_FUNCTION)
{
if(CAR(n)->u.sval.subtype == FUNCTION_BUILTIN) /* driver fun? */
{
if(!CAR(n)->u.sval.u.efun->docode ||
!CAR(n)->u.sval.u.efun->docode(n))
{
emit0(F_MARK);
+ PUSH_CLEANUP_FRAME(do_pop_mark, 0);
do_docode(CDR(n),0);
tmp1=store_constant(& CAR(n)->u.sval,
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
CAR(n)->name);
emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));
-
+ POP_AND_DONT_CLEANUP;
}
if(n->type == void_type_string)
return 0;
return 1;
}else{
if(CAR(n)->u.sval.u.object == Pike_compiler->fake_object)
return do_lfun_call(CAR(n)->u.sval.subtype,CDR(n));
}
}
emit0(F_MARK);
-
+ PUSH_CLEANUP_FRAME(do_pop_mark, 0);
do_docode(CDR(n),0);
tmp1=store_constant(& CAR(n)->u.sval,
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
CAR(n)->name);
emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));
-
+ POP_AND_DONT_CLEANUP;
return 1;
}
else if(CAR(n)->token == F_IDENTIFIER &&
IDENTIFIER_IS_FUNCTION(ID_FROM_INT(Pike_compiler->new_program,
CAR(n)->u.id.number)->identifier_flags))
{
return do_lfun_call(CAR(n)->u.id.number,CDR(n));
}
else if(CAR(n)->token == F_EXTERNAL &&
pike.git/src/docode.c:1012:
{
return do_lfun_call(CAR(n)->u.integer.b,CDR(n));
}
else
{
struct pike_string *tmp;
struct efun *fun;
node *foo;
emit0(F_MARK);
+ PUSH_CLEANUP_FRAME(do_pop_mark, 0);
do_docode(CAR(n),0);
do_docode(CDR(n),0);
tmp=findstring("call_function");
if(!tmp) yyerror("No call_function efun.");
foo=find_module_identifier(tmp,0);
if(!foo || !foo->token==F_CONSTANT)
{
yyerror("No call_function efun.");
}else{
pike.git/src/docode.c:1034:
foo->u.sval.u.efun->function == f_call_function)
{
emit0(F_CALL_FUNCTION);
}else{
/* We might want to put "predef::"+foo->name here /Hubbe */
tmp1=store_constant(& foo->u.sval, 1, foo->name);
emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));
}
}
free_node(foo);
+ POP_AND_DONT_CLEANUP;
return 1;
}
case F_ARG_LIST:
case F_COMMA_EXPR:
tmp1 = do_docode(CAR(n), (INT16)(flags & ~WANT_LVALUE));
tmp1+=do_docode(CDR(n),flags);
return DO_NOT_WARN((INT32)tmp1);
pike.git/src/docode.c:1083:
if (!(CAR(n) && (current_switch_type = CAR(n)->type))) {
current_switch_type = mixed_type_string;
}
current_label->break_label=alloc_label();
cases=count_cases(CDR(n));
tmp1=emit1(F_SWITCH,0);
+ current_stack_depth--;
emit1(F_ALIGN,sizeof(INT32));
current_switch_values_on_stack=0;
current_switch_case=1;
current_switch_default=-1;
current_switch_jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+2));
jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+2));
for(e=1; e<cases*2+2; e++)
{
pike.git/src/docode.c:1275:
case F_BREAK:
case F_CONTINUE: {
struct statement_label *label, *p;
if (CAR(n)) {
struct pike_string *name = CAR(n)->u.sval.u.string;
struct statement_label_name *lbl_name;
for (label = current_label; label; label = label->prev)
for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next)
if (lbl_name->str == name)
- goto label_found;
+ goto label_found_1;
my_yyerror("No surrounding statement labeled '%s'.", name->str);
return 0;
- label_found:
+ label_found_1:
if (n->token == F_CONTINUE && label->continue_label < 0) {
my_yyerror("Cannot continue the non-loop statement on line %d.",
lbl_name->line_number);
return 0;
}
}
- else
+ else {
if (n->token == F_BREAK) {
- label = current_label;
- if(label->break_label < 0)
- {
+ for (label = current_label; label; label = label->prev)
+ if (label->break_label >= 0)
+ goto label_found_2;
yyerror("Break outside loop or switch.");
return 0;
}
- }
+
else {
for (label = current_label; label; label = label->prev)
if (label->continue_label >= 0)
- goto continue_label_found;
+ goto label_found_2;
yyerror("Continue outside loop.");
return 0;
- continue_label_found:
- ;
+
}
-
+ label_found_2: ;
+ }
for (p = current_label; 1; p = p->prev) {
struct cleanup_frame *q;
- for (q = p->cleanups; q; q = q->prev)
+ for (q = p->cleanups; q; q = q->prev) {
+ do_pop(current_stack_depth - q->stack_depth);
q->cleanup(q->cleanup_arg);
-
+ }
+ do_pop(current_stack_depth - p->stack_depth);
if (p == label) break;
}
if (n->token == F_BREAK) {
if (label->break_label < 0) label->emit_break_label = 1;
label->break_label = do_branch(label->break_label);
}
else
do_branch(label->continue_label);
pike.git/src/docode.c:1378:
return 0;
case F_SSCANF:
tmp1=do_docode(CAR(n),DO_NOT_COPY);
tmp2=do_docode(CDR(n),DO_NOT_COPY | DO_LVALUE);
emit1(F_SSCANF, DO_NOT_WARN((INT32)(tmp1+tmp2)));
return 1;
case F_CATCH: {
INT32 *prev_switch_jumptable = current_switch_jumptable;
- PUSH_STATEMENT_LABEL;
+ tmp1=do_jump(F_CATCH,-1);
+ PUSH_CLEANUP_FRAME(do_escape_catch, 0);
-
+ PUSH_STATEMENT_LABEL;
current_switch_jumptable=0;
current_label->break_label=alloc_label();
if (TEST_COMPAT(7,0))
current_label->continue_label=alloc_label();
- PUSH_CLEANUP_FRAME(do_escape_catch, 0);
+
- tmp1=do_jump(F_CATCH,-1);
+
DO_CODE_BLOCK(CAR(n));
if (TEST_COMPAT(7,0))
ins_label(current_label->continue_label);
ins_label(current_label->break_label);
emit0(F_THROW_ZERO);
-
+ current_switch_jumptable = prev_switch_jumptable;
+ POP_STATEMENT_LABEL;
+
ins_label(DO_NOT_WARN((INT32)tmp1));
-
+ current_stack_depth++;
- current_switch_jumptable = prev_switch_jumptable;
+
POP_AND_DONT_CLEANUP;
- POP_STATEMENT_LABEL;
+
return 1;
}
case F_LVALUE_LIST:
return do_docode(CAR(n),DO_LVALUE)+do_docode(CDR(n),DO_LVALUE);
case F_ARRAY_LVALUE:
tmp1=do_docode(CAR(n),DO_LVALUE);
#ifdef PIKE_DEBUG
if(tmp1 & 1)
pike.git/src/docode.c:1603:
do_docode(CDR(n), (INT16)(flags | DO_LVALUE));
default:
fatal("Infernal compiler error (unknown parse-tree-token %d).\n", n->token);
return 0; /* make gcc happy */
}
}
void do_code_block(node *n)
{
+ #ifdef PIKE_DEBUG
+ if (current_stack_depth != -4711) fatal("Reentrance in do_code_block().\n");
+ current_stack_depth = 0;
+ #endif
+
init_bytecode();
label_no=1;
emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);
emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);
emit0(F_START_FUNCTION);
low_insert_label(0);
if(Pike_compiler->new_program->identifier_references[Pike_compiler->compiler_frame->
current_function_number].id_flags &
ID_INLINE)
pike.git/src/docode.c:1640:
/* This is a no-op, but prevents optimizer to delete the bytes below */
low_insert_label(-1);
emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);
emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);
emit0(F_START_FUNCTION);
low_insert_label(Pike_compiler->compiler_frame->recur_label);
DO_CODE_BLOCK(n);
}
assemble();
+
+ #ifdef PIKE_DEBUG
+ current_stack_depth = -4711;
+ #endif
}
int docode(node *n)
{
int tmp;
int label_no_save = label_no;
dynamic_buffer instrbuf_save = instrbuf;
-
+ int stack_depth_save = current_stack_depth;
+ struct statement_label *label_save = current_label;
+ struct cleanup_frame *top_cleanups_save = top_statement_label_dummy.cleanups;
instrbuf.s.str=0;
label_no=1;
-
+ current_stack_depth = 0;
+ current_label = &top_statement_label_dummy; /* Fix these two to */
+ top_statement_label_dummy.cleanups = 0; /* please F_PUSH_ARRAY. */
init_bytecode();
tmp=do_docode(n,0);
assemble();
instrbuf=instrbuf_save;
label_no = label_no_save;
-
+ current_stack_depth = stack_depth_save;
+ current_label = label_save;
+ top_statement_label_dummy.cleanups = top_cleanups_save;
return tmp;
}