## "Simulate" the Java VM on a method.# Result: adt { jtype: byte; pc: int;}; jvmstack: array of ref Result; # simulated JVM stackjvmtos: int; # number of items in jvmstackjvmwords: int; # number of words that would be on JVM stackrettype: int; # return type of simulated method jvmpop(): ref Result{ r: ref Result; if(jvmtos == 0) verifyerrormess("stack underflow"); r = jvmstack[--jvmtos]; if(r.jtype == byte 'J' || r.jtype == byte 'D') jvmwords -= 2; else jvmwords -= 1; if(jvmwords < 0) verifyerrormess("stack underflow"); return r;} jvmpush(r: ref Result){ if(r.jtype == byte 'J' || r.jtype == byte 'D') jvmwords += 2; else jvmwords += 1; if(jvmwords > code.max_stack) verifyerrormess("stack overflow"); jvmstack[jvmtos++] = r;} ## Initialize jvmstack to process basic block bb.# jvminit(bb: ref BB){ i: int; r: ref Result; s: array of ref StkSnap; jvmtos = 0; jvmwords = 0; if(int (bb.flags & (BB_FINALLY | BB_HANDLER))) { r = ref Result(byte 'L', code.code_length); jvmpush(r); # push a dummy return; } # set jvmstack to bb.entrystk s = bb.entrystk; for(i = 0; i < bb.entrysz; i++) { r = ref Result(s[i].jtype, s[i].pc[0]); jvmpush(r); }} typecheck(r: ref Result, jtype: byte){ # assumes 'L' and '[' are interchangeable if(r.jtype != jtype && (int r.jtype + int jtype) != 'L' + '[') verifyerror(code.j[r.pc]);} jvmtype(jtype: int): byte{ case jtype { 'Z' or 'B' or 'C' or 'S' => jtype = 'I'; } return byte jtype;} srcalloc(j: ref Jinst, n: int){ j.nsrc = n; j.src = array [n] of int;} iconst(j: ref Jinst, ival: int){ r: ref Result; addrimm(j.dst, ival); r = ref Result(byte 'I', j.pc); j.jtype = byte 'I'; jvmpush(r);} mpconst(j: ref Jinst, jtype: int, off: int){ r: ref Result; addrsind(j.dst, Amp, off); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r);} verifyindex(j: ref Jinst, jtype: int, ix: int){ n: int; case jtype { 'I' or 'F' or 'L' => n = code.max_locals-1; 'J' or 'D' => n = code.max_locals-2; } if(ix > n) verifyerror(j);} getfpoff(jtype: int, ix: int): int{ off: int; case jtype { 'I' => off = localix(DIS_W, ix); 'J' or 'F' or 'D' => off = localix(DIS_L, ix); 'L' => off = localix(DIS_P, ix); } return off;} javaload(j: ref Jinst, jtype: int, ix: int){ r: ref Result; verifyindex(j, jtype, ix); addrsind(j.dst, Afp, getfpoff(jtype, ix)); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r);} javastore(j: ref Jinst, jtype: int, ix: int){ r: ref Result; verifyindex(j, jtype, ix); srcalloc(j, 1); r = jvmpop(); typecheck(r, byte jtype); j.src[0] = r.pc; addrsind(j.dst, Afp, getfpoff(jtype, ix));} arrayload(j: ref Jinst, jtype: int){ r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, byte 'I'); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte '['); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r);} arraystore(j: ref Jinst, jtype: int){ r: ref Result; srcalloc(j, 3); r = jvmpop(); typecheck(r, byte jtype); j.src[2] = r.pc; r = jvmpop(); typecheck(r, byte 'I'); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte '['); j.src[0] = r.pc; } binop(j: ref Jinst, loptype: int, roptype: int, dsttype: int){ r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, byte roptype); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte loptype); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte dsttype, j.pc); j.jtype = byte dsttype; jvmpush(r);} unop(j: ref Jinst, srctype: int, dsttype: int){ r: ref Result; srcalloc(j, 1); r = jvmpop(); typecheck(r, byte srctype); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte dsttype, j.pc); j.jtype = byte dsttype; jvmpush(r);} ## If the local variable being stored into corresponds to a local# that is on the stack, then an explicit mov_ MUST be generated# for the load instruction that put it on the stack.# storechk(six: int, stype: int){ i, lix: int; ltype: byte; j: ref Jinst; jpi: ref Jinst.Pi; jpw: ref Jinst.Pw; for(i = 0; i < jvmtos; i++) { j = code.j[jvmstack[i].pc]; lix = -1; pick jp := j { Pi => jpi = jp; Pw => jpw = jp; } case int j.op { Jiload or Jlload or Jfload or Jdload or Jaload => lix = jpi.i; Jiload_0 or Jlload_0 or Jfload_0 or Jdload_0 or Jaload_0 => lix = 0; Jiload_1 or Jlload_1 or Jfload_1 or Jdload_1 or Jaload_1 => lix = 1; Jiload_2 or Jlload_2 or Jfload_2 or Jdload_2 or Jaload_2 => lix = 2; Jiload_3 or Jlload_3 or Jfload_3 or Jdload_3 or Jaload_3 => lix = 3; Jwide => case int jpw.w.op { Jiload or Jlload or Jfload or Jdload or Jaload => lix = jpw.w.ix; } } ltype = byte '-'; case int j.op { Jiload or Jiload_0 or Jiload_1 or Jiload_2 or Jiload_3 => ltype = byte 'I'; Jlload or Jlload_0 or Jlload_1 or Jlload_2 or Jlload_3 => ltype = byte 'J'; Jfload or Jfload_0 or Jfload_1 or Jfload_2 or Jfload_3 => ltype = byte 'F'; Jdload or Jdload_0 or Jdload_1 or Jdload_2 or Jdload_3 => ltype = byte 'D'; Jaload or Jaload_0 or Jaload_1 or Jaload_2 or Jaload_3 => ltype = byte 'L'; Jwide => case int jpw.w.op { Jiload => ltype = byte 'I'; Jlload => ltype = byte 'J'; Jfload => ltype = byte 'F'; Jdload => ltype = byte 'D'; Jaload => ltype = byte 'L'; } } if(lix == six && ltype == byte stype && j.movsrc != nil && j.movsrc.mode == byte Anone) { *j.movsrc = *j.dst; addrsind(j.dst, Afp, -1); } }} useone(j: ref Jinst, jtype: int){ r: ref Result; srcalloc(j, 1); r = jvmpop(); typecheck(r, byte jtype); j.src[0] = r.pc;} usetwo(j: ref Jinst, loptype: byte, roptype: byte){ r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, roptype); j.src[1] = r.pc; r = jvmpop(); typecheck(r, loptype); j.src[0] = r.pc;} javanew(j: ref Jinst.Pi){ r: ref Result; name: string; name = CLASSNAME(j.i); if(name[0] == '[') verifyerror(j); addrsind(j.dst, Afp, -1); r = ref Result(byte 'L', j.pc); j.jtype = byte 'L'; jvmpush(r);} checkdim(j: ref Jinst, ix: int): int{ ndim: int; name: string; ndim = 0; name = CLASSNAME(ix); while(name[ndim] == '[') ndim++; if(ndim > 255) verifyerror(j); return ndim;} anewarray(j: ref Jinst.Pi){ checkdim(j, j.i); unop(j, 'I', '[');} multianewarray(j: ref Jinst.Px2d){ r: ref Result; i, ndim: int; ndim = checkdim(j, j.x2d.ix); if(ndim == 0 || j.x2d.dim > ndim) verifyerror(j); srcalloc(j, j.x2d.dim); for(i = j.x2d.dim-1; i >= 0; i--) { r = jvmpop(); typecheck(r, byte 'I'); j.src[i] = r.pc; } addrsind(j.dst, Afp, -1); r = ref Result(byte '[', j.pc); j.jtype = byte '['; jvmpush(r);} getname(j: ref Jinst): string{ ix: int; pick jp := j { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getname[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => pick n := class.cps[c.fmiref.name_type_index] { Pnat => return STRING(n.nat.name_index); * => badpick("getname[Pnat]"); } * => badpick("getname[Pfmiref]"); } return nil;} getsig(j: ref Jinst): string{ ix: int; pick jp := j { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getsig[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => pick n := class.cps[c.fmiref.name_type_index] { Pnat => return STRING(n.nat.sig_index); * => badpick("getsig[Pnat]"); } * => badpick("getsig[Pfmiref]"); } return nil;} Lines 1–500 of 1329. Load more
# # "Simulate" the Java VM on a method. # Result: adt { jtype: byte; pc: int; }; jvmstack: array of ref Result; # simulated JVM stack jvmtos: int; # number of items in jvmstack jvmwords: int; # number of words that would be on JVM stack rettype: int; # return type of simulated method jvmpop(): ref Result { r: ref Result; if(jvmtos == 0) verifyerrormess("stack underflow"); r = jvmstack[--jvmtos]; if(r.jtype == byte 'J' || r.jtype == byte 'D') jvmwords -= 2; else jvmwords -= 1; if(jvmwords < 0) verifyerrormess("stack underflow"); return r; } jvmpush(r: ref Result) { if(r.jtype == byte 'J' || r.jtype == byte 'D') jvmwords += 2; else jvmwords += 1; if(jvmwords > code.max_stack) verifyerrormess("stack overflow"); jvmstack[jvmtos++] = r; } # # Initialize jvmstack to process basic block bb. # jvminit(bb: ref BB) { i: int; r: ref Result; s: array of ref StkSnap; jvmtos = 0; jvmwords = 0; if(int (bb.flags & (BB_FINALLY | BB_HANDLER))) { r = ref Result(byte 'L', code.code_length); jvmpush(r); # push a dummy return; } # set jvmstack to bb.entrystk s = bb.entrystk; for(i = 0; i < bb.entrysz; i++) { r = ref Result(s[i].jtype, s[i].pc[0]); jvmpush(r); } } typecheck(r: ref Result, jtype: byte) { # assumes 'L' and '[' are interchangeable if(r.jtype != jtype && (int r.jtype + int jtype) != 'L' + '[') verifyerror(code.j[r.pc]); } jvmtype(jtype: int): byte { case jtype { 'Z' or 'B' or 'C' or 'S' => jtype = 'I'; } return byte jtype; } srcalloc(j: ref Jinst, n: int) { j.nsrc = n; j.src = array [n] of int; } iconst(j: ref Jinst, ival: int) { r: ref Result; addrimm(j.dst, ival); r = ref Result(byte 'I', j.pc); j.jtype = byte 'I'; jvmpush(r); } mpconst(j: ref Jinst, jtype: int, off: int) { r: ref Result; addrsind(j.dst, Amp, off); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r); } verifyindex(j: ref Jinst, jtype: int, ix: int) { n: int; case jtype { 'I' or 'F' or 'L' => n = code.max_locals-1; 'J' or 'D' => n = code.max_locals-2; } if(ix > n) verifyerror(j); } getfpoff(jtype: int, ix: int): int { off: int; case jtype { 'I' => off = localix(DIS_W, ix); 'J' or 'F' or 'D' => off = localix(DIS_L, ix); 'L' => off = localix(DIS_P, ix); } return off; } javaload(j: ref Jinst, jtype: int, ix: int) { r: ref Result; verifyindex(j, jtype, ix); addrsind(j.dst, Afp, getfpoff(jtype, ix)); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r); } javastore(j: ref Jinst, jtype: int, ix: int) { r: ref Result; verifyindex(j, jtype, ix); srcalloc(j, 1); r = jvmpop(); typecheck(r, byte jtype); j.src[0] = r.pc; addrsind(j.dst, Afp, getfpoff(jtype, ix)); } arrayload(j: ref Jinst, jtype: int) { r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, byte 'I'); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte '['); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte jtype, j.pc); j.jtype = byte jtype; jvmpush(r); } arraystore(j: ref Jinst, jtype: int) { r: ref Result; srcalloc(j, 3); r = jvmpop(); typecheck(r, byte jtype); j.src[2] = r.pc; r = jvmpop(); typecheck(r, byte 'I'); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte '['); j.src[0] = r.pc; } binop(j: ref Jinst, loptype: int, roptype: int, dsttype: int) { r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, byte roptype); j.src[1] = r.pc; r = jvmpop(); typecheck(r, byte loptype); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte dsttype, j.pc); j.jtype = byte dsttype; jvmpush(r); } unop(j: ref Jinst, srctype: int, dsttype: int) { r: ref Result; srcalloc(j, 1); r = jvmpop(); typecheck(r, byte srctype); j.src[0] = r.pc; addrsind(j.dst, Afp, -1); r = ref Result(byte dsttype, j.pc); j.jtype = byte dsttype; jvmpush(r); } # # If the local variable being stored into corresponds to a local # that is on the stack, then an explicit mov_ MUST be generated # for the load instruction that put it on the stack. # storechk(six: int, stype: int) { i, lix: int; ltype: byte; j: ref Jinst; jpi: ref Jinst.Pi; jpw: ref Jinst.Pw; for(i = 0; i < jvmtos; i++) { j = code.j[jvmstack[i].pc]; lix = -1; pick jp := j { Pi => jpi = jp; Pw => jpw = jp; } case int j.op { Jiload or Jlload or Jfload or Jdload or Jaload => lix = jpi.i; Jiload_0 or Jlload_0 or Jfload_0 or Jdload_0 or Jaload_0 => lix = 0; Jiload_1 or Jlload_1 or Jfload_1 or Jdload_1 or Jaload_1 => lix = 1; Jiload_2 or Jlload_2 or Jfload_2 or Jdload_2 or Jaload_2 => lix = 2; Jiload_3 or Jlload_3 or Jfload_3 or Jdload_3 or Jaload_3 => lix = 3; Jwide => case int jpw.w.op { Jiload or Jlload or Jfload or Jdload or Jaload => lix = jpw.w.ix; } } ltype = byte '-'; case int j.op { Jiload or Jiload_0 or Jiload_1 or Jiload_2 or Jiload_3 => ltype = byte 'I'; Jlload or Jlload_0 or Jlload_1 or Jlload_2 or Jlload_3 => ltype = byte 'J'; Jfload or Jfload_0 or Jfload_1 or Jfload_2 or Jfload_3 => ltype = byte 'F'; Jdload or Jdload_0 or Jdload_1 or Jdload_2 or Jdload_3 => ltype = byte 'D'; Jaload or Jaload_0 or Jaload_1 or Jaload_2 or Jaload_3 => ltype = byte 'L'; Jwide => case int jpw.w.op { Jiload => ltype = byte 'I'; Jlload => ltype = byte 'J'; Jfload => ltype = byte 'F'; Jdload => ltype = byte 'D'; Jaload => ltype = byte 'L'; } } if(lix == six && ltype == byte stype && j.movsrc != nil && j.movsrc.mode == byte Anone) { *j.movsrc = *j.dst; addrsind(j.dst, Afp, -1); } } } useone(j: ref Jinst, jtype: int) { r: ref Result; srcalloc(j, 1); r = jvmpop(); typecheck(r, byte jtype); j.src[0] = r.pc; } usetwo(j: ref Jinst, loptype: byte, roptype: byte) { r: ref Result; srcalloc(j, 2); r = jvmpop(); typecheck(r, roptype); j.src[1] = r.pc; r = jvmpop(); typecheck(r, loptype); j.src[0] = r.pc; } javanew(j: ref Jinst.Pi) { r: ref Result; name: string; name = CLASSNAME(j.i); if(name[0] == '[') verifyerror(j); addrsind(j.dst, Afp, -1); r = ref Result(byte 'L', j.pc); j.jtype = byte 'L'; jvmpush(r); } checkdim(j: ref Jinst, ix: int): int { ndim: int; name: string; ndim = 0; name = CLASSNAME(ix); while(name[ndim] == '[') ndim++; if(ndim > 255) verifyerror(j); return ndim; } anewarray(j: ref Jinst.Pi) { checkdim(j, j.i); unop(j, 'I', '['); } multianewarray(j: ref Jinst.Px2d) { r: ref Result; i, ndim: int; ndim = checkdim(j, j.x2d.ix); if(ndim == 0 || j.x2d.dim > ndim) verifyerror(j); srcalloc(j, j.x2d.dim); for(i = j.x2d.dim-1; i >= 0; i--) { r = jvmpop(); typecheck(r, byte 'I'); j.src[i] = r.pc; } addrsind(j.dst, Afp, -1); r = ref Result(byte '[', j.pc); j.jtype = byte '['; jvmpush(r); } getname(j: ref Jinst): string { ix: int; pick jp := j { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getname[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => pick n := class.cps[c.fmiref.name_type_index] { Pnat => return STRING(n.nat.name_index); * => badpick("getname[Pnat]"); } * => badpick("getname[Pfmiref]"); } return nil; } getsig(j: ref Jinst): string { ix: int; pick jp := j { Pi => ix = jp.i; Px2c0 => ix = jp.x2c0.ix; * => badpick("getsig[Pi|Px2c0]"); } pick c := class.cps[ix] { Pfmiref => pick n := class.cps[c.fmiref.name_type_index] { Pnat => return STRING(n.nat.sig_index); * => badpick("getsig[Pnat]"); } * => badpick("getsig[Pfmiref]"); } return nil; }