U8 *LexStatement2Bin(CCompCtrl *cc, I64 *_type, I64 comp_flags=0) {//Compile one cc statement to bin code. I64 size, i, j, k, *res = INVALID_PTR; CCodeCtrl *tmpcbh; if (_type) *_type = RT_I64; Btr(&cc->flags, CCf_PASS_TRACE_PRESENT); if (cc->aot_depth == 2) COCPush(cc); COCInit(cc); if (!ParseStatement(cc,,, comp_flags)) { if (cc->coc.coc_head.next != &cc->coc.coc_head) { cc->coc.coc_head.last->ic_flags &= ~ICF_RES_NOT_USED; ICAdd(cc, IC_RETURN_VAL2, 0, 0); ICAdd(cc, IC_RET, 0, 0); if (res = COCCompile(cc, &size, NULL, _type)) { if (cc->flags & CCF_AOT_COMPILE) { j = cc->aotc->rip; k = (size + 7) >> 3; for (i = 0; i < k; i++) AOTStoreCodeU64(cc, res[i]); Free(res); res = j; } } } //TODO: else del misc? } else //TODO: too dangerous to del Misc? QueueDel(&cc->coc.coc_head.next); if (cc->aot_depth == 2) { tmpcbh = COCPopNoFree(cc); COCAppend(cc, tmpcbh); } return res; } CAOT *CompJoin(CCompCtrl *cc, I64 comp_flags, U8 *map_name=NULL, U8 mapfile_drive_let=0) { CAOTCtrl *aotc, *old_aot = cc->aotc; I64 i, j, l; U8 *buf; CAOTBinBlk *tmpbin; CAOTImportExport *tmpie; Bool okay = TRUE; CLexHashTableContext *htc = MAlloc(sizeof(CLexHashTableContext)); CAOT *res = CAlloc(sizeof(CAOT)), *parent; if (parent = cc->aot) { res->parent_aot = parent; QueueInsert(res, parent->last); } else QueueInit(res); cc->aot = res; res->next_ie = res->last_ie = &res->next_ie; cc->aotc = aotc = CAlloc(sizeof(CAOTCtrl)); cc->aot_depth++; aotc->bin = CAlloc(sizeof(CAOTBinBlk)); aotc->max_align_bits = 0; aotc->org = INVALID_PTR; MemCopy(htc, &cc->htc, sizeof(CLexHashTableContext)); if (cc->htc.fun) cc->htc.global_hash_table = HashTableNew(128); else cc->htc.global_hash_table = HashTableNew(1024); if (cc->flags & CCF_AOT_COMPILE) { cc->htc.define_hash_table = cc->htc.global_hash_table; if (cc->aot_depth <= 1) cc->htc.global_hash_table->next = cmp.asm_hash; else cc->htc.global_hash_table->next = htc->global_hash_table; } else cc->htc.global_hash_table->next = Fs->hash_table; cc->htc.hash_table_list = cc->htc.local_hash_table = HashTableNew(16); cc->htc.local_hash_table->next = cc->htc.global_hash_table; cc->htc.local_var_list = cc->htc.fun; //ZealC local variables cc->htc.fun = NULL; try { if (comp_flags & CMPF_LEX_FIRST) Lex(cc); if (!(comp_flags & CMPF_ONE_ASM_INS)) comp_flags |= CMPF_PRS_SEMICOLON; if (cc->flags & CCF_AOT_COMPILE) { while (cc->token != TK_EOF) { buf = LexStatement2Bin(cc, NULL, comp_flags); if (buf != INVALID_PTR) { tmpie = CAlloc(sizeof(CAOTImportExport)); tmpie->type = IET_MAIN; tmpie->rip = buf; QueueInsert(tmpie, res->last_ie); } if (comp_flags & CMPF_ASM_BLK) break; } } else ParseStatement(cc,,, comp_flags); AOTGlobalsResolve(cc, res); } catch { if (Fs->except_ch == 'Compiler' && !(comp_flags & CMPF_ASM_BLK)) { LexPutPos(cc); Fs->catch_except = TRUE; } okay = FALSE; } if (!okay) { if (cc->error_count < 1) cc->error_count = 1; cc->aot = res->parent_aot; Free(res); LinkedListDel(aotc->bin); res = NULL; } else { if (map_name) MapFileWrite(cc->htc.global_hash_table, map_name, mapfile_drive_let); HashTableDel(cc->htc.local_hash_table); HashTableDel(cc->htc.global_hash_table); if (!aotc->num_bin_U8s) res->buf = NULL; else { if (cc->flags & CCF_AOT_COMPILE) res->buf = MAlloc(aotc->num_bin_U8s); else { if (aotc->org == INVALID_PTR) res->buf = MAlloc(aotc->num_bin_U8s, Fs->code_heap); else res->buf = aotc->org; } res->aot_U8s = aotc->num_bin_U8s; tmpbin = aotc->bin; j = 0; l = aotc->num_bin_U8s; while (tmpbin) { i = l; if (i > AOT_BIN_BLK_SIZE) i = AOT_BIN_BLK_SIZE; MemCopy(res->buf + j, tmpbin->body, i); j += i; l -= i; tmpbin = tmpbin->next; } } LinkedListDel(aotc->bin); res->abss = aotc->abss; res->heap_globals = aotc->heap_globals; res->max_align_bits = aotc->max_align_bits; res->org = aotc->org; } cc->aot = parent; MemCopy(&cc->htc, htc, sizeof(CLexHashTableContext)); Free(htc); Free(aotc); cc->aotc = old_aot; cc->aot_depth--; return res; } CAOT *CompBuf(U8 *buf, U8 *map_name=NULL, I64 *error_count=NULL, I64 *warning_count=NULL, U8 mapfile_drive_let=0) { CCompCtrl *cc; CAOT *res = NULL; cc = CompCtrlNew(buf, CCF_DONT_FREE_BUF); cc->flags |= CCF_AOT_COMPILE; QueueInsert(cc, Fs->last_cc); res = CompJoin(cc, CMPF_LEX_FIRST, map_name, mapfile_drive_let); if (error_count) *error_count = cc->error_count; if (warning_count) *warning_count = cc->warning_count; QueueRemove(cc); if (res) CompCtrlDel(cc); return res; } U0 CompFixUpJITAsm(CCompCtrl *cc, CAOT *tmpaot) { I64 i, rip2 = tmpaot->buf + tmpaot->rip, *str = NULL; U8 *ptr; CCodeMisc *g_lb; CAOTAbsAddr *tmpa, *tmpa1; CAOTImportExport *tmpie, *tmpie1; CHashExport *tmpex; tmpa = tmpaot->abss; while (tmpa) { tmpa1 = tmpa->next; ptr = rip2 + tmpa->rip; switch [tmpa->type] { case AAT_ADD_U8: *ptr(U8 *) += rip2; break; case AAT_SUB_U8: *ptr(U8 *) -= rip2; break; case AAT_ADD_U16: *ptr(U16 *) += rip2; break; case AAT_SUB_U16: *ptr(U16 *) -= rip2; break; case AAT_ADD_U32: *ptr(U32 *) += rip2; break; case AAT_SUB_U32: *ptr(U32 *) -= rip2; break; case AAT_ADD_U64: *ptr(I64 *) += rip2; break; case AAT_SUB_U64: *ptr(I64 *) -= rip2; break; } Free(tmpa); tmpa = tmpa1; } tmpie = tmpaot->next_ie; while (tmpie != &tmpaot->next_ie) { tmpie1 = tmpie->next; if (tmpie->str) { Free(str); str = tmpie->str; } switch (tmpie->type) { case IET_REL32_EXPORT: case IET_IMM32_EXPORT: case IET_REL64_EXPORT: case IET_IMM64_EXPORT: tmpex = CAlloc(sizeof(CHashExport)); tmpex->str = str; str = NULL; tmpex->type = HTT_EXPORT_SYS_SYM | HTF_IMM; if (tmpie->type == IET_IMM32_EXPORT || tmpie->type == IET_IMM64_EXPORT) tmpex->val = tmpie->rip; else tmpex->val = tmpie->rip + rip2; tmpex->src_link = tmpie->src_link; tmpie->src_link = NULL; HashAdd(tmpex, Fs->hash_table); SysSymImportsResolve(tmpex->str); break; case IET_REL_I0...IET_IMM_I64: if (tmpie->str) { if (tmpie->flags & IEF_GOTO_LABEL) { if (!(g_lb = COCGoToLabelFind(cc, str))) "Unresolved Reference:%s\n", str; else { g_lb->use_count++; g_lb = OptLabelFwd(g_lb); i = g_lb->addr + tmpaot->buf; } tmpex = NULL; } else { if (!(tmpex = HashFind(str, Fs->hash_table, HTG_ALL - HTT_IMPORT_SYS_SYM))) "Unresolved Reference:%s\n", str; else { if (tmpex->type & HTT_FUN) i = tmpex(CHashFun *)->exe_addr; else if (tmpex->type & HTT_GLOBAL_VAR) i = tmpex(CHashGlobalVar *)->data_addr; else i = tmpex->val; } g_lb = NULL; } } if (tmpex || g_lb) { ptr = tmpie->rip + rip2; switch [tmpie->type] { case IET_REL_I0: case IET_IMM_U0: break; case IET_REL_I8: if (!(I8_MIN <= i - ptr - 1 <= I8_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U8 *) = i - ptr - 1; break; case IET_IMM_U8: *ptr(U8 *) = i; break; case IET_REL_I16: if (!(I16_MIN <= i - ptr - 2 <= I16_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U16 *) = i - ptr - 2; break; case IET_IMM_U16: *ptr(U16 *) = i; break; case IET_REL_I32: if (!(I32_MIN <= i - ptr - 4 <= I32_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U32 *) = i - ptr - 4; break; case IET_IMM_U32: *ptr(U32 *) = i; break; case IET_REL_I64: *ptr(I64 *) = i - ptr - 8; break; case IET_IMM_I64: *ptr(I64 *) = i; break; } } break; } Free(tmpie->src_link); Free(tmpie); tmpie = tmpie1; } Free(str); if (!cc->aot_depth && Bt(&cc->opts, OPTf_TRACE)) Un(rip2, tmpaot->aot_U8s, 64); QueueRemove(tmpaot); Free(tmpaot); } U0 CompFixUpAOTAsm(CCompCtrl *cc, CAOT *tmpaot) { CAOTCtrl *aotc = cc->aotc; I64 i, rip2 = tmpaot->rip + cc->aotc->rip; U8 *ptr; CCodeMisc *g_lb = NULL; CAOTAbsAddr *tmpa, *tmpa1; CAOTImportExport *tmpie, *tmpie1; tmpa = tmpaot->abss; while (tmpa) { tmpa1 = tmpa->next; tmpa->next = aotc->abss; ptr = tmpaot->buf + tmpaot->rip + tmpa->rip; switch [tmpa->type] { case AAT_ADD_U8: *ptr(U8 *) += rip2; break; case AAT_SUB_U8: *ptr(U8 *) -= rip2; break; case AAT_ADD_U16: *ptr(U16 *) += rip2; break; case AAT_SUB_U16: *ptr(U16 *) -= rip2; break; case AAT_ADD_U32: *ptr(U32 *) += rip2; break; case AAT_SUB_U32: *ptr(U32 *) -= rip2; break; case AAT_ADD_U64: *ptr(I64 *) += rip2; break; case AAT_SUB_U64: *ptr(I64 *) -= rip2; break; } aotc->abss = tmpa; tmpa->rip += rip2; tmpa = tmpa1; } tmpie = tmpaot->next_ie; while (tmpie != &tmpaot->next_ie) { tmpie1 = tmpie->next; QueueRemove(tmpie); if (IET_REL_I0 <= tmpie->type <= IET_IMM_I64) { if (tmpie->str) { if (tmpie->flags & IEF_GOTO_LABEL) { if (!(g_lb = COCGoToLabelFind(cc, tmpie->str))) "Unresolved Reference:%s\n", tmpie->str; else { g_lb->use_count++; g_lb = OptLabelFwd(g_lb); } } else g_lb = NULL; } } else g_lb = NULL; ptr = tmpaot->buf + tmpaot->rip + tmpie->rip; if (g_lb) { i = g_lb->addr + tmpaot->buf; switch [tmpie->type] { case IET_REL_I0: case IET_IMM_U0: break; case IET_REL_I8: if (!(I8_MIN <= i - ptr - 1 <= I8_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U8 *) = i - ptr - 1; break; case IET_IMM_U8: *ptr(U8 *) = i; break; case IET_REL_I16: if (!(I16_MIN <= i - ptr - 2 <= I16_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U16 *) = i - ptr - 2; break; case IET_IMM_U16: *ptr(U16 *) = i; break; case IET_REL_I32: if (!(I32_MIN <= i - ptr - 4 <= I32_MAX)) LexExcept(cc, "Branch out of range at "); *ptr(U32 *) = i - ptr - 4; break; case IET_IMM_U32: *ptr(U32 *) = i; break; case IET_REL_I64: *ptr(I64 *) = i - ptr - 8; break; case IET_IMM_I64: *ptr(I64 *) = i; break; } Free(tmpie->src_link); Free(tmpie); } else { switch (tmpie->type) { start: case IET_REL32_EXPORT: case IET_IMM32_EXPORT: case IET_REL64_EXPORT: case IET_IMM64_EXPORT: case IET_IMM_U0: case IET_IMM_U8: case IET_IMM_U16: case IET_IMM_U32: case IET_IMM_I64: case IET_REL_I0: break; case IET_REL_I8: *ptr(U8 *) -= rip2; break; case IET_REL_I16: *ptr(U16 *) -= rip2; break; case IET_REL_I32: *ptr(U32 *) -= rip2; break; case IET_REL_I64: *ptr(I64 *) -= rip2; break; end: tmpie->rip += rip2; break; } tmpie->aot = NULL; QueueInsert(tmpie, tmpaot->parent_aot->last_ie); } tmpie = tmpie1; } } I64 Comp(U8 *filename, U8 *map_name=NULL, U8 *out_name=NULL, U8 mapfile_drive_let=0) {//AOT Compile ZC or PRJ file and output ZXE file. Returns err_count. U8 *ptr, *fbuf = NULL, *fbuf2 = NULL, *fbuf3 = NULL, *patch_table = MAlloc(0x20000); CAOT *tmpaot; I64 i, count, size = 0, error_count = 0, warning_count = 0, aot_U8s = 0; CZXE *zxe; CAOTImportExport *tmpie, *tmpie1; CAOTAbsAddr *tmpa, *tmpa1; CAOTHeapGlobalRef *tmphgr, *tmphgr1; CAOTHeapGlobal *tmphg, *tmphg1; fbuf = ExtDefault(filename, "PRJ"); fbuf2 = MStrPrint("#include \"%s\"", fbuf); if (map_name) fbuf3 = ExtDefault(map_name, "MAP"); if (tmpaot = CompBuf(fbuf2, fbuf3, &error_count, &warning_count, mapfile_drive_let)) { aot_U8s = tmpaot->aot_U8s; ptr = patch_table; //See Load() count = 0; tmpa = tmpaot->abss; while (tmpa) { if (!(tmpa->type & IEF_IMM_NOT_REL)) count++; tmpa = tmpa->next; } if (count) { *ptr++ = IET_ABS_ADDR; *ptr(U32 *)++ = count; *ptr++ = 0; tmpa = tmpaot->abss; while (tmpa) { tmpa1 = tmpa->next; if (!(tmpa->type & IEF_IMM_NOT_REL)) *ptr(U32 *)++ = tmpa->rip; Free(tmpa); tmpa = tmpa1; } } tmphg = tmpaot->heap_globals; while (tmphg) { tmphg1 = tmphg->next; count = 0; tmphgr = tmphg->references; while (tmphgr) { count++; tmphgr = tmphgr->next; } if (count) { *ptr++ = IET_DATA_HEAP; *ptr(U32 *)++ = count; if (tmphg->str) { i = StrLen(tmphg->str); MemCopy(ptr, tmphg->str, i + 1); Free(tmphg->str); ptr += i + 1; } else *ptr++ = 0; *ptr(I64 *)++ = tmphg->size; tmphgr = tmphg->references; while (tmphgr) { tmphgr1 = tmphgr->next; *ptr(U32 *)++ = tmphgr->rip; Free(tmphgr); tmphgr = tmphgr1; } } Free(tmphg); tmphg = tmphg1; } //Do exports first tmpie = tmpaot->next_ie; while (tmpie != &tmpaot->next_ie) { tmpie1 = tmpie->next; if (!tmpie->type || IET_REL32_EXPORT <= tmpie->type <= IET_IMM64_EXPORT) { QueueRemove(tmpie); *ptr++ = tmpie->type; *ptr(U32 *)++ = tmpie->rip; if (tmpie->str) { i = StrLen(tmpie->str); MemCopy(ptr, tmpie->str, i + 1); Free(tmpie->str); ptr += i + 1; } else *ptr++ = 0; Free(tmpie->src_link); Free(tmpie); } tmpie = tmpie1; } //Do imports second tmpie = tmpaot->next_ie; while (tmpie != &tmpaot->next_ie) { tmpie1 = tmpie->next; QueueRemove(tmpie); *ptr++ = tmpie->type; if (tmpie->aot) tmpie->rip += tmpie->aot->rip2; *ptr(U32 *)++ = tmpie->rip; if (tmpie->str) { i = StrLen(tmpie->str); MemCopy(ptr, tmpie->str, i + 1); Free(tmpie->str); ptr += i + 1; } else *ptr++ = 0; Free(tmpie->src_link); Free(tmpie); tmpie = tmpie1; } *ptr++ = IET_END; MemSet(ptr, 0, 16); i = ptr - patch_table; //Needs 16 ALIGN size = (sizeof(CZXE) + aot_U8s + i + 15) & -16; zxe = MAlloc(size); zxe->jmp = 0xEB + 256 * (sizeof(CZXE) - 2); #assert sizeof(CZXE) - 2 <= I8_MAX zxe->reserved = 0; zxe->signature = ZXE_SIGNATURE_VAL; zxe->org = tmpaot->org; zxe->module_align_bits = tmpaot->max_align_bits; zxe->patch_table_offset = sizeof(CZXE) + aot_U8s; zxe->file_size = size; MemCopy(zxe(U8 *) + sizeof(CZXE), tmpaot->buf, aot_U8s); MemCopy(zxe(U8 *) + sizeof(CZXE) + aot_U8s, patch_table, size - aot_U8s - sizeof(CZXE)); Free(fbuf2); if (out_name) fbuf2 = ExtDefault(out_name, "ZXE"); else fbuf2 = ExtChange(fbuf, "ZXE"); FileWrite(fbuf2, zxe, size); Free(zxe); Free(tmpaot->buf); QueueDel(tmpaot); Free(tmpaot); } Free(patch_table); Free(fbuf); Free(fbuf2); Free(fbuf3); Print("Errs:%d Warns:%d Code:%X Size:%X\n", error_count, warning_count, aot_U8s, size); return error_count; } I64 ExePutS(U8 *buf, U8 *filename=NULL, I64 ccf_flags=0, CLexHashTableContext *htc=NULL) {//JIT Compile and execute text from a puts(""). I64 res; Bool okay = TRUE; CCompCtrl *cc; if (!filename) filename = blkdev.tmp_filename; cc = CompCtrlNew(buf, ccf_flags | CCF_DONT_FREE_BUF, filename); if (Fs->last_cc != &Fs->next_cc) { cc->opts = Fs->last_cc->opts; if (htc) { cc->flags = cc->flags & ~CCF_ASM_EXPRESSIONS | htc->old_flags & CCF_ASM_EXPRESSIONS; MemCopy(&cc->htc, htc, sizeof(CLexHashTableContext)); } } QueueInsert(cc, Fs->last_cc); try { Lex(cc); res = ExeCmdLine(cc); } catch { if (Fs->except_ch == 'Compiler' || Fs->except_ch == 'Break') { Fs->catch_except = TRUE; okay = FALSE; res = 0; } } QueueRemove(cc); if (okay) CompCtrlDel(cc); //TODO: can crash return res; } I64 ExePrint(U8 *format, ...) {//JIT Compile and execute text from a printf(). I64 res; U8 *buf = StrPrintJoin(NULL, format, argc, argv); res = ExePutS(buf); Free(buf); return res; } I64 ExeFile(U8 *name, I64 ccf_flags=0) {//JIT Compile and execute a file. I64 res; U8 *name2 = ExtDefault(name, "ZC"), *st = MStrPrint("#include \"%s\";", name2); res = ExePutS(st, name, ccf_flags); Free(st); Free(name2); return res; } I64 RunFile(U8 *name, I64 ccf_flags=0, ...) {//ExeFile() with args using LastFun(). ExeFile(name, ccf_flags); return LastFun(argc, argv); } I64 ExePutS2(U8 *buf, U8 *filename=NULL, I64 ccf_flags=0) {//throws exceptions I64 res; CCompCtrl *cc; if (!filename) filename = blkdev.tmp_filename; cc = CompCtrlNew(buf, ccf_flags | CCF_DONT_FREE_BUF, filename); if (Fs->last_cc != &Fs->next_cc) cc->opts = Fs->last_cc->opts; QueueInsert(cc, Fs->last_cc); Lex(cc); res = ExeCmdLine(cc); QueueRemove(cc); CompCtrlDel(cc); return res; } I64 ExePrint2(U8 *format, ...) {//throws exceptions I64 res; U8 *buf = StrPrintJoin(NULL, format, argc, argv); res = ExePutS2(buf); Free(buf); return res; } I64 ExeFile2(U8 *name, I64 ccf_flags=0) {//throws exceptions I64 res; U8 *name2 = ExtDefault(name, "ZC"), *st = MStrPrint("#include \"%s\";", name2); res = ExePutS2(st, name, ccf_flags); Free(st); Free(name2); return res; } I64 RunFile2(U8 *name, I64 ccf_flags=0, ...) {//ExeFile2() with args using LastFun(). throws exceptions. ExeFile2(name, ccf_flags); return LastFun(argc, argv); } I64 StreamExePrint(U8 *format, ...) {//Causes value from stream to be used in an #exe{} block. U8 *buf = StrPrintJoin(NULL, format, argc, argv); I64 res = 0; CLexHashTableContext *htc; CCompCtrl *cc = Fs->last_cc; if (cc == &Fs->next_cc) PrintErr("Not Compiling\n"); else { if (!(cc->flags & CCF_EXE_BLK)) LexExcept(cc, "StreamExePrint only allowed in AOT compiled #exe{} mode."); if (htc = cc->htc.next) res = ExePutS(buf,,, htc); } Free(buf); return res; } U0 CInit() { CompLoadDefines; CompFillTables; QueueInit(&cmp.ic_nop); cmp.ic_nop.ic_class = cmp.internal_types[RT_I64]; cmp.ic_nop.ic_code = IC_NOP1; AsmHashLoad; UAsmHashLoad; } CInit;