| int optind = 1; |
int optind = 1; |
| #endif |
#endif |
| |
|
| #define CODE_BLOCK_SIZE (1024*1024) |
#define CODE_BLOCK_SIZE (256*1024) |
| Address code_area=0; |
Address code_area=0; |
| Cell code_area_size = CODE_BLOCK_SIZE; |
Cell code_area_size = CODE_BLOCK_SIZE; |
| Address code_here=0; /* does for code-area what HERE does for the dictionary */ |
Address code_here=0; /* does for code-area what HERE does for the dictionary */ |
| Address start_flush=0; /* start of unflushed code */ |
Address start_flush=0; /* start of unflushed code */ |
| |
Cell last_jump=0; /* if the last prim was compiled without jump, this |
| |
is it's number, otherwise this contains 0 */ |
| |
|
| static int no_super=0; /* true if compile_prim should not fuse prims */ |
static int no_super=0; /* true if compile_prim should not fuse prims */ |
| /* --no-dynamic by default on gcc versions >=3.1 (it works with 3.0.4, |
/* --no-dynamic by default on gcc versions >=3.1 (it works with 3.0.4, |
| #ifndef NO_DYNAMIC |
#ifndef NO_DYNAMIC |
| typedef struct { |
typedef struct { |
| Label start; |
Label start; |
| Cell length; /* excluding the jump */ |
Cell length; /* only includes the jump iff superend is true*/ |
| |
Cell restlength; /* length of the rest (i.e., the jump or (on superend) 0) */ |
| char superend; /* true if primitive ends superinstruction, i.e., |
char superend; /* true if primitive ends superinstruction, i.e., |
| unconditional branch, execute, etc. */ |
unconditional branch, execute, etc. */ |
| Cell nimmargs; |
Cell nimmargs; |
| pi->length = symbols1[i+1]-symbols1[i]; |
pi->length = symbols1[i+1]-symbols1[i]; |
| else |
else |
| pi->length = prim_len; |
pi->length = prim_len; |
| |
pi->restlength = symbols1[i+1] - symbols1[i] - pi->length; |
| pi->nimmargs = 0; |
pi->nimmargs = 0; |
| if (debug) |
if (debug) |
| fprintf(stderr, "Prim %3d @ %p %p %p, length=%3d superend=%1d", |
fprintf(stderr, "Prim %3d @ %p %p %p, length=%3d restlength=%2d superend=%1d", |
| i, s1, s2, s3, prim_len, pi->superend); |
i, s1, s2, s3, pi->length, pi->restlength, pi->superend); |
| assert(prim_len>=0); |
assert(prim_len>=0); |
| while (j<prim_len) { |
while (j<(pi->length+pi->restlength)) { |
| if (s1[j]==s3[j]) { |
if (s1[j]==s3[j]) { |
| if (s1[j] != s2[j]) { |
if (s1[j] != s2[j]) { |
| pi->start = NULL; /* not relocatable */ |
pi->start = NULL; /* not relocatable */ |
| if (debug) |
if (debug) |
| fprintf(stderr,"\n non_reloc: engine1!=engine2 offset %3d",j); |
fprintf(stderr,"\n non_reloc: engine1!=engine2 offset %3d",j); |
| |
/* assert(j<prim_len); */ |
| break; |
break; |
| } |
} |
| j++; |
j++; |
| pi->start = NULL; /* not relocatable */ |
pi->start = NULL; /* not relocatable */ |
| if (debug) |
if (debug) |
| fprintf(stderr,"\n non_reloc: engine1!=engine3 offset %3d",j); |
fprintf(stderr,"\n non_reloc: engine1!=engine3 offset %3d",j); |
| |
/* assert(j<prim_len);*/ |
| break; |
break; |
| } |
} |
| j+=4; |
j+=4; |
| #endif |
#endif |
| } |
} |
| |
|
| |
#ifndef NO_DYNAMIC |
| |
void flush_to_here(void) |
| |
{ |
| |
FLUSH_ICACHE(start_flush, code_here-start_flush); |
| |
start_flush=code_here; |
| |
} |
| |
|
| |
void append_jump(void) |
| |
{ |
| |
if (last_jump) { |
| |
PrimInfo *pi = &priminfos[last_jump]; |
| |
|
| |
memcpy(code_here, pi->start+pi->length, pi->restlength); |
| |
code_here += pi->restlength; |
| |
last_jump=0; |
| |
flush_to_here(); |
| |
} |
| |
} |
| |
|
| |
Address append_prim(Cell p) |
| |
{ |
| |
PrimInfo *pi = &priminfos[p]; |
| |
Address old_code_here = code_here; |
| |
|
| |
if (code_area+code_area_size < code_here+pi->length+pi->restlength) { |
| |
/* not enough space for all cases */ |
| |
append_jump(); |
| |
code_here = start_flush = code_area = my_alloc(code_area_size); |
| |
old_code_here = code_here; |
| |
} |
| |
memcpy(code_here, pi->start, pi->length); |
| |
code_here += pi->length; |
| |
if (pi->superend) |
| |
flush_to_here(); |
| |
return old_code_here; |
| |
} |
| |
#endif |
| |
|
| #ifdef NO_IP |
#ifdef NO_IP |
| int nbranchinfos=0; |
int nbranchinfos=0; |
| |
|
| int l = priminfos[p].length; |
int l = priminfos[p].length; |
| Address old_code_here=code_here; |
Address old_code_here=code_here; |
| |
|
| memcpy(code_here, vm_prims[p], l); |
assert(vm_prims[p]==priminfos[p].start); |
| code_here+=l; |
append_prim(p); |
| return (Cell*)(old_code_here+priminfos[p].immargs[0].offset); |
return (Cell*)(old_code_here+priminfos[p].immargs[0].offset); |
| } |
} |
| |
|
| { |
{ |
| Cell *next_code_target; |
Cell *next_code_target; |
| PrimInfo *pi = &priminfos[N_call2]; |
PrimInfo *pi = &priminfos[N_call2]; |
| |
Address old_code_here = append_prim(N_call2); |
| |
|
| memcpy(code_here, pi->start, pi->length); |
next_code_target = (Cell *)(old_code_here + pi->immargs[0].offset); |
| next_code_target = (Cell *)(code_here + pi->immargs[0].offset); |
register_branchinfo(old_code_here + pi->immargs[1].offset, targetptr); |
| register_branchinfo(code_here + pi->immargs[1].offset, targetptr); |
|
| code_here += pi->length; |
|
| return next_code_target; |
return next_code_target; |
| } |
} |
| #endif |
#endif |
| set_rel_target(compile_prim1arg(N_abranch),*(Xt)last_prim); |
set_rel_target(compile_prim1arg(N_abranch),*(Xt)last_prim); |
| } else { |
} else { |
| unsigned j; |
unsigned j; |
| |
Address old_code_here = append_prim(i); |
| |
|
| memcpy(code_here, *last_prim, pi->length); |
|
| for (j=0; j<pi->nimmargs; j++) { |
for (j=0; j<pi->nimmargs; j++) { |
| struct immarg *ia = &(pi->immargs[j]); |
struct immarg *ia = &(pi->immargs[j]); |
| Cell argval = last_start[pi->nimmargs - j]; /* !! specific to prims */ |
Cell argval = last_start[pi->nimmargs - j]; /* !! specific to prims */ |
| if (ia->rel) { /* !! assumption: relative refs are branches */ |
if (ia->rel) { /* !! assumption: relative refs are branches */ |
| register_branchinfo(code_here + ia->offset, argval); |
register_branchinfo(old_code_here + ia->offset, argval); |
| } else /* plain argument */ |
} else /* plain argument */ |
| *(Cell *)(code_here + ia->offset) = argval; |
*(Cell *)(old_code_here + ia->offset) = argval; |
| } |
} |
| code_here += pi->length; |
|
| } |
} |
| if (next_code_target!=NULL) |
if (next_code_target!=NULL) |
| *next_code_target = (Cell)code_here; |
*next_code_target = (Cell)code_here; |
| #elif !defined(NO_DYNAMIC) |
#elif !defined(NO_DYNAMIC) |
| Label prim=(Label)*start; |
Label prim=(Label)*start; |
| unsigned i; |
unsigned i; |
| Address old_code_here=code_here; |
Address old_code_here; |
| static Address last_jump=0; |
|
| |
|
| i = ((Xt)prim)-vm_prims; |
i = ((Xt)prim)-vm_prims; |
| prim = *(Xt)prim; |
prim = *(Xt)prim; |
| return; |
return; |
| } |
} |
| if (i>=npriminfos || priminfos[i].start == 0) { /* not a relocatable prim */ |
if (i>=npriminfos || priminfos[i].start == 0) { /* not a relocatable prim */ |
| if (last_jump) { /* make sure the last sequence is complete */ |
append_jump(); |
| memcpy(code_here, last_jump, IND_JUMP_LENGTH); |
|
| code_here += IND_JUMP_LENGTH; |
|
| last_jump = 0; |
|
| FLUSH_ICACHE(start_flush, code_here-start_flush); |
|
| start_flush=code_here; |
|
| } |
|
| *start = (Cell)prim; |
*start = (Cell)prim; |
| return; |
return; |
| } |
} |
| #ifdef ALIGN_CODE |
#ifdef ALIGN_CODE |
| ALIGN_CODE; |
ALIGN_CODE; |
| #endif |
#endif |
| memcpy(code_here, (Address)prim, priminfos[i].length); |
assert(prim==priminfos[i].start); |
| code_here += priminfos[i].length; |
old_code_here = append_prim(i); |
| last_jump = (priminfos[i].superend) ? 0 : (prim+priminfos[i].length); |
last_jump = (priminfos[i].superend) ? 0 : i; |
| if (last_jump == 0) { |
|
| FLUSH_ICACHE(start_flush, code_here-start_flush); |
|
| start_flush=code_here; |
|
| } |
|
| *start = (Cell)old_code_here; |
*start = (Cell)old_code_here; |
| return; |
return; |
| #else /* !defined(DOUBLY_INDIRECT), no code replication */ |
#else /* !defined(DOUBLY_INDIRECT), no code replication */ |