pike.git
/
src
/
docode.c
version
»
Context lines:
10
20
40
80
file
none
3
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.
89
2000
/
12
/
05
21
:
08
:
17
per
Exp $");
+
RCSID("$Id: docode.c,v 1.
90
2001
/
01
/
10
20
:
00
:
23
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:22:
#include "peep.h" #include "docode.h" #include "operators.h" #include "object.h" #include "opcodes.h" #include "language.h" #include "lex.h" static int do_docode2(node *n, INT16 flags);
-
INT32
current
_
break=-1
;
-
INT32
current
_
continue=-1
;
+
struct
statement
_
label_name
+
{
+
struct statement_label_name *next
;
+
struct pike
_
string *str
;
+
unsigned INT16 line_number;
+
};
-
+
struct statement_label
+
{
+
struct statement_label *prev;
+
struct statement_label_name *name;
+
INT16 emit_break_label;
+
INT32 break_label, continue_label;
+
unsigned catch_depth;
+
};
+
static struct statement_label *current_label = 0;
+
+
static unsigned catch_depth = 0;
+
+
#define PUSH_STATEMENT_LABEL do { \
+
struct statement_label new_label__; \
+
new_label__.prev = current_label; \
+
if (!current_label || current_label->break_label != -2) { \
+
/* Only cover the current label if it's in use by a statement. */ \
+
new_label__.name = 0; \
+
new_label__.break_label = new_label__.continue_label = -1; \
+
new_label__.catch_depth = catch_depth; \
+
current_label = &new_label__; \
+
} \
+
do
+
+
#define POP_STATEMENT_LABEL \
+
while (0); \
+
current_label = new_label__.prev; \
+
} while (0)
+
static INT32 current_switch_case; static INT32 current_switch_default; static INT32 current_switch_values_on_stack; static INT32 *current_switch_jumptable =0; static struct pike_string *current_switch_type = NULL; void upd_int(int offset, INT32 tmp) { MEMCPY(Pike_compiler->new_program->program+offset, (char *)&tmp,sizeof(tmp)); }
pike.git/src/docode.c:60:
return lbl; } #define LBLCACHESIZE 4711 #define CURRENT_INSTR ((long)instrbuf.s.len / (long)sizeof(p_instr)) #define MAX_UNWIND 100 static int lbl_cache[LBLCACHESIZE];
-
int do_branch(INT32 lbl)
+
int do_branch(INT32 lbl
, int catch_escapes
)
{ if(lbl==-1) { lbl=alloc_label(); }else{ INT32 last,pos=lbl_cache[lbl % LBLCACHESIZE]; if(pos < (last=CURRENT_INSTR) && (CURRENT_INSTR - pos) < MAX_UNWIND) { #define BUF ((p_instr *)instrbuf.s.str) if(BUF[pos].opcode == F_LABEL && BUF[pos].arg == lbl)
pike.git/src/docode.c:87:
BUF[pos].arg, BUF[pos].arg2, BUF[pos].line, BUF[pos].file); } } } } }
+
while (catch_escapes--)
+
emit0(F_ESCAPE_CATCH);
emit1(F_BRANCH, lbl); return lbl; } void low_insert_label(int lbl) { lbl_cache[ lbl % LBLCACHESIZE ] = CURRENT_INSTR; emit1(F_LABEL, lbl); }
pike.git/src/docode.c:159:
void do_cond_jump(node *n, int label, int iftrue, int flags) { iftrue=!!iftrue; if((flags & DO_POP) && node_is_tossable(n)) { int t,f; t=!!node_is_true(n); f=!!node_is_false(n); if(t || f) {
-
if(t == iftrue) do_branch( label);
+
if(t == iftrue) do_branch( label
, 0
);
return; } } switch(n->token) { case F_LAND: case F_LOR: if(iftrue == (n->token==F_LAND)) {
pike.git/src/docode.c:426:
return 0; } tmp1=alloc_label(); do_jump_when_zero(CAR(n), DO_NOT_WARN((INT32)tmp1)); adroppings=do_docode(CADR(n), flags); tmp3=emit1(F_POP_N_ELEMS,0); /* Else */
-
tmp2=do_branch(-1);
+
tmp2=do_branch(-1
, 0
);
low_insert_label( DO_NOT_WARN((INT32)tmp1)); bdroppings=do_docode(CDDR(n), flags); if(adroppings < bdroppings) { do_pop(bdroppings - adroppings); } if(adroppings > bdroppings) {
pike.git/src/docode.c:661:
emit0(F_DEC_AND_POP); return 0; }else{ emit0(n->token); return 1; } case F_FOR: { INT32 *prev_switch_jumptable = current_switch_jumptable;
-
INT32 break
_
save = current
_
break;
-
INT32 continue_save = current_continue;
+
PUSH
_
STATEMENT
_
LABEL
{
current_switch_jumptable=0;
-
current_break=alloc_label();
-
current_continue=alloc_label();
+
current_
label->
break
_label
=alloc_label();
+
current_
label->
continue
_label
=alloc_label();
if(CDR(n)) {
-
do_jump_when_zero(CAR(n),current_break);
+
do_jump_when_zero(CAR(n),current_
label->
break
_label
);
tmp2=ins_label(-1); DO_CODE_BLOCK(CADR(n));
-
ins_label(current_continue);
+
ins_label(current_
label->
continue
_label
);
DO_CODE_BLOCK(CDDR(n)); }else{ tmp2=ins_label(-1); } do_jump_when_non_zero(CAR(n), DO_NOT_WARN((INT32)tmp2));
-
ins_label(current_break);
+
ins_label(current_
label->
break
_label
);
current_switch_jumptable = prev_switch_jumptable;
-
current_break=break_save;
-
current
_
continue=continue
_
save
;
+
}
POP
_
STATEMENT
_
LABEL
;
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;
-
INT32 break
_
save = current
_
break;
-
INT32 continue_save = current_continue;
+
PUSH
_
STATEMENT
_
LABEL
{
current_switch_jumptable=0;
-
current_break=alloc_label();
-
current_continue=alloc_label();
+
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 &&
pike.git/src/docode.c:729:
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
-
tmp3=do_branch(-1);
+
tmp3=do_branch(-1
, 0
);
tmp1=ins_label(-1); DO_CODE_BLOCK(CDR(n));
-
ins_label(current_continue);
+
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_break);
+
ins_label(current_
label->
break
_label
);
#ifdef PIKE_DEBUG if(d_flag) emit0(F_POP_MARK); #endif current_switch_jumptable = prev_switch_jumptable;
-
current_break=break_save;
-
current
_
continue=continue
_
save
;
+
}
POP
_
STATEMENT
_
LABEL
;
do_pop(4); 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;
-
INT32 break
_
save = current
_
break;
-
INT32 continue_save = current_continue;
+
PUSH
_
STATEMENT
_
LABEL
{
current_switch_jumptable=0;
-
current_break=alloc_label();
-
current_continue=alloc_label();
+
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
-
tmp3=do_branch(-1);
+
tmp3=do_branch(-1
, 0
);
tmp1=ins_label(-1); DO_CODE_BLOCK(CDR(n));
-
ins_label(current_continue);
+
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_break);
+
ins_label(current_
label->
break
_label
);
#ifdef PIKE_DEBUG if(d_flag) emit0(F_POP_MARK); #endif current_switch_jumptable = prev_switch_jumptable;
-
current_break=break_save;
-
current
_
continue=continue
_
save
;
+
}
POP
_
STATEMENT
_
LABEL
;
do_pop(3); return 0; } case F_DO: { INT32 *prev_switch_jumptable = current_switch_jumptable;
-
INT32 break
_
save = current
_
break;
-
INT32 continue_save = current_continue;
+
PUSH
_
STATEMENT
_
LABEL
{
current_switch_jumptable=0;
-
current_break=alloc_label();
-
current_continue=alloc_label();
+
current_
label->
break
_label
=alloc_label();
+
current_
label->
continue
_label
=alloc_label();
tmp2=ins_label(-1); DO_CODE_BLOCK(CAR(n));
-
ins_label(current_continue);
+
ins_label(current_
label->
continue
_label
);
do_jump_when_non_zero(CDR(n), DO_NOT_WARN((INT32)tmp2));
-
ins_label(current_break);
+
ins_label(current_
label->
break
_label
);
current_switch_jumptable = prev_switch_jumptable;
-
current_break=break_save;
-
current
_
continue=continue
_
save
;
+
}
POP
_
STATEMENT
_
LABEL
;
return 0; } case F_POP_VALUE: { DO_CODE_BLOCK(CAR(n)); return 0; } case F_CAST:
pike.git/src/docode.c:958:
*/ case F_SWITCH: { INT32 e,cases,*order; INT32 *jumptable; INT32 prev_switch_values_on_stack = current_switch_values_on_stack; INT32 prev_switch_case = current_switch_case; INT32 prev_switch_default = current_switch_default; INT32 *prev_switch_jumptable = current_switch_jumptable;
-
INT32 break_save = current_break;
+
struct pike_string *prev_switch_type = current_switch_type; #ifdef PIKE_DEBUG struct svalue *save_sp=Pike_sp; #endif
-
+
PUSH_STATEMENT_LABEL {
if(do_docode(CAR(n),0)!=1) fatal("Internal compiler error, time to panic\n"); if (!(CAR(n) && (current_switch_type = CAR(n)->type))) { current_switch_type = mixed_type_string; }
-
current_break=alloc_label();
+
current_
label->
break
_label
=alloc_label();
cases=count_cases(CDR(n)); tmp1=emit1(F_SWITCH,0); 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));
pike.git/src/docode.c:1053:
pop_stack(); free((char *)jumptable); free((char *)current_switch_jumptable); current_switch_jumptable = prev_switch_jumptable; current_switch_default = prev_switch_default; current_switch_case = prev_switch_case; current_switch_values_on_stack = prev_switch_values_on_stack; current_switch_type = prev_switch_type;
-
low_insert_label( current_break);
+
low_insert_label( current_
label->
break
_label
);
-
current
_
break=break
_
save
;
+
} POP
_
STATEMENT
_
LABEL
;
#ifdef PIKE_DEBUG if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer) fatal("Stack error after F_SWITCH (underflow)\n"); #endif return 0; } case F_CASE: { if(!current_switch_jumptable)
pike.git/src/docode.c:1159:
{ yyerror("Default outside switch."); }else if(current_switch_default!=-1){ yyerror("Duplicate switch default."); }else{ current_switch_default = ins_label(-1); } return 0; case F_BREAK:
-
if(current_
break
== -1)
+
case
F_CONTINUE:
+
if
(
CAR(n)) {
+
struct pike_string *name = CAR(n)->u.sval.u.string;
+
struct statement_label *label;
+
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;
+
my_yyerror("No surrounding statement labeled '%s'.", name->str);
+
return 0;
+
+
label_found:
+
if (n->token == F_BREAK) {
+
if (label->
break
_label
< 0) label->emit_break_label
=
1;
+
label->break_label
=
+
do_branch(label
-
>break_label, catch_depth - label->catch_depth
)
;
+
}
+
else {
+
if (label->continue_label < 0)
+
my_yyerror("Cannot continue the non-loop statement on line %d.",
+
lbl_name->line_number);
+
else
+
do_branch(label->continue_label, catch_depth - label->catch_depth);
+
}
+
}
+
+
else
+
if (n->token == F_BREAK) {
+
if(!current_label || current_label->break_label < 0)
{ yyerror("Break outside loop or switch."); }else{
-
do_branch( current_break);
+
do_branch( current_
label->
break
_label,
+
catch_depth - current_label->catch_depth
);
}
-
+
}
+
else {
+
struct statement_label *label;
+
for (label = current_label; label; label = label->prev)
+
if (label->continue_label >= 0) {
+
do_branch( label->continue_label,
+
catch_depth - label->catch_depth);
return 0;
-
+
}
+
yyerror("Continue outside loop.");
+
}
+
return 0;
-
case F_
CONTINUE
:
-
if(current
_
continue == -1)
+
case F_
NORMAL_STMT_LABEL
:
+
case
F
_
CUSTOM_STMT_LABEL:
{
-
yyerror("continue
outside
loop
or
switch
.
"
);
-
}else{
-
do
_
branch
( current_
continue
);
+
PUSH_STATEMENT_LABEL
{
+
struct statement_label *label;
+
struct statement_label_name name;
+
name
.
str = CAR(n
)
->u.sval.u.string
;
+
name.line_number = n->line_number;
+
+
for (label = current
_
label; label; label = label->prev) {
+
struct statement_label_name *lbl_name;
+
for
(
lbl_name
= label->name; lbl_name; lbl_name = lbl_name->next)
+
if (lbl_name->str == name.str) {
+
INT32 save_line = lex.
current_
line;
+
lex.current_line = name.line_number;
+
my_yyerror("Duplicate nested labels, previous one on line %d.",
+
lbl_name->line_number
);
+
lex.current_line = save_line;
+
break;
}
-
+
}
+
+
name.next = current_label->name;
+
current_label->name = &name;
+
+
if (!name.next) {
+
current_label->emit_break_label = 0;
+
if (n->token == F_CUSTOM_STMT_LABEL)
+
/* The statement we precede has custom label handling; leave
+
* the statement_label "open" so the statement will use it
+
* instead of covering it. */
+
current_label->break_label = -2;
+
else
+
current_label->break_label = -1;
+
}
+
DO_CODE_BLOCK(CDR(n));
+
if (!name.next && current_label->emit_break_label)
+
low_insert_label(current_label->break_label);
+
} POP_STATEMENT_LABEL;
return 0;
-
+
}
case F_RETURN: do_docode(CAR(n),0); emit0(F_RETURN); 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: {
-
/* FIXME: Pike 7.0 compatibility? */
-
INT32 break
_
save = current
_
break;
-
INT32 continue_save = current_continue;
+
PUSH
_
STATEMENT
_
LABEL
{
INT32 *prev_switch_jumptable = current_switch_jumptable; current_switch_jumptable=0;
-
current_break=alloc_label();
-
current_continue=alloc_label();
+
current_
label->
break
_label
=alloc_label();
+
if (TEST_COMPAT(7,0))
+
current_
label->
continue
_label
=alloc_label();
-
+
catch_depth++;
tmp1=do_jump(F_CATCH,-1); DO_CODE_BLOCK(CAR(n));
-
ins_label(current_continue);
-
ins_label(current_break);
+
catch_depth--;
+
+
if (TEST_COMPAT(7,0))
+
ins_label(current_
label->
continue
_label
);
+
ins_label(current_
label->
break
_label
);
emit0(F_THROW_ZERO); ins_label(DO_NOT_WARN((INT32)tmp1));
-
current_break=break_save;
-
current_continue=continue_save;
+
current_switch_jumptable = prev_switch_jumptable;
-
+
} 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)