|
|
|
|
|
|
#include "global.h" |
#include "stralloc.h" |
#include "dynamic_buffer.h" |
#include "program.h" |
#include "las.h" |
#include "docode.h" |
#include "pike_embed.h" |
#include "pike_error.h" |
#include "lex.h" |
#include "pike_memory.h" |
#include "peep.h" |
#include "stuff.h" |
#include "bignum.h" |
#include "opcodes.h" |
#include "builtin_functions.h" |
#include "constants.h" |
#include "interpret.h" |
#include "pikecode.h" |
#include "pike_compiler.h" |
|
#ifdef PIKE_DEBUG |
static int hasarg(int opcode) |
{ |
return instrs[opcode-F_OFFSET].flags & I_HASARG; |
} |
|
static int hasarg2(int opcode) |
{ |
return instrs[opcode-F_OFFSET].flags & I_HASARG2; |
} |
|
static void dump_instr(p_instr *p) |
{ |
if(!p) return; |
fprintf(stderr,"%s",get_token_name(p->opcode)); |
if(hasarg(p->opcode)) |
{ |
fprintf(stderr,"(%d",p->arg); |
if(hasarg2(p->opcode)) |
fprintf(stderr,",%d",p->arg2); |
fprintf(stderr,")"); |
} |
} |
#endif |
|
|
static int asm_opt(void); |
|
|
dynamic_buffer instrbuf; |
long num_instrs = 0; |
|
|
void init_bytecode(void) |
{ |
initialize_buf(&instrbuf); |
num_instrs = 0; |
} |
|
void exit_bytecode(void) |
{ |
ptrdiff_t e, length; |
p_instr *c; |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
for(e=0;e<length;e++) { |
free_string(dmalloc_touch_named(struct pike_string *, c[e].file, |
"exit_bytecode")); |
#ifdef PIKE_DEBUG |
c[e].file = (void *)(ptrdiff_t)~0; |
#endif |
} |
|
toss_buffer(&instrbuf); |
} |
|
|
|
ptrdiff_t insert_opcode(p_instr *opcode) |
{ |
|
p_instr *p = (p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); |
if (!p) Pike_fatal("Out of memory in peep.\n"); |
*p = *opcode; |
num_instrs++; |
return p - (p_instr *)instrbuf.s.str; |
} |
|
ptrdiff_t insert_opcode2(unsigned int f, |
INT32 b, |
INT32 c, |
INT_TYPE current_line, |
struct pike_string *current_file) |
{ |
p_instr *p; |
|
#ifdef PIKE_DEBUG |
if(!hasarg2(f) && c) |
Pike_fatal("hasarg2(%d) is wrong!\n",f); |
#endif |
|
p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); |
|
|
#ifdef PIKE_DEBUG |
if(!instrbuf.s.len) |
Pike_fatal("Low make buf space failed!!!!!!\n"); |
#endif |
|
p->opcode=f; |
p->line=current_line; |
copy_shared_string(p->file, dmalloc_touch_named(struct pike_string *, |
current_file, |
"insert_opcode")); |
p->arg=b; |
p->arg2=c; |
|
return p - (p_instr *)instrbuf.s.str; |
} |
|
ptrdiff_t insert_opcode1(unsigned int f, |
INT32 b, |
INT_TYPE current_line, |
struct pike_string *current_file) |
{ |
#ifdef PIKE_DEBUG |
if(!hasarg(f) && b) |
Pike_fatal("hasarg(%d) is wrong!\n",f); |
#endif |
|
return insert_opcode2(f,b,0,current_line,current_file); |
} |
|
ptrdiff_t insert_opcode0(int f, INT_TYPE current_line, |
struct pike_string *current_file) |
{ |
#ifdef PIKE_DEBUG |
if(hasarg(f)) |
Pike_fatal("hasarg(%d) is wrong!\n",f); |
#endif |
return insert_opcode1(f,0,current_line, current_file); |
} |
|
|
void update_arg(int instr,INT32 arg) |
{ |
p_instr *p; |
#ifdef PIKE_DEBUG |
if(instr > (long)instrbuf.s.len / (long)sizeof(p_instr) || instr < 0) |
Pike_fatal("update_arg outside known space.\n"); |
#endif |
p=(p_instr *)instrbuf.s.str; |
p[instr].arg=arg; |
} |
|
#ifndef FLUSH_CODE_GENERATOR_STATE |
#define FLUSH_CODE_GENERATOR_STATE() |
#endif |
|
|
|
INT32 assemble(int store_linenumbers) |
{ |
INT32 entry_point; |
INT32 max_label=-1,tmp; |
INT32 *labels, *jumps, *uses, *aliases; |
ptrdiff_t e, length; |
p_instr *c; |
struct pike_string *tripples = NULL; |
#ifdef PIKE_DEBUG |
INT32 max_pointer=-1; |
int synch_depth = 0; |
size_t fun_start = Pike_compiler->new_program->num_program; |
#endif |
int relabel; |
int reoptimize = relabel = !(debug_options & NO_PEEP_OPTIMIZING); |
struct lex *lex; |
CHECK_COMPILER(); |
lex = &THIS_COMPILATION->lex; |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
#ifdef PIKE_DEBUG |
if((a_flag > 1 && store_linenumbers) || a_flag > 2) |
{ |
for (e = 0; e < length; e++) { |
if (c[e].opcode == F_POP_SYNCH_MARK) synch_depth--; |
fprintf(stderr, "~~~%4ld %4lx %*s", (long)c[e].line, |
(unsigned long)e, synch_depth, ""); |
dump_instr(c+e); |
fprintf(stderr,"\n"); |
if (c[e].opcode == F_SYNCH_MARK) synch_depth++; |
} |
if (synch_depth) { |
Pike_fatal("Unbalanced sync_mark/pop_sync_mark: %d\n", synch_depth); |
} |
} |
#endif |
|
|
if (store_linenumbers) { |
p_wchar2 *current_tripple; |
struct pike_string *previous_file = NULL; |
INT_TYPE previous_line = 0; |
ptrdiff_t num_linedirectives = 0; |
|
|
for (e=0; e < length; e++) { |
if (c[e].file != previous_file) { |
previous_file = dmalloc_touch_named(struct pike_string *, |
c[e].file, "prev_file"); |
num_linedirectives++; |
} |
if (c[e].line != previous_line) { |
previous_line = c[e].line; |
num_linedirectives++; |
} |
} |
|
|
|
|
|
if (!(tripples = begin_wide_shared_string(3*(length+num_linedirectives), |
2))) { |
Pike_fatal("Failed to allocate wide string of length %d 3*(%d + %d).\n", |
3*(length+num_linedirectives), length, num_linedirectives); |
} |
previous_file = NULL; |
previous_line = 0; |
current_tripple = STR2(tripples); |
for (e = 0; e < length; e++) { |
if (c[e].file != previous_file) { |
current_tripple[0] = F_FILENAME; |
current_tripple[1] = |
store_prog_string(dmalloc_touch_named(struct pike_string *, |
c[e].file, |
"store_prog_string")); |
current_tripple[2] = 0; |
current_tripple += 3; |
previous_file = dmalloc_touch_named(struct pike_string *, |
c[e].file, "prev_file"); |
} |
if (c[e].line != previous_line) { |
current_tripple[0] = F_LINE; |
current_tripple[1] = c[e].line; |
#if SIZEOF_INT_TYPE > 4 |
current_tripple[2] = c[e].line>>32; |
#else |
current_tripple[2] = 0; |
#endif |
current_tripple += 3; |
previous_line = c[e].line; |
} |
current_tripple[0] = c[e].opcode; |
current_tripple[1] = c[e].arg; |
current_tripple[2] = c[e].arg2; |
current_tripple += 3; |
} |
#ifdef PIKE_DEBUG |
if (current_tripple != STR2(tripples) + 3*(length + num_linedirectives)) { |
Pike_fatal("Tripple length mismatch %d != %d 3*(%d + %d)\n", |
current_tripple - STR2(tripples), |
3*(length + num_linedirectives), |
length, num_linedirectives); |
} |
#endif /* PIKE_DEBUG */ |
tripples = end_shared_string(tripples); |
} |
|
for(e=0;e<length;e++,c++) { |
if(c->opcode == F_LABEL) { |
if(c->arg > max_label) |
max_label = c->arg; |
} |
#ifdef PIKE_DEBUG |
else if (instrs[c->opcode - F_OFFSET].flags & I_POINTER) { |
if (c->arg > max_pointer) |
max_pointer = c->arg; |
} |
#endif /* PIKE_DEBUG */ |
} |
|
#ifdef PIKE_DEBUG |
if (max_pointer > max_label) { |
fprintf(stderr, |
"Reference to undefined label %d > %d\n" |
"Bad instructions are marked with '***':\n", |
max_pointer, max_label); |
c=(p_instr *)instrbuf.s.str; |
for(e=0;e<length;e++,c++) { |
if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; |
fprintf(stderr, " * %4ld %4lx ", |
(long)c->line, (unsigned long)e); |
dump_instr(c); |
if ((instrs[c->opcode - F_OFFSET].flags & I_POINTER) && |
(c->arg > max_label)) { |
fprintf(stderr, " ***\n"); |
} else { |
fprintf(stderr, "\n"); |
} |
if (c->opcode == F_SYNCH_MARK) synch_depth++; |
} |
|
Pike_fatal("Reference to undefined label %d > %d\n", |
max_pointer, max_label); |
} |
#endif /* PIKE_DEBUG */ |
|
#ifndef INS_ENTRY |
|
for (c = (p_instr *) instrbuf.s.str, e = 0; e < length; e++, c++) |
if (c->opcode == F_ENTRY) c->opcode = F_NOP; |
#endif |
|
labels=xalloc(sizeof(INT32) * 4 * (max_label+2)); |
jumps = labels + max_label + 2; |
uses = jumps + max_label + 2; |
aliases = uses + max_label + 2; |
while(relabel) |
{ |
|
for(e=0;e<=max_label;e++) |
{ |
labels[e]=jumps[e]= aliases[e] = -1; |
uses[e]=0; |
} |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
for(e=0;e<length;e++) |
if(c[e].opcode == F_LABEL && c[e].arg>=0) { |
INT32 l = c[e].arg; |
labels[l]=(INT32)e; |
while (e+1 < length && |
c[e+1].opcode == F_LABEL && c[e+1].arg >= 0) { |
|
|
|
e++; |
labels[c[e].arg] = (INT32)e; |
aliases[c[e].arg] = l; |
} |
} |
|
for(e=0;e<length;e++) |
{ |
if(instrs[c[e].opcode-F_OFFSET].flags & I_POINTER) |
{ |
if (aliases[c[e].arg] >= 0) c[e].arg = aliases[c[e].arg]; |
|
while(1) |
{ |
int tmp; |
tmp=labels[c[e].arg]; |
|
while(tmp<length && |
(c[tmp].opcode == F_LABEL || |
c[tmp].opcode == F_NOP)) tmp++; |
|
if(tmp>=length) break; |
|
if(c[tmp].opcode==F_BRANCH) |
{ |
c[e].arg=c[tmp].arg; |
continue; |
} |
|
#define TWOO(X,Y) (((X)<<8)+(Y)) |
|
switch(TWOO(c[e].opcode,c[tmp].opcode)) |
{ |
case TWOO(F_LOR,F_BRANCH_WHEN_NON_ZERO): |
c[e].opcode=F_BRANCH_WHEN_NON_ZERO; |
|
case TWOO(F_LOR,F_LOR): |
c[e].arg=c[tmp].arg; |
continue; |
|
case TWOO(F_LAND,F_BRANCH_WHEN_ZERO): |
c[e].opcode=F_BRANCH_WHEN_ZERO; |
|
case TWOO(F_LAND,F_LAND): |
c[e].arg=c[tmp].arg; |
continue; |
|
case TWOO(F_LOR, F_RETURN): |
c[e].opcode=F_RETURN_IF_TRUE; |
goto pointer_opcode_done; |
|
case TWOO(F_BRANCH, F_RETURN): |
case TWOO(F_BRANCH, F_RETURN_0): |
case TWOO(F_BRANCH, F_RETURN_1): |
case TWOO(F_BRANCH, F_RETURN_LOCAL): |
if(c[e].file) { |
free_string(dmalloc_touch_named(struct pike_string *, |
c[e].file, "branch_opt 1")); |
} |
c[e]=c[tmp]; |
if(c[e].file) { |
add_ref(dmalloc_touch_named(struct pike_string *, |
c[e].file, "branch_opt 2")); |
} |
goto pointer_opcode_done; |
} |
break; |
} |
#ifdef PIKE_DEBUG |
if (c[e].arg < 0 || c[e].arg > max_label) |
Pike_fatal ("Invalid index into uses: %d\n", c[e].arg); |
#endif |
uses[c[e].arg]++; |
} |
pointer_opcode_done:; |
} |
|
for(e=0;e<=max_label;e++) |
{ |
if(!uses[e] && labels[e]>=0) |
{ |
c[labels[e]].opcode=F_NOP; |
reoptimize = 1; |
} |
} |
|
if(!reoptimize) { |
#ifdef PIKE_DEBUG |
if (a_flag > 3) fprintf (stderr, "Optimizer done after relabel.\n"); |
#endif |
break; |
} |
|
|
|
relabel = asm_opt(); |
|
reoptimize = 0; |
|
if (!relabel) { |
#ifdef PIKE_DEBUG |
if (a_flag > 3) fprintf (stderr, "Optimizer done after asm_opt.\n"); |
#endif |
break; |
} |
|
#if 1 |
#ifdef PIKE_DEBUG |
if (a_flag > 3) |
fprintf(stderr, "Rerunning optimizer.\n"); |
#endif |
#else /* !1 */ |
relabel = 0; |
#endif /* 1 */ |
} |
|
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
for(e=0;e<=max_label;e++) labels[e]=jumps[e]=-1; |
|
|
#ifdef START_NEW_FUNCTION |
START_NEW_FUNCTION(store_linenumbers); |
#endif |
|
#ifdef ALIGN_PIKE_FUNCTION_BEGINNINGS |
while( ( (((INT32) PIKE_PC)+4) & (ALIGN_PIKE_JUMPS-1))) |
ins_byte(0); |
#endif |
|
if (store_linenumbers) { |
ins_data(store_prog_string(tripples)); |
free_string(tripples); |
} else { |
ins_data(0); |
} |
|
entry_point = PIKE_PC; |
|
#ifdef PIKE_DEBUG |
synch_depth = 0; |
#endif |
FLUSH_CODE_GENERATOR_STATE(); |
for(e=0;e<length;e++) |
{ |
#ifdef PIKE_DEBUG |
if (c != (((p_instr *)instrbuf.s.str)+e)) { |
Pike_fatal("Instruction loop deviates. " |
"0x%04"PRINTPTRDIFFT"x != 0x%04"PRINTPTRDIFFT"x\n", |
e, c - ((p_instr *)instrbuf.s.str)); |
} |
if(((a_flag > 2) && store_linenumbers) || |
(a_flag > 3) || |
(lex->pragmas & ID_DISASSEMBLE)) |
{ |
if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; |
fprintf(stderr, "===%4ld %4lx %*s", (long)c->line, |
(unsigned long)PIKE_PC, synch_depth, ""); |
dump_instr(c); |
fprintf(stderr,"\n"); |
if (c->opcode == F_SYNCH_MARK) synch_depth++; |
} |
#endif |
|
if(store_linenumbers) { |
store_linenumber(c->line, dmalloc_touch_named(struct pike_string *, |
c->file, |
"store_line")); |
#ifdef PIKE_DEBUG |
if (c->opcode < F_MAX_OPCODE) |
ADD_COMPILED(c->opcode); |
#endif /* PIKE_DEBUG */ |
} |
|
switch(c->opcode) |
{ |
case F_NOP: |
case F_NOTREACHED: |
case F_START_FUNCTION: |
break; |
case F_ALIGN: |
ins_align(c->arg); |
break; |
|
case F_BYTE: |
ins_byte((unsigned char)(c->arg)); |
break; |
|
case F_DATA: |
ins_data(c->arg); |
break; |
|
case F_ENTRY: |
#ifdef INS_ENTRY |
INS_ENTRY(); |
#else |
Pike_fatal ("F_ENTRY is supposed to be gone here.\n"); |
#endif |
break; |
|
case F_LABEL: |
if(c->arg == -1) { |
#ifdef PIKE_DEBUG |
if (!(debug_options & NO_PEEP_OPTIMIZING)) |
Pike_fatal ("Failed to optimize away an unused label.\n"); |
#endif |
break; |
} |
#ifdef PIKE_DEBUG |
if(c->arg > max_label || c->arg < 0) |
Pike_fatal("max_label calculation failed!\n"); |
|
if(labels[c->arg] != -1) |
Pike_fatal("Duplicate label!\n"); |
#endif |
FLUSH_CODE_GENERATOR_STATE(); |
labels[c->arg] = (INT32)PIKE_PC; |
if ((e+1 < length) && |
(c[1].opcode != F_LABEL) && |
(c[1].opcode != F_BYTE) && |
(c[1].opcode != F_ENTRY) && |
(c[1].opcode != F_DATA)) { |
|
UPDATE_PC(); |
} |
|
break; |
|
case F_VOLATILE_RETURN: |
ins_f_byte(F_RETURN); |
break; |
|
case F_POINTER: |
#ifdef PIKE_DEBUG |
if(c->arg > max_label || c->arg < 0) |
Pike_fatal("Jump to unknown label?\n"); |
#endif |
tmp = (INT32)PIKE_PC; |
ins_pointer(jumps[c->arg]); |
jumps[c->arg]=tmp; |
break; |
|
default: |
switch(instrs[c->opcode - F_OFFSET].flags & I_IS_MASK) |
{ |
case I_ISPTRJUMP: |
#ifdef INS_F_JUMP |
tmp=INS_F_JUMP(c->opcode, (labels[c->arg] != -1)); |
if(tmp != -1) |
{ |
UPDATE_F_JUMP(tmp, jumps[c->arg]); |
jumps[c->arg]=~tmp; |
break; |
} |
#endif |
|
ins_f_byte(c->opcode); |
|
#ifdef PIKE_DEBUG |
if(c->arg > max_label || c->arg < 0) |
Pike_fatal("Jump to unknown label?\n"); |
#endif |
tmp = (INT32)PIKE_PC; |
ins_pointer(jumps[c->arg]); |
jumps[c->arg]=tmp; |
break; |
|
case I_ISPTRJUMPARGS: |
#ifdef INS_F_JUMP_WITH_TWO_ARGS |
tmp = INS_F_JUMP_WITH_TWO_ARGS(c->opcode, c->arg, c->arg2, |
(labels[c[1].arg] != -1)); |
if(tmp != -1) |
{ |
|
#ifdef PIKE_DEBUG |
if (c[1].opcode != F_POINTER) { |
Pike_fatal("Expected opcode %s to be followed by a pointer\n", |
instrs[c->opcode - F_OFFSET].name); |
} |
#endif /* PIKE_DEBUG */ |
c++; |
e++; |
UPDATE_F_JUMP(tmp, jumps[c->arg]); |
jumps[c->arg]=~tmp; |
break; |
} |
#endif /* INS_F_JUMP_WITH_TWO_ARGS */ |
|
|
|
|
|
|
|
case I_TWO_ARGS: |
case I_ISJUMPARGS: |
ins_f_byte_with_2_args(c->opcode, c->arg, c->arg2); |
break; |
|
case I_ISPTRJUMPARG: |
#ifdef INS_F_JUMP_WITH_ARG |
tmp = INS_F_JUMP_WITH_ARG(c->opcode, c->arg, (labels[c[1].arg] != -1)); |
if(tmp != -1) |
{ |
|
#ifdef PIKE_DEBUG |
if (c[1].opcode != F_POINTER) { |
Pike_fatal("Expected opcode %s to be followed by a pointer\n", |
instrs[c->opcode - F_OFFSET].name); |
} |
#endif /* PIKE_DEBUG */ |
c++; |
e++; |
UPDATE_F_JUMP(tmp, jumps[c->arg]); |
jumps[c->arg]=~tmp; |
break; |
} |
#endif /* INS_F_JUMP_WITH_ARG */ |
|
|
|
|
|
|
|
case I_HASARG: |
case I_ISJUMPARG: |
ins_f_byte_with_arg(c->opcode, c->arg); |
break; |
|
case 0: |
case I_ISJUMP: |
ins_f_byte(c->opcode); |
break; |
|
#ifdef PIKE_DEBUG |
default: |
Pike_fatal("Unknown instruction type.\n"); |
#endif |
} |
} |
|
#ifdef PIKE_DEBUG |
if (instrs[c->opcode - F_OFFSET].flags & I_HASPOINTER) { |
if ((e+1 >= length) || (c[1].opcode != F_POINTER)) { |
Pike_fatal("Expected instruction %s to be followed by a pointer.\n" |
"Got %s (%d != %d)\n.", |
instrs[c->opcode - F_OFFSET].name, |
(e+1 < length)?instrs[c[1].opcode - F_OFFSET].name:"EOI", |
(e+1 < length)?c[1].opcode:0, F_POINTER); |
} |
} |
#endif /* PIKE_DEBUG */ |
|
#ifdef ALIGN_PIKE_JUMPS |
if(e+1 < length) |
{ |
|
|
|
|
|
|
switch(c->opcode) |
{ |
case F_RETURN: |
case F_VOLATILE_RETURN: |
case F_BRANCH: |
case F_RETURN_0: |
case F_RETURN_1: |
case F_RETURN_LOCAL: |
|
#define CALLS(X) \ |
case PIKE_CONCAT3(F_,X,_AND_RETURN): \ |
case PIKE_CONCAT3(F_MARK_,X,_AND_RETURN): |
|
CALLS(APPLY) |
CALLS(CALL_FUNCTION) |
CALLS(CALL_LFUN) |
CALLS(CALL_BUILTIN) |
while( ((INT32) PIKE_PC & (ALIGN_PIKE_JUMPS-1) ) ) |
ins_byte(0); |
} |
} |
#endif |
|
c++; |
} |
|
for(e=0;e<=max_label;e++) |
{ |
INT32 tmp2=labels[e]; |
|
while(jumps[e]!=-1) |
{ |
#ifdef PIKE_DEBUG |
if(labels[e]==-1) |
Pike_fatal("Hyperspace error: unknown jump point %ld(%ld) at %d (pc=%x).\n", |
PTRDIFF_T_TO_LONG(e), PTRDIFF_T_TO_LONG(max_label), |
labels[e], jumps[e]); |
#endif |
#ifdef INS_F_JUMP |
if(jumps[e] < 0) |
{ |
tmp = READ_F_JUMP(~jumps[e]); |
UPDATE_F_JUMP(~jumps[e], tmp2); |
jumps[e]=tmp; |
continue; |
} |
#endif |
|
tmp = read_pointer(jumps[e]); |
upd_pointer(jumps[e], tmp2 - jumps[e]); |
jumps[e]=tmp; |
} |
} |
|
free(labels); |
|
#ifdef END_FUNCTION |
END_FUNCTION(store_linenumbers); |
#endif |
|
#ifdef PIKE_DEBUG |
if (a_flag > 6) { |
size_t len = (Pike_compiler->new_program->num_program - fun_start)* |
sizeof(PIKE_OPCODE_T); |
fprintf(stderr, "Code at offset %"PRINTSIZET"d through %"PRINTSIZET"d:\n", |
fun_start, Pike_compiler->new_program->num_program-1); |
#ifdef DISASSEMBLE_CODE |
DISASSEMBLE_CODE(Pike_compiler->new_program->program + fun_start, len); |
#else /* !DISASSEMBLE_CODE */ |
{ |
|
} |
#endif /* DISASSEMBLE_CODE */ |
} |
#endif /* PIKE_DEBUG */ |
|
exit_bytecode(); |
|
return entry_point; |
} |
|
|
|
static void do_optimization(int topop, int topush, ...); |
static inline int opcode(int offset); |
static inline int argument(int offset); |
static inline int argument2(int offset); |
|
#include "peep_engine.c" |
|
#ifndef PEEP_STACK_SIZE |
#define PEEP_STACK_SIZE 256 |
#endif |
|
|
|
|
static long stack_depth = 0; |
static p_instr instrstack[PEEP_STACK_SIZE]; |
|
int remove_clear_locals=0x7fffffff; |
static ptrdiff_t eye, len; |
static p_instr *instructions; |
|
|
|
static inline p_instr *insopt2(int f, INT32 a, INT32 b, |
INT_TYPE cl, struct pike_string *cf) |
{ |
p_instr *p; |
|
#ifdef PIKE_DEBUG |
if(!hasarg2(f) && b) |
Pike_fatal("hasarg2(%d /*%s */) is wrong!\n",f,get_f_name(f)); |
#endif |
|
p = instrstack + stack_depth++; |
|
#ifdef PIKE_DEBUG |
if(stack_depth > PEEP_STACK_SIZE) |
Pike_fatal("Instructions stacked too high!!!!!!\n"); |
#endif |
|
p->opcode=f; |
p->line=cl; |
copy_shared_string(p->file, dmalloc_touch_named(struct pike_string *, |
cf, "insopt2")); |
p->arg=a; |
p->arg2=b; |
|
return p; |
} |
|
static inline p_instr *insopt1(int f, INT32 a, INT_TYPE cl, |
struct pike_string *cf) |
{ |
#ifdef PIKE_DEBUG |
if(!hasarg(f) && a) |
Pike_fatal("hasarg(%d /* %s */) is wrong!\n",f,get_f_name(f)); |
#endif |
|
return insopt2(f,a,0,cl, cf); |
} |
|
static inline p_instr *insopt0(int f, INT_TYPE cl, struct pike_string *cf) |
{ |
#ifdef PIKE_DEBUG |
if(hasarg(f)) |
Pike_fatal("hasarg(%d /* %s */) is wrong!\n",f,get_f_name(f)); |
#endif |
return insopt2(f,0,0,cl, cf); |
} |
|
#ifdef PIKE_DEBUG |
static void debug(void) |
{ |
if (num_instrs != (long)instrbuf.s.len / (long)sizeof(p_instr)) { |
Pike_fatal("PEEP: instrbuf lost count (%d != %d)\n", |
num_instrs, (long)instrbuf.s.len / (long)sizeof(p_instr)); |
} |
if(instrbuf.s.len) |
{ |
p_instr *p; |
p=(p_instr *)low_make_buf_space(0, &instrbuf); |
if(!p[-1].file) |
Pike_fatal("No file name on last instruction!\n"); |
} |
} |
#else |
#define debug() |
#endif |
|
|
|
static inline p_instr *instr(int offset) |
{ |
if (offset >= num_instrs) return NULL; |
return ((p_instr *)low_make_buf_space(0, &instrbuf)) - (offset + 1); |
} |
|
static inline int opcode(int offset) |
{ |
p_instr *a; |
a=instr(offset); |
if(a) return a->opcode; |
return -1; |
} |
|
static inline int argument(int offset) |
{ |
p_instr *a; |
a=instr(offset); |
if(a) return a->arg; |
return -1; |
} |
|
static inline int argument2(int offset) |
{ |
p_instr *a; |
a=instr(offset); |
if(a) return a->arg2; |
return -1; |
} |
|
static int advance(void) |
{ |
p_instr *p; |
if(stack_depth) |
{ |
p = instrstack + --stack_depth; |
}else{ |
if (eye >= len) return 0; |
p = instructions + eye; |
eye++; |
} |
insert_opcode(p); |
debug_malloc_touch_named(p->file, "advance"); |
debug(); |
return 1; |
} |
|
static void pop_n_opcodes(int n) |
{ |
int e; |
p_instr *p; |
|
#ifdef PIKE_DEBUG |
if (n > num_instrs) |
Pike_fatal("Popping out of instructions.\n"); |
#endif |
|
p = ((p_instr *)low_make_buf_space(0, &instrbuf)) - n; |
for (e = 0; e < n; e++) { |
free_string(dmalloc_touch_named(struct pike_string *, p[e].file, |
"pop_n_opcodes")); |
} |
num_instrs -= n; |
low_make_buf_space(-((INT32)sizeof(p_instr))*n, &instrbuf); |
} |
|
|
|
static void do_optimization(int topop, int topush, ...) |
{ |
va_list arglist; |
int q=0; |
int oplen; |
struct pike_string *cf; |
INT_TYPE cl=instr(0)->line; |
|
#ifdef PIKE_DEBUG |
if(a_flag>5) |
{ |
int e; |
fprintf(stderr, "PEEP at %ld:", cl); |
for(e = topop; e--;) |
{ |
fprintf(stderr," "); |
dump_instr(instr(e)); |
} |
fprintf(stderr," => "); |
} |
#endif |
|
if (stack_depth + topush > PEEP_STACK_SIZE) { |
|
#ifdef PIKE_DEBUG |
if (a_flag) { |
fprintf(stderr, "PEEP stack full.\n"); |
} |
#endif |
return; |
} |
|
copy_shared_string(cf,dmalloc_touch_named(struct pike_string *, |
instr(0)->file, |
"do_optimization")); |
pop_n_opcodes(topop); |
|
va_start(arglist, topush); |
|
while((oplen = va_arg(arglist, int))) |
{ |
q++; |
switch(oplen) |
{ |
#ifdef PIKE_DEBUG |
default: |
Pike_fatal("Unsupported argument number: %d\n", oplen); |
break; |
#endif /* PIKE_DEBUG */ |
|
case 1: |
{ |
int i=va_arg(arglist, int); |
insopt0(i,cl,cf); |
} |
break; |
|
case 2: |
{ |
int i=va_arg(arglist, int); |
int j=va_arg(arglist, int); |
insopt1(i,j,cl,cf); |
} |
break; |
|
case 3: |
{ |
int i=va_arg(arglist, int); |
int j=va_arg(arglist, int); |
int k=va_arg(arglist, int); |
insopt2(i,j,k,cl,cf); |
} |
break; |
} |
} |
|
va_end(arglist); |
|
|
free_string(dmalloc_touch_named(struct pike_string *, cf, |
"do_optimization")); |
debug(); |
|
#ifdef PIKE_DEBUG |
if(a_flag>5) |
{ |
p_instr *p = instrstack + stack_depth; |
int e; |
for(e=0;e<q;e++) |
{ |
fprintf(stderr," "); |
dump_instr(p-(e+1)); |
} |
fprintf(stderr,"\n"); |
} |
if (q != topush) { |
Pike_fatal("PEEP: Lost track of instructions to push (%d != %d)\n", |
q, topush); |
} |
#endif |
|
|
|
|
|
} |
|
static int asm_opt(void) |
{ |
int relabel = 0; |
|
#ifdef PIKE_DEBUG |
if(a_flag > 3) |
{ |
p_instr *c; |
ptrdiff_t e, length; |
int synch_depth = 0; |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
fprintf(stderr,"Before peep optimization:\n"); |
for(e=0;e<length;e++,c++) |
{ |
if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; |
fprintf(stderr,"<<<%4ld: %*s",(long)c->line,synch_depth,""); |
dump_instr(c); |
fprintf(stderr,"\n"); |
if (c->opcode == F_SYNCH_MARK) synch_depth++; |
} |
} |
#endif |
|
len=instrbuf.s.len/sizeof(p_instr); |
instructions=(p_instr *)instrbuf.s.str; |
instrbuf.s.str=0; |
init_bytecode(); |
|
for(eye = 0; advance();) |
{ |
#ifdef PIKE_DEBUG |
if(a_flag>6) { |
int e; |
fprintf(stderr, "#%ld,%ld:", (long)eye, stack_depth); |
for(e = 4;e--;) { |
fprintf(stderr," "); |
dump_instr(instr(e)); |
} |
|
fprintf(stderr,"\n"); |
} |
#endif |
|
relabel |= low_asm_opt(); |
} |
|
free(instructions); |
|
#ifdef PIKE_DEBUG |
if(a_flag > 4) |
{ |
p_instr *c; |
ptrdiff_t e, length; |
int synch_depth = 0; |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
fprintf(stderr,"After peep optimization:\n"); |
for(e=0;e<length;e++,c++) |
{ |
if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; |
fprintf(stderr,">>>%4ld: %*s",(long)c->line,synch_depth,""); |
dump_instr(c); |
fprintf(stderr,"\n"); |
if (c->opcode == F_SYNCH_MARK) synch_depth++; |
} |
} |
#endif |
|
return relabel; |
} |
|
|