/** * Reads the file that specifies method calls that should be replaced by other method calls. The * file is of the form: * * <p>[regex] [orig-method-def] [new-method-name] * * <p>where the orig_method-def is of the form: * * <p>fully-qualified-method-name (args) * * <p>Blank lines and // comments are ignored. The orig-method-def is replaced by a call to * new-method-name with the same arguments in any classfile that matches the regular expressions. * All method names and argument types should be fully qualified. */ public void read_map_file(File map_file) throws IOException { LineNumberReader lr = new LineNumberReader(new FileReader(map_file)); MapFileError mfe = new MapFileError(lr, map_file); Pattern current_regex = null; Map<MethodDef, MethodInfo> map = new LinkedHashMap<MethodDef, MethodInfo>(); for (String line = lr.readLine(); line != null; line = lr.readLine()) { line = line.replaceFirst("//.*$", ""); if (line.trim().length() == 0) continue; if (line.startsWith(" ")) { if (current_regex == null) throw new IOException("No current class regex on line " + lr.getLineNumber()); StrTok st = new StrTok(line, mfe); st.stok.wordChars('.', '.'); MethodDef md = parse_method(st); String new_method = st.need_word(); map.put(md, new MethodInfo(new_method)); } else { if (current_regex != null) { MethodMapInfo mmi = new MethodMapInfo(current_regex, map); map_list.add(mmi); map = new LinkedHashMap<MethodDef, MethodInfo>(); } current_regex = Pattern.compile(line); } } if (current_regex != null) { MethodMapInfo mmi = new MethodMapInfo(current_regex, map); map_list.add(mmi); } dump_map_list(); }
public void addUsedConst(int idx, int len) { Integer ii = new Integer(idx); if (cpoolUsed.contains(ii)) return; cpoolUsed.add(ii); if (len > 1) { // add a dummy entry for a long or double constant cpoolUsed.add(null); } cpoolMap.put(idx, cpoolUsed.indexOf(ii)); }
/** * Transforms invoke instructions that match the specified list for this class to call the * specified static call instead. */ private InstructionList xform_inst(MethodGen mg, Instruction inst) { switch (inst.getOpcode()) { case Constants.INVOKESTATIC: { InstructionList il = new InstructionList(); INVOKESTATIC is = (INVOKESTATIC) inst; String cname = is.getClassName(pgen); String mname = is.getMethodName(pgen); Type[] args = is.getArgumentTypes(pgen); MethodDef orig = new MethodDef(cname + "." + mname, args); MethodInfo call = method_map.get(orig); if (call != null) { call.cnt++; String classname = call.method_class; String methodname = mname; debug_map.log( "%s.%s: Replacing method %s.%s (%s) with %s.%s%n", mg.getClassName(), mg.getName(), cname, mname, UtilMDE.join(args, ", "), classname, methodname); il.append( ifact.createInvoke( classname, methodname, is.getReturnType(pgen), args, Constants.INVOKESTATIC)); } return (il); } case Constants.INVOKEVIRTUAL: { InstructionList il = new InstructionList(); INVOKEVIRTUAL iv = (INVOKEVIRTUAL) inst; String cname = iv.getClassName(pgen); String mname = iv.getMethodName(pgen); Type[] args = iv.getArgumentTypes(pgen); Type instance_type = iv.getReferenceType(pgen); Type[] new_args = BCELUtil.insert_type(instance_type, args); MethodDef orig = new MethodDef(cname + "." + mname, args); if (debug_class) System.out.printf("looking for %s in map %s%n", orig, method_map); MethodInfo call = method_map.get(orig); if (call != null) { call.cnt++; String classname = call.method_class; String methodname = mname; debug_map.log( "Replacing method %s.%s (%s) with %s.%s%n", cname, mname, ArraysMDE.toString(args), classname, methodname); il.append( ifact.createInvoke( classname, methodname, iv.getReturnType(pgen), new_args, Constants.INVOKESTATIC)); } return (il); } default: return (null); } }
public void dump(PrintWriter out, PrintWriter outLinkInfo) { int i; out.println("//"); out.println("//\t" + classRefAddress + ": " + clazz.getClassName() + " class info"); out.println("//"); out.println("\t\t" + instSize + ",\t//\tinstance size"); for (i = 0; i < clft.len; ++i) { if (!clft.isStatic[i]) { out.println("\t\t\t\t//\t" + clft.idx[i] + " " + clft.key[i]); } } // link info: class addresses outLinkInfo.println( "class " + clazz.getClassName() + " " + methodsAddress + " " + cpoolAddress); outLinkInfo.println(" -instSize " + instSize); out.println("\t\t" + staticValueVarAddress + ",\t//\tpointer to static primitive fields"); if (instSize > 31) { System.err.println("Error: Object of " + clazz.getClassName() + " to big! Size=" + instSize); System.exit(-1); } out.println("\t\t" + instGCinfo + ",\t//\tinstance GC info"); String supname = "null"; int superAddr = 0; if (superClass != null) { supname = superClass.clazz.getClassName(); superAddr = ((JopClassInfo) appInfo.cliMap.get(supname)).classRefAddress; } if (!clazz.isInterface()) { out.println("\t\t" + superAddr + ",\t//\tpointer to super class - " + supname); // link info: super address outLinkInfo.println(" -super " + superAddr); } else { out.println("\t\t" + (-interfaceID) + ",\t//\tinterface ID"); } boolean useSuperInterfaceTable = false; if ((iftableAddress == 0) && (superClass != null)) { iftableAddress = ((JopClassInfo) appInfo.cliMap.get(supname)).iftableAddress; useSuperInterfaceTable = true; } out.println("\t\t" + iftableAddress + ",\t//\tpointer to interface table"); if (!clazz.isInterface()) { out.println("//"); out.println("//\t" + methodsAddress + ": " + clazz.getClassName() + " method table"); out.println("//"); int addr = methodsAddress; for (i = 0; i < clvt.len; i++) { clvt.mi[i].dumpMethodStruct(out, addr); outLinkInfo.println(" -mtab " + clvt.mi[i].getFQMethodName() + " " + addr); addr += ClassStructConstants.METH_STR; } } else { out.println("//"); out.println("//\tno method table for interfaces"); out.println("//"); } out.println(); out.println("\t\t" + classRefAddress + ",\t//\tpointer back to class struct (cp-1)"); out.println(); out.println("//"); out.println("//\t" + cpoolAddress + ": " + clazz.getClassName() + " constants"); out.println("//"); // link info: constant pool mapping for (Entry<Integer, Integer> entry : cpoolMap.entrySet()) { outLinkInfo.println(" -constmap " + entry.getKey() + " " + entry.getValue()); } // constant pool length includes the length field // same is true for the index in the bytecodes: // The lowest constant has index 1. out.println("\t\t" + (cpoolArry.length + 1) + ",\t//\tconst pool length"); out.println(); for (i = 0; i < cpoolArry.length; ++i) { out.println("\t\t" + cpoolArry[i] + ",\t//\t" + cpoolComments[i]); } if (iftableAddress != 0 && !useSuperInterfaceTable) { out.println("//"); out.println( "//\t" + (iftableAddress - (interfaceCnt + 31) / 32) + ": " + clazz.getClassName() + " implements table"); out.println("//"); for (i = (interfaceCnt + 31) / 32 - 1; i >= 0; i--) { String comment = ""; int word = 0; int j; for (j = 31; j >= 0; j--) { word <<= 1; if ((i * 32 + j) < interfaceCnt) { if (implementsInterface(interfaceList.get(i * 32 + j))) { word |= 1; comment += interfaceList.get(i * 32 + j) + ", "; } ; } } out.println("\t\t" + word + ",\t//\t" + comment); } out.println("//"); out.println("//\t" + iftableAddress + ": " + clazz.getClassName() + " interface table"); out.println("//"); if (!clazz.isInterface()) { out.println("//\tTODO: is it enough to use methodId as key???"); out.println("//"); for (i = 0; i < listIT.size(); ++i) { IT it = (IT) listIT.get(i); int j; for (j = 0; j < clvt.len; j++) { if (clvt.key[j].equals(it.key)) { break; } } if (j != clvt.len) { out.print("\t\t" + (methodsAddress + j * ClassStructConstants.METH_STR) + ","); } else { out.print("\t\t" + 0 + ",\t"); } out.println("\t//\t" + it.meth.methodId); } } } }