/* Byte code fragment construction functions */ #include "types.h" /* Initialize a fragment */ void iz_frag(Frag *f, ptrdiff_t alignment) { f->start = (unsigned char *)joe_malloc(f->size = 1024); f->len = 0; f->align = alignment; } void fin_code(Frag *f) { f->start = (unsigned char *)joe_realloc(f->start, f->len); f->size = f->len; } void clr_frag(Frag *f) { joe_free(f->start); } /* Expand a fragment */ /* Expand code block by at least 'size' words */ static void expand_frag(Frag *frag, ptrdiff_t size) { if ((frag->size >> 1) > size) // Grow by 50% frag->size = frag->size + (frag->size >> 1); else // Grow by 50% plus requested size frag->size += frag->size + (frag->size >> 1); frag->start = (unsigned char *)joe_realloc(frag->start, frag->size); } /* Emit a byte: this does no alignment */ ptrdiff_t emitb_noalign(Frag *f, char c) { ptrdiff_t start; if (f->len + SIZEOF(unsigned char) > f->size) expand_frag(f, SIZEOF(unsigned char)); start = f->len; f->start[f->len++] = (unsigned char)c; return start; } /* Align to some power of 2 */ void align_frag(Frag *f,ptrdiff_t alignment) { ptrdiff_t x; ptrdiff_t add = align_o(f->len, alignment); for (x = 0; x != add; ++x) emitb_noalign(f, '-'); } /* Emit a byte and align */ ptrdiff_t emitb(Frag *f, char c) { ptrdiff_t ofst = emitb_noalign(f, c); if (f->len & (f->align - 1)) align_frag(f, f->align); return ofst; } /* Emit a short */ ptrdiff_t emith(Frag *f, short c) { ptrdiff_t start; if (f->len & (SIZEOF(short) - 1)) align_frag(f, SIZEOF(short)); if (f->len + SIZEOF(short) > f->size) expand_frag(f, SIZEOF(short)); start = f->len; *(short *)(f->start + f->len) = c; f->len += SIZEOF(short); if (f->len & (f->align - 1)) align_frag(f, f->align); return start; } /* Emit an integer */ ptrdiff_t emiti(Frag *f, int c) { ptrdiff_t start; if (f->len & (SIZEOF(int) - 1)) align_frag(f, SIZEOF(int)); if (f->len + SIZEOF(int) > f->size) expand_frag(f, SIZEOF(int)); start = f->len; *(int *)(f->start + f->len) = c; f->len += SIZEOF(int); if (f->len & (f->align - 1)) align_frag(f, f->align); return start; } /* Emit a double */ ptrdiff_t emitd(Frag *f, double d) { ptrdiff_t start; if (f->len & (SIZEOF(double) - 1)) align_frag(f, SIZEOF(double)); if (f->len + SIZEOF(double) > f->size) expand_frag(f, SIZEOF(double)); start = f->len; *(double *)(f->start + f->len) = d; f->len += SIZEOF(double); if (f->len & (f->align - 1)) align_frag(f, f->align); return start; } /* Emit a pointer */ ptrdiff_t emitp(Frag *f, void *p) { ptrdiff_t start; if (f->len & (SIZEOF(void *) - 1)) align_frag(f, SIZEOF(void *)); if (f->len + SIZEOF(void *) > f->size) expand_frag(f, SIZEOF(void *)); start = f->len; *(void **)(f->start + f->len) = p; f->len += SIZEOF(void *); if (f->len & (f->align - 1)) align_frag(f, f->align); return start; } /* Append a string to the code block */ ptrdiff_t emits(Frag *f, unsigned char *s, int len) { ptrdiff_t start; start = emiti(f, len); if (f->len + len + 1 > f->size) expand_frag(f, len + 1); if (len) mcpy(f->start + f->len, s, len); f->start[f->len + len] = 0; f->len += len + 1; if (f->len & (f->align - 1)) align_frag(f, f->align); return start; } ptrdiff_t emit_branch(Frag *f, ptrdiff_t target) { ptrdiff_t ofst = emiti(f, 0); fragi(f, ofst) = (int)(target - ofst); return ofst; } void fixup_branch(Frag *f, ptrdiff_t pos) { align_frag(f, SIZEOF(int)); fragi(f, pos) = (int)(f->len - pos); } /* Modify each item in a linked-list to point to here */ void frag_link(Frag *f, ptrdiff_t chain) { ptrdiff_t ket; align_frag(f, SIZEOF(int)); ket = f->len; while (chain) { int next = fragi(f, chain); fragi(f, chain) = (int)(ket - chain); chain = next; } } short fetchh(Frag *f, ptrdiff_t *pcp) { ptrdiff_t pc = *pcp; short i; pc += align_o(pc, SIZEOF(short)); i = fragh(f, pc); pc += SIZEOF(short); if (pc & (f->align - 1)) pc += align_o(pc, f->align); *pcp = pc; return i; } int fetchi(Frag *f, ptrdiff_t *pcp) { ptrdiff_t pc = *pcp; int i; pc += align_o(pc, SIZEOF(int)); i = fragi(f, pc); pc += SIZEOF(int); if (pc & (f->align - 1)) pc += align_o(pc, f->align); *pcp = pc; return i; } void *fetchp(Frag *f, ptrdiff_t *pcp) { ptrdiff_t pc = *pcp; void *p; pc += align_o(pc, SIZEOF(void *)); p = fragp(f, pc); pc += SIZEOF(void *); if (pc & (f->align - 1)) pc += align_o(pc, f->align); *pcp = pc; return p; }