U8 *LexStmt2Bin(CCmpCtrl *cc,I64 *_type,I64 cmp_flags=0) {//Compile one cc stmt 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 (!PrsStmt(cc,,,cmp_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? QueDel(&cc->coc.coc_head.next); if (cc->aot_depth==2) { tmpcbh=COCPopNoFree(cc); COCAppend(cc,tmpcbh); } return res; } CAOT *CmpJoin(CCmpCtrl *cc,I64 cmp_flags,U8 *map_name=NULL,U8 mapfile_drv_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; QueIns(res,parent->last); } else QueInit(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; MemCpy64(htc,&cc->htc,sizeof(CLexHashTableContext)/8); if (cc->htc.fun) cc->htc.glbl_hash_table=HashTableNew(128); else cc->htc.glbl_hash_table=HashTableNew(1024); if (cc->flags&CCF_AOT_COMPILE) { cc->htc.define_hash_table=cc->htc.glbl_hash_table; if (cc->aot_depth<=1) cc->htc.glbl_hash_table->next=cmp.asm_hash; else cc->htc.glbl_hash_table->next=htc->glbl_hash_table; } else cc->htc.glbl_hash_table->next=Fs->hash_table; cc->htc.hash_table_lst=cc->htc.local_hash_table=HashTableNew(16); cc->htc.local_hash_table->next=cc->htc.glbl_hash_table; cc->htc.local_var_lst=cc->htc.fun; //HolyC local vars cc->htc.fun=NULL; try { if (cmp_flags&CMPF_LEX_FIRST) Lex(cc); if (!(cmp_flags&CMPF_ONE_ASM_INS)) cmp_flags|=CMPF_PRS_SEMICOLON; if (cc->flags&CCF_AOT_COMPILE) { while (cc->token!=TK_EOF) { buf=LexStmt2Bin(cc,NULL,cmp_flags); if (buf!=INVALID_PTR) { tmpie=CAlloc(sizeof(CAOTImportExport)); tmpie->type=IET_MAIN; tmpie->rip=buf; QueIns(tmpie,res->last_ie); } if (cmp_flags&CMPF_ASM_BLK) break; } } else PrsStmt(cc,,,cmp_flags); AOTGlblsResolve(cc,res); } catch { if (Fs->except_ch=='Compiler' && !(cmp_flags&CMPF_ASM_BLK)) { LexPutPos(cc); Fs->catch_except=TRUE; } okay=FALSE; } if (!okay) { if (cc->error_cnt<1) cc->error_cnt=1; cc->aot=res->parent_aot; Free(res); LinkedLstDel(aotc->bin); res=NULL; } else { if (map_name) MapFileWrite(cc->htc.glbl_hash_table,map_name,mapfile_drv_let); HashTableDel(cc->htc.local_hash_table); HashTableDel(cc->htc.glbl_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; MemCpy(res->buf+j,tmpbin->body,i); j+=i; l-=i; tmpbin=tmpbin->next; } } LinkedLstDel(aotc->bin); res->abss=aotc->abss; res->heap_glbls=aotc->heap_glbls; res->max_align_bits=aotc->max_align_bits; res->org=aotc->org; } cc->aot=parent; MemCpy64(&cc->htc,htc,sizeof(CLexHashTableContext)/8); Free(htc); Free(aotc); cc->aotc=old_aot; cc->aot_depth--; return res; } CAOT *CmpBuf(U8 *buf,U8 *map_name=NULL, I64 *error_cnt=NULL, I64 *warning_cnt=NULL,U8 mapfile_drv_let=0) { CCmpCtrl *cc; CAOT *res=NULL; cc=CmpCtrlNew(buf,CCF_DONT_FREE_BUF); cc->flags|=CCF_AOT_COMPILE; QueIns(cc,Fs->last_cc); res=CmpJoin(cc,CMPF_LEX_FIRST,map_name,mapfile_drv_let); if (error_cnt) *error_cnt=cc->error_cnt; if (warning_cnt) *warning_cnt=cc->warning_cnt; QueRem(cc); if (res) CmpCtrlDel(cc); return res; } U0 CmpFixUpJITAsm(CCmpCtrl *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_cnt++; 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_GLBL_VAR) i=tmpex(CHashGlblVar *)->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); QueRem(tmpaot); Free(tmpaot); } U0 CmpFixUpAOTAsm(CCmpCtrl *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; QueRem(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_cnt++; 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; QueIns(tmpie,tmpaot->parent_aot->last_ie); } tmpie=tmpie1; } } I64 Cmp(U8 *filename,U8 *map_name=NULL,U8 *out_name=NULL,U8 mapfile_drv_let=0) {//AOT Compile HC or PRJ file a and output BIN file. Returns err_cnt. U8 *ptr,*fbuf=NULL,*fbuf2=NULL,*fbuf3=NULL, *patch_table=MAlloc(0x20000); CAOT *tmpaot; I64 i,cnt,size=0,error_cnt=0,warning_cnt=0,aot_U8s=0; CBinFile *bfh; CAOTImportExport *tmpie,*tmpie1; CAOTAbsAddr *tmpa,*tmpa1; CAOTHeapGlblRef *tmphgr,*tmphgr1; CAOTHeapGlbl *tmphg,*tmphg1; fbuf=ExtDft(filename,"PRJ.Z"); fbuf2=MStrPrint("#include \"%s\"",fbuf); if (map_name) fbuf3=ExtDft(map_name,"MAP.Z"); if (tmpaot=CmpBuf(fbuf2,fbuf3,&error_cnt,&warning_cnt,mapfile_drv_let)) { aot_U8s=tmpaot->aot_U8s; ptr=patch_table; //See Load() cnt=0; tmpa=tmpaot->abss; while (tmpa) { if (!(tmpa->type&IEF_IMM_NOT_REL)) cnt++; tmpa=tmpa->next; } if (cnt) { *ptr++=IET_ABS_ADDR; *ptr(U32 *)++=cnt; *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_glbls; while (tmphg) { tmphg1=tmphg->next; cnt=0; tmphgr=tmphg->references; while (tmphgr) { cnt++; tmphgr=tmphgr->next; } if (cnt) { *ptr++=IET_DATA_HEAP; *ptr(U32 *)++=cnt; if (tmphg->str) { i=StrLen(tmphg->str); MemCpy(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) { QueRem(tmpie); *ptr++=tmpie->type; *ptr(U32 *)++=tmpie->rip; if (tmpie->str) { i=StrLen(tmpie->str); MemCpy(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; QueRem(tmpie); *ptr++=tmpie->type; if (tmpie->aot) tmpie->rip+=tmpie->aot->rip2; *ptr(U32 *)++=tmpie->rip; if (tmpie->str) { i=StrLen(tmpie->str); MemCpy(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(CBinFile)+aot_U8s+i+15)&-16; bfh=MAlloc(size); bfh->jmp=0xEB+256*(sizeof(CBinFile)-2); #assert sizeof(CBinFile)-2<=I8_MAX bfh->reserved=0; bfh->bin_signature=BIN_SIGNATURE_VAL; bfh->org=tmpaot->org; bfh->module_align_bits=tmpaot->max_align_bits; bfh->patch_table_offset=sizeof(CBinFile)+aot_U8s; bfh->file_size=size; MemCpy(bfh(U8 *)+sizeof(CBinFile),tmpaot->buf,aot_U8s); MemCpy(bfh(U8 *)+sizeof(CBinFile)+aot_U8s,patch_table, size-aot_U8s-sizeof(CBinFile)); Free(fbuf2); if (out_name) fbuf2=ExtDft(out_name,"BIN.Z"); else fbuf2=ExtChg(fbuf,"BIN.Z"); FileWrite(fbuf2,bfh,size); Free(bfh); Free(tmpaot->buf); QueDel(tmpaot); Free(tmpaot); } Free(patch_table); Free(fbuf); Free(fbuf2); Free(fbuf3); Print("Errs:%d Warns:%d Code:%X Size:%X\n", error_cnt,warning_cnt,aot_U8s,size); return error_cnt; } 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; CCmpCtrl *cc; if (!filename) filename=blkdev.tmp_filename; cc=CmpCtrlNew(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; MemCpy64(&cc->htc,htc,sizeof(CLexHashTableContext)/8); } } QueIns(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; } } QueRem(cc); if (okay) CmpCtrlDel(cc); //TODO: can crash return res; } I64 ExePrint(U8 *fmt,...) {//JIT Compile and execute text from a printf(). I64 res; U8 *buf=StrPrintJoin(NULL,fmt,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=ExtDft(name,"HC.Z"), *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; CCmpCtrl *cc; if (!filename) filename=blkdev.tmp_filename; cc=CmpCtrlNew(buf,ccf_flags|CCF_DONT_FREE_BUF,filename); if (Fs->last_cc!=&Fs->next_cc) cc->opts=Fs->last_cc->opts; QueIns(cc,Fs->last_cc); Lex(cc); res=ExeCmdLine(cc); QueRem(cc); CmpCtrlDel(cc); return res; } I64 ExePrint2(U8 *fmt,...) {//throws exceptions I64 res; U8 *buf=StrPrintJoin(NULL,fmt,argc,argv); res=ExePutS2(buf); Free(buf); return res; } I64 ExeFile2(U8 *name,I64 ccf_flags=0) {//throws exceptions I64 res; U8 *name2=ExtDft(name,"HC.Z"),*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 *fmt,...) {//Causes value from stream to be used in an #exe{} block. U8 *buf=StrPrintJoin(NULL,fmt,argc,argv); I64 res=0; CLexHashTableContext *htc; CCmpCtrl *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() { CmpLoadDefines; CmpFillTables; QueInit(&cmp.ic_nop); cmp.ic_nop.ic_class=cmp.internal_types[RT_I64]; cmp.ic_nop.ic_code=IC_NOP1; AsmHashLoad; UAsmHashLoad; } CInit;