pcdis: int;callunrescue: int;J: ref Jinst;M: ref Method;code: ref Code; # method under translation trylevel: fn(pc: int): int;unrescue: fn(n: int); ## Allocate a Dis instruction.# newi(op: int): ref Inst{ i: ref Inst; i = ref Inst(byte op, nil, nil, nil, pcdis, J, nil); i.s = ref Addr(byte 0, 0, 0); i.m = ref Addr(byte 0, 0, 0); i.d = ref Addr(byte 0, 0, 0); pcdis += 1; if(J != nil && J.dis == nil) J.dis = i; if(ihead == nil) ihead = i; if(itail != nil) itail.next = i; itail = i; return i;} ## Allocate a Dis instruction and record for branch-address patching.# newibap(op: int): ref Inst{ i: ref Inst; i = newi(op); patchop(i); return i;} ## Turn single indirection off fp into double indirection.# sind2dind(a: ref Addr, s: int){ if(a.mode == byte Afp) { a.mode = byte Afpind; a.ival = a.offset; a.offset = s; } else if(a.mode == byte Amp && a.offset == 0) ; # verifyerror(J); # can't reject prior to runtime else fatal("sind2dind: " + string a.mode + " not Afp");} ## Middle operands that match destination operands are redundant.# middstcmp(i: ref Inst){ m, d: ref Addr; m = i.m; d = i.d; if(m.mode == Afp && m.mode == d.mode && m.offset == d.offset) { m.mode = Anone; m.offset = 0; }} ## For instructions that may reference Module Data.# datareloc(i: ref Inst){ if(i.op == byte IMOVP && i.s.mode == byte Amp && i.s.offset == 0) return; # don't relocate reference to nil if(i.s.mode == byte Amp) addDreloc(i, PSRC, PSIND); if(i.m.mode == byte Amp) addDreloc(i, PMID, PSIND);} movinst(jtype: int): int{ movi: int; case jtype { 'Z' or 'B' => if(J.op == byte Jgetfield || J.op == byte Jgetstatic) movi = ICVTBW; else if(J.op == byte Jputfield || J.op == byte Jputstatic) movi = ICVTWB; else movi = IMOVW; 'C' or 'S' or 'I' => movi = IMOVW; 'J' => movi = IMOVL; 'F' or 'D' => movi = IMOVF; 'L' or '[' => movi = IMOVP; } return movi;} FieldInfo: adt { classname: string; fieldname: string; sig: string; flags: int;}; getfldinfo(): ref FieldInfo{ i: int; m: ref Method; fi: ref FieldInfo = ref FieldInfo(nil, nil, nil, 0); ix: int; pick jp := J { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getfldinfo[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => fi.classname = CLASSNAME(c.fmiref.class_index); pick n := class.cps[c.fmiref.name_type_index] { Pnat => fi.fieldname = STRING(n.nat.name_index); fi.sig = STRING(n.nat.sig_index); * => badpick("getfldinfo[Pnat]"); } * => badpick("getfldinfo[Pfmiref]"); } fi.flags = 0; if(fi.classname != THISCLASS) return fi; for(i = 0; i < class.methods_count; i++) { m = class.methods[i]; if(fi.fieldname == STRING(m.name_index) && fi.sig == STRING(m.sig_index)) { fi.flags = m.access_flags; break; } } return fi;} ## mframe instruction for a call to a Loader entry point.# loadermframe(frm: ref Freloc, frf: ref Freloc): ref Inst{ imframe: ref Inst; imframe = newi(IMFRAME); addrsind(imframe.s, Amp, 0); addrimm(imframe.m, 0); addrsind(imframe.d, Afp, getreg(DIS_W)); LTIpatch(frm, imframe, PSRC, PSIND); LTIpatch(frf, imframe, PMID, PIMM); return imframe;} ## mcall instruction for a call to a Loader entry point.# loadermcall(imframe: ref Inst, frf: ref Freloc, frm: ref Freloc): ref Inst{ imcall: ref Inst; imcall = newi(IMCALL); *imcall.s = *imframe.d; *imcall.m = *imframe.m; *imcall.d = *imframe.s; LTIpatch(frf, imcall, PMID, PIMM); LTIpatch(frm, imcall, PDST, PSIND); return imcall;} ## Call "rtload" for run-time resolution.# rtcache: array of string;rtncache: int;rtnmax: int; callrtload(rtc: ref RTClass, classname: string){ j: int; imframe, i: ref Inst; cr: ref Creloc; frm, frf: ref Freloc; rtr: ref RTReloc; # rtload() already called for classname in this basic block ? for(j = 0; j < rtncache; j++) { if(rtcache[j] == classname) return; } if(rtncache >= rtnmax) { oldrtnmax := rtnmax; rtnmax += ALLOCINCR; newrtcache := array [rtnmax] of string; for(k := 0; k < oldrtnmax; k++) newrtcache[k] = rtcache[k]; rtcache = newrtcache; } rtcache[rtncache++] = classname; rtr = getRTReloc(rtc, RMP, nil, 0); cr = getCreloc(RLOADER); frm = getFreloc(cr, RMP, nil, 0); frf = getFreloc(cr, "rtload", nil, 0); i = newi(IBNEW); addrsind(i.s, Amp, 0); addrsind(i.m, Amp, 0); addrimm(i.d, i.pc+4); RTIpatch(rtr, i, PSRC, PSIND); imframe = loadermframe(frm, frf); i = newi(ILEA); addrsind(i.s, Amp, 0); addrdind(i.d, Afpind, imframe.d.offset, REGSIZE); RTIpatch(rtr, i, PSRC, PSIND); loadermcall(imframe, frf, frm); relreg(imframe.d);} ## Sign-extend an 8-bit unsigned char (Dis byte) to a 32-bit int.# signextend(dst: ref Addr){ i: ref Inst; i = newi(ISHLW); addrimm(i.s, 24); # *i.m = *dst; # redundant *i.d = *dst; i = newi(ISHRW); addrimm(i.s, 24); # *i.m = *dst; # redundant *i.d = *dst;} ## addw instruction for run-time relocated getstatic & putstatic.# rtstaticadd(fi: ref FieldInfo, rtc: ref RTClass): ref Addr{ i: ref Inst; i = newi(IADDW); addrdind(i.s, Ampind, 0, 0); addrsind(i.m, Amp, 0); addrsind(i.d, Afp, getreg(DIS_W)); RTIpatch(getRTReloc(rtc, RMP, nil, 0), i, PSRC, PDIND1); RTIpatch(getRTReloc(rtc, fi.fieldname, fi.sig, Rgetputstatic), i, PMID, PSIND); return i.d;} ## Run-time relocated getstatic.# rtgetstatic(fi: ref FieldInfo){ a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtstaticadd(fi, rtc); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d);} ## Run-time relocated putstatic.# rtputstatic(fi: ref FieldInfo){ a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtstaticadd(fi, rtc); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[0]].dst; relreg(code.j[J.src[0]].dst); *i.d = *a; sind2dind(i.d, 0); relreg(a); datareloc(i);} ## addw instruction for load-time relocated getstatic & putstatic.# ltstaticadd(fi: ref FieldInfo): ref Addr{ i: ref Inst; cr: ref Creloc; i = newi(IADDW); addrdind(i.s, Ampind, 0, 0); addrimm(i.m, 0); addrsind(i.d, Afp, getreg(DIS_W)); cr = getCreloc(fi.classname); LTIpatch(getFreloc(cr, RMP, nil, 0), i, PSRC, PDIND1); LTIpatch(getFreloc(cr, fi.fieldname, fi.sig, Rgetputstatic), i, PMID, PIMM); return i.d;} ## Load-time relocated getstatic.# getstatic(){ i: ref Inst; a: ref Addr; fi: ref FieldInfo; fi = getfldinfo(); if(dortload(fi.classname)) { rtgetstatic(fi); return; } a = ltstaticadd(fi); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d);} ## Load-time relocated putstatic.# putstatic(){ i: ref Inst; a: ref Addr; fi: ref FieldInfo; fi = getfldinfo(); if(dortload(fi.classname)) { rtputstatic(fi); return; } a = ltstaticadd(fi); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[0]].dst; relreg(code.j[J.src[0]].dst); *i.d = *a; sind2dind(i.d, 0); relreg(a); datareloc(i);} ## addw instruction for run-time relocated getfield & putfield.# rtfieldadd(fi: ref FieldInfo, rtc: ref RTClass, a: ref Addr): ref Addr{ i: ref Inst; i = newi(IADDW); *i.s = *a; addrsind(i.m, Amp, 0); addrsind(i.d, Afp, getreg(DIS_W)); RTIpatch(getRTReloc(rtc, fi.fieldname, fi.sig, Rgetputfield), i, PMID, PSIND); return i.d;} ## Run-time relocated getfield.# rtgetfield(fi: ref FieldInfo){ a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtfieldadd(fi, rtc, code.j[J.src[0]].dst); relreg(code.j[J.src[0]].dst); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d);} ## Run-time relocated putfield.# rtputfield(fi: ref FieldInfo){ a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtfieldadd(fi, rtc, code.j[J.src[0]].dst); relreg(code.j[J.src[0]].dst); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[1]].dst; relreg(code.j[J.src[1]].dst); *i.d = *a; relreg(a); sind2dind(i.d, 0); datareloc(i);} ## Load-time relocated getfield.# getfield(){ i: ref Inst;Lines 1–500 of 2960. Load more
pcdis: int; callunrescue: int; J: ref Jinst; M: ref Method; code: ref Code; # method under translation trylevel: fn(pc: int): int; unrescue: fn(n: int); # # Allocate a Dis instruction. # newi(op: int): ref Inst { i: ref Inst; i = ref Inst(byte op, nil, nil, nil, pcdis, J, nil); i.s = ref Addr(byte 0, 0, 0); i.m = ref Addr(byte 0, 0, 0); i.d = ref Addr(byte 0, 0, 0); pcdis += 1; if(J != nil && J.dis == nil) J.dis = i; if(ihead == nil) ihead = i; if(itail != nil) itail.next = i; itail = i; return i; } # # Allocate a Dis instruction and record for branch-address patching. # newibap(op: int): ref Inst { i: ref Inst; i = newi(op); patchop(i); return i; } # # Turn single indirection off fp into double indirection. # sind2dind(a: ref Addr, s: int) { if(a.mode == byte Afp) { a.mode = byte Afpind; a.ival = a.offset; a.offset = s; } else if(a.mode == byte Amp && a.offset == 0) ; # verifyerror(J); # can't reject prior to runtime else fatal("sind2dind: " + string a.mode + " not Afp"); } # # Middle operands that match destination operands are redundant. # middstcmp(i: ref Inst) { m, d: ref Addr; m = i.m; d = i.d; if(m.mode == Afp && m.mode == d.mode && m.offset == d.offset) { m.mode = Anone; m.offset = 0; } } # # For instructions that may reference Module Data. # datareloc(i: ref Inst) { if(i.op == byte IMOVP && i.s.mode == byte Amp && i.s.offset == 0) return; # don't relocate reference to nil if(i.s.mode == byte Amp) addDreloc(i, PSRC, PSIND); if(i.m.mode == byte Amp) addDreloc(i, PMID, PSIND); } movinst(jtype: int): int { movi: int; case jtype { 'Z' or 'B' => if(J.op == byte Jgetfield || J.op == byte Jgetstatic) movi = ICVTBW; else if(J.op == byte Jputfield || J.op == byte Jputstatic) movi = ICVTWB; else movi = IMOVW; 'C' or 'S' or 'I' => movi = IMOVW; 'J' => movi = IMOVL; 'F' or 'D' => movi = IMOVF; 'L' or '[' => movi = IMOVP; } return movi; } FieldInfo: adt { classname: string; fieldname: string; sig: string; flags: int; }; getfldinfo(): ref FieldInfo { i: int; m: ref Method; fi: ref FieldInfo = ref FieldInfo(nil, nil, nil, 0); ix: int; pick jp := J { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getfldinfo[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => fi.classname = CLASSNAME(c.fmiref.class_index); pick n := class.cps[c.fmiref.name_type_index] { Pnat => fi.fieldname = STRING(n.nat.name_index); fi.sig = STRING(n.nat.sig_index); * => badpick("getfldinfo[Pnat]"); } * => badpick("getfldinfo[Pfmiref]"); } fi.flags = 0; if(fi.classname != THISCLASS) return fi; for(i = 0; i < class.methods_count; i++) { m = class.methods[i]; if(fi.fieldname == STRING(m.name_index) && fi.sig == STRING(m.sig_index)) { fi.flags = m.access_flags; break; } } return fi; } # # mframe instruction for a call to a Loader entry point. # loadermframe(frm: ref Freloc, frf: ref Freloc): ref Inst { imframe: ref Inst; imframe = newi(IMFRAME); addrsind(imframe.s, Amp, 0); addrimm(imframe.m, 0); addrsind(imframe.d, Afp, getreg(DIS_W)); LTIpatch(frm, imframe, PSRC, PSIND); LTIpatch(frf, imframe, PMID, PIMM); return imframe; } # # mcall instruction for a call to a Loader entry point. # loadermcall(imframe: ref Inst, frf: ref Freloc, frm: ref Freloc): ref Inst { imcall: ref Inst; imcall = newi(IMCALL); *imcall.s = *imframe.d; *imcall.m = *imframe.m; *imcall.d = *imframe.s; LTIpatch(frf, imcall, PMID, PIMM); LTIpatch(frm, imcall, PDST, PSIND); return imcall; } # # Call "rtload" for run-time resolution. # rtcache: array of string; rtncache: int; rtnmax: int; callrtload(rtc: ref RTClass, classname: string) { j: int; imframe, i: ref Inst; cr: ref Creloc; frm, frf: ref Freloc; rtr: ref RTReloc; # rtload() already called for classname in this basic block ? for(j = 0; j < rtncache; j++) { if(rtcache[j] == classname) return; } if(rtncache >= rtnmax) { oldrtnmax := rtnmax; rtnmax += ALLOCINCR; newrtcache := array [rtnmax] of string; for(k := 0; k < oldrtnmax; k++) newrtcache[k] = rtcache[k]; rtcache = newrtcache; } rtcache[rtncache++] = classname; rtr = getRTReloc(rtc, RMP, nil, 0); cr = getCreloc(RLOADER); frm = getFreloc(cr, RMP, nil, 0); frf = getFreloc(cr, "rtload", nil, 0); i = newi(IBNEW); addrsind(i.s, Amp, 0); addrsind(i.m, Amp, 0); addrimm(i.d, i.pc+4); RTIpatch(rtr, i, PSRC, PSIND); imframe = loadermframe(frm, frf); i = newi(ILEA); addrsind(i.s, Amp, 0); addrdind(i.d, Afpind, imframe.d.offset, REGSIZE); RTIpatch(rtr, i, PSRC, PSIND); loadermcall(imframe, frf, frm); relreg(imframe.d); } # # Sign-extend an 8-bit unsigned char (Dis byte) to a 32-bit int. # signextend(dst: ref Addr) { i: ref Inst; i = newi(ISHLW); addrimm(i.s, 24); # *i.m = *dst; # redundant *i.d = *dst; i = newi(ISHRW); addrimm(i.s, 24); # *i.m = *dst; # redundant *i.d = *dst; } # # addw instruction for run-time relocated getstatic & putstatic. # rtstaticadd(fi: ref FieldInfo, rtc: ref RTClass): ref Addr { i: ref Inst; i = newi(IADDW); addrdind(i.s, Ampind, 0, 0); addrsind(i.m, Amp, 0); addrsind(i.d, Afp, getreg(DIS_W)); RTIpatch(getRTReloc(rtc, RMP, nil, 0), i, PSRC, PDIND1); RTIpatch(getRTReloc(rtc, fi.fieldname, fi.sig, Rgetputstatic), i, PMID, PSIND); return i.d; } # # Run-time relocated getstatic. # rtgetstatic(fi: ref FieldInfo) { a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtstaticadd(fi, rtc); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d); } # # Run-time relocated putstatic. # rtputstatic(fi: ref FieldInfo) { a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtstaticadd(fi, rtc); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[0]].dst; relreg(code.j[J.src[0]].dst); *i.d = *a; sind2dind(i.d, 0); relreg(a); datareloc(i); } # # addw instruction for load-time relocated getstatic & putstatic. # ltstaticadd(fi: ref FieldInfo): ref Addr { i: ref Inst; cr: ref Creloc; i = newi(IADDW); addrdind(i.s, Ampind, 0, 0); addrimm(i.m, 0); addrsind(i.d, Afp, getreg(DIS_W)); cr = getCreloc(fi.classname); LTIpatch(getFreloc(cr, RMP, nil, 0), i, PSRC, PDIND1); LTIpatch(getFreloc(cr, fi.fieldname, fi.sig, Rgetputstatic), i, PMID, PIMM); return i.d; } # # Load-time relocated getstatic. # getstatic() { i: ref Inst; a: ref Addr; fi: ref FieldInfo; fi = getfldinfo(); if(dortload(fi.classname)) { rtgetstatic(fi); return; } a = ltstaticadd(fi); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d); } # # Load-time relocated putstatic. # putstatic() { i: ref Inst; a: ref Addr; fi: ref FieldInfo; fi = getfldinfo(); if(dortload(fi.classname)) { rtputstatic(fi); return; } a = ltstaticadd(fi); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[0]].dst; relreg(code.j[J.src[0]].dst); *i.d = *a; sind2dind(i.d, 0); relreg(a); datareloc(i); } # # addw instruction for run-time relocated getfield & putfield. # rtfieldadd(fi: ref FieldInfo, rtc: ref RTClass, a: ref Addr): ref Addr { i: ref Inst; i = newi(IADDW); *i.s = *a; addrsind(i.m, Amp, 0); addrsind(i.d, Afp, getreg(DIS_W)); RTIpatch(getRTReloc(rtc, fi.fieldname, fi.sig, Rgetputfield), i, PMID, PSIND); return i.d; } # # Run-time relocated getfield. # rtgetfield(fi: ref FieldInfo) { a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtfieldadd(fi, rtc, code.j[J.src[0]].dst); relreg(code.j[J.src[0]].dst); i = newi(movinst(fi.sig[0])); *i.s = *a; sind2dind(i.s, 0); relreg(a); dstreg(J.dst, j2dtype(J.jtype)); *i.d = *J.dst; if(fi.sig[0] == 'B') signextend(i.d); } # # Run-time relocated putfield. # rtputfield(fi: ref FieldInfo) { a: ref Addr; i: ref Inst; rtc: ref RTClass; rtc = getRTClass(fi.classname); callrtload(rtc, fi.classname); a = rtfieldadd(fi, rtc, code.j[J.src[0]].dst); relreg(code.j[J.src[0]].dst); i = newi(movinst(fi.sig[0])); *i.s = *code.j[J.src[1]].dst; relreg(code.j[J.src[1]].dst); *i.d = *a; relreg(a); sind2dind(i.d, 0); datareloc(i); } # # Load-time relocated getfield. # getfield() { i: ref Inst;