private static boolean checkMethodUsedByBaseClassOrInterface( BytecodeMethod mtd, ByteCodeClass cls) { if (cls == null) { return false; } if (cls.getBaseInterfacesObject() != null) { for (ByteCodeClass bc : cls.getBaseInterfacesObject()) { for (BytecodeMethod m : bc.getMethods()) { if (m.getMethodName().equals(mtd.getMethodName())) { if (m.isUsedByNative()) { return true; } break; } } } } for (BytecodeMethod m : cls.getMethods()) { if (m.getMethodName().equals(mtd.getMethodName())) { if (m.isUsedByNative()) { return true; } break; } } return false; }
private static boolean cullMethods(boolean found) { for (ByteCodeClass bc : classes) { bc.unmark(); if (bc.isIsInterface() || bc.getBaseClass() == null) { continue; } for (BytecodeMethod mtd : bc.getMethods()) { if (mtd.isEliminated() || mtd.isUsedByNative() || mtd.isMain() || mtd.getMethodName().equals("__CLINIT__") || mtd.getMethodName().equals("finalize") || mtd.isNative()) { continue; } if (!isMethodUsed(mtd)) { if (isMethodUsedByBaseClassOrInterface(mtd, bc)) { continue; } found = true; mtd.setEliminated(true); /*if(ByteCodeTranslator.verbose) { System.out.println("Eliminating method: " + mtd.getClsName() + "." + mtd.getMethodName()); }*/ } } } return found; }
public static ByteCodeClass getClassObject(String name) { for (ByteCodeClass cls : classes) { if (cls.getClsName().equals(name)) { return cls; } } return null; }
private static ByteCodeClass getClassByName(String name) { name = name.replace('/', '_').replace('$', '_'); for (ByteCodeClass bc : classes) { if (bc.getClsName().equals(name)) { return bc; } } return null; }
private static boolean isMethodUsedByBaseClassOrInterface(BytecodeMethod mtd, ByteCodeClass cls) { boolean b = checkMethodUsedByBaseClassOrInterface(mtd, cls.getBaseClassObject()); if (b) { return true; } for (ByteCodeClass bc : cls.getBaseInterfacesObject()) { b = checkMethodUsedByBaseClassOrInterface(mtd, bc); if (b) { return true; } } return false; }
@Override public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { ByteCodeField fld = new ByteCodeField(clsName, access, name, desc, signature, value); cls.addField(fld); return new FieldVisitorWrapper(super.visitField(access, name, desc, signature, value)); }
private static void appendClassOffset(ByteCodeClass bc, List<Integer> clsIds) { if (bc.getBaseClassObject() != null) { if (!clsIds.contains(bc.getBaseClassObject().getClassOffset())) { clsIds.add(bc.getBaseClassObject().getClassOffset()); appendClassOffset(bc.getBaseClassObject(), clsIds); } } if (bc.getBaseInterfacesObject() != null) { for (ByteCodeClass c : bc.getBaseInterfacesObject()) { if (c != null && !clsIds.contains(c.getClassOffset())) { clsIds.add(c.getClassOffset()); if (c.getBaseClassObject() != null) { appendClassOffset(c, clsIds); } } } } }
private static void usedByNativeCheck() { for (ByteCodeClass bc : classes) { // java_lang_Thread_runImpl___long for (BytecodeMethod mtd : bc.getMethods()) { // check native code StringBuilder b = new StringBuilder(); mtd.appendFunctionPointer(b); String str = b.toString(); for (String s : nativeSources) { if (s.contains(str)) { mtd.setUsedByNative(true); break; } } } } }
private static void cullClasses(boolean found, int depth) { if (found && depth < 3) { for (ByteCodeClass bc : classes) { bc.updateAllDependencies(); } // int classCount = classes.size(); ByteCodeClass.markDependencies(classes); List<ByteCodeClass> tmp = ByteCodeClass.clearUnmarked(classes); /*if(ByteCodeTranslator.verbose) { System.out.println("Classes removed from: " + classCount + " to " + classes.size()); for(ByteCodeClass bc : classes) { if(!tmp.contains(bc)) { System.out.println("Removed class: " + bc.getClsName()); } } }*/ classes = tmp; eliminateUnusedMethods(depth + 1); } }
private static void writeFile( ByteCodeClass cls, File outputDir, ConcatenatingFileOutputStream writeBufferInstead) throws Exception { OutputStream outMain = writeBufferInstead != null && ByteCodeTranslator.output == ByteCodeTranslator.OutputType.OUTPUT_TYPE_IOS ? writeBufferInstead : new FileOutputStream( new File( outputDir, cls.getClsName() + "." + ByteCodeTranslator.output.extension())); if (outMain instanceof ConcatenatingFileOutputStream) { ((ConcatenatingFileOutputStream) outMain).beginNextFile(cls.getClsName()); } if (ByteCodeTranslator.output == ByteCodeTranslator.OutputType.OUTPUT_TYPE_IOS) { outMain.write(cls.generateCCode(classes).getBytes()); outMain.close(); // we also need to write the header file for iOS String headerName = cls.getClsName() + ".h"; FileOutputStream outHeader = new FileOutputStream(new File(outputDir, headerName)); outHeader.write(cls.generateCHeader().getBytes()); outHeader.close(); } else { outMain.write(cls.generateCSharpCode().getBytes()); outMain.close(); } }
@Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (name.indexOf("DynaCCSmsServiceConstants") > -1) { System.out.println("Break"); } cls.setBaseClass(superName); cls.setBaseInterfaces(interfaces); if ((access & Opcodes.ACC_ABSTRACT) == Opcodes.ACC_ABSTRACT) { cls.setIsAbstract(true); } if ((access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE) { cls.setIsInterface(true); } if ((access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL) { cls.setFinalClass(true); } super.visit(version, access, name, signature, superName, interfaces); }
private static boolean isMethodUsed(BytecodeMethod m) { for (ByteCodeClass bc : classes) { for (BytecodeMethod mtd : bc.getMethods()) { if (mtd.isEliminated() || mtd == m) { continue; } if (mtd.isMethodUsed(m)) { return true; } } } // check native code StringBuilder b = new StringBuilder(); m.appendFunctionPointer(b); String str = b.toString(); for (String s : nativeSources) { if (s.contains(str)) { return true; } } return false; }
@Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { BytecodeMethod mtd = new BytecodeMethod(clsName, access, name, desc, signature, exceptions); cls.addMethod(mtd); JSRInlinerAdapter a = new JSRInlinerAdapter( new MethodVisitorWrapper( super.visitMethod(access, name, desc, signature, exceptions), mtd), access, name, desc, signature, exceptions); return a; }
@Override public void visitSource(String source, String debug) { cls.setSourceFile(source); super.visitSource(source, debug); }
public static void writeOutput(File outputDirectory) throws Exception { System.out.println("outputDirectory is: " + outputDirectory.getAbsolutePath()); if (ByteCodeClass.getMainClass() == null) { System.out.println( "Error main class is not defined. The main class name is expected to have a public static void main(String[]) method and it is assumed to reside in the com.package.name directory"); System.exit(1); } String file = "Unknown File"; try { for (ByteCodeClass bc : classes) { // special case for object if (bc.getClsName().equals("java_lang_Object")) { continue; } file = bc.getClsName(); bc.setBaseClassObject(getClassByName(bc.getBaseClass())); List<ByteCodeClass> lst = new ArrayList<ByteCodeClass>(); for (String s : bc.getBaseInterfaces()) { ByteCodeClass bcode = getClassByName(s); if (bcode == null) { System.out.println( "Error while working with the class: " + s + " file:" + file + " no class definition"); } else { lst.add(getClassByName(s)); } } bc.setBaseInterfacesObject(lst); } for (ByteCodeClass bc : classes) { file = bc.getClsName(); bc.updateAllDependencies(); } ByteCodeClass.markDependencies(classes); classes = ByteCodeClass.clearUnmarked(classes); // load the native sources (including user native code) readNativeFiles(outputDirectory); // loop over methods and start eliminating the body of unused methods eliminateUnusedMethods(); generateClassAndMethodIndexHeader(outputDirectory); boolean concatenate = "true".equals(System.getProperty("concatenateFiles", "false")); ConcatenatingFileOutputStream cos = concatenate ? new ConcatenatingFileOutputStream(outputDirectory) : null; for (ByteCodeClass bc : classes) { file = bc.getClsName(); writeFile(bc, outputDirectory, cos); } if (cos != null) cos.realClose(); } catch (Throwable t) { System.out.println("Error while working with the class: " + file); t.printStackTrace(); if (t instanceof Exception) { throw (Exception) t; } if (t instanceof RuntimeException) { throw (RuntimeException) t; } } }
private static void generateClassAndMethodIndexHeader(File outputDirectory) throws Exception { int classOffset = 0; int methodOffset = 0; ArrayList<BytecodeMethod> methods = new ArrayList<BytecodeMethod>(); for (ByteCodeClass bc : classes) { bc.setClassOffset(classOffset); classOffset++; methodOffset = bc.updateMethodOffsets(methodOffset); methods.addAll(bc.getMethods()); } StringBuilder bld = new StringBuilder(); StringBuilder bldM = new StringBuilder(); bldM.append("#include \"cn1_class_method_index.h\"\n"); bldM.append("#include \"cn1_globals.h\"\n\n"); bld.append("#ifndef __CN1_CLASS_METHOD_INDEX_H__\n#define __CN1_CLASS_METHOD_INDEX_H__\n\n"); bld.append("// maps to offsets in the constant pool below\nextern int classNameLookup[];\n"); bldM.append("// maps to offsets in the constant pool below\nint classNameLookup[] = {"); boolean first = true; for (ByteCodeClass bc : classes) { if (first) { bldM.append("\n "); } else { bldM.append(",\n "); } first = false; bldM.append(addToConstantPool(bc.getClsName().replace('_', '.'))); bldM.append(""); } bldM.append("};\n\n"); for (ByteCodeClass bc : classes) { bld.append("#define cn1_class_id_"); bld.append(bc.getClsName()); bld.append(" "); bld.append(bc.getClassOffset()); bld.append("\n"); } int arrayId = classes.size() + 1; bld.append("#define cn1_array_start_offset "); bld.append(arrayId); bld.append("\n"); // leave space for primitive arrays arrayId += 100; for (ByteCodeClass bc : classes) { bld.append("#define cn1_array_1_id_"); bld.append(bc.getClsName()); bld.append(" "); bld.append(arrayId); bld.append("\n"); arrayId++; bld.append("#define cn1_array_2_id_"); bld.append(bc.getClsName()); bld.append(" "); bld.append(arrayId); bld.append("\n"); arrayId++; bld.append("#define cn1_array_3_id_"); bld.append(bc.getClsName()); bld.append(" "); bld.append(arrayId); bld.append("\n"); arrayId++; /*bld.append("#define cn1_array_4_id_"); bld.append(bc.getClsName()); bld.append(" "); bld.append(arrayId); bld.append("\n"); arrayId++;*/ } bld.append("\n\n"); bld.append("// maps to offsets in the constant pool below\nextern int methodNameLookup[];\n"); bldM.append("// maps to offsets in the constant pool below\nint methodNameLookup[] = {"); first = true; for (BytecodeMethod m : methods) { if (first) { bldM.append("\n "); } else { bldM.append(",\n "); } first = false; bldM.append(addToConstantPool(m.getMethodName())); bldM.append(""); } bldM.append("};\n\n"); ArrayList<Integer> instances = new ArrayList<Integer>(); int counter = 0; for (ByteCodeClass bc : classes) { /*bld.append("extern int classInstanceOfArr"); bld.append(counter); bld.append("[];\n");*/ bldM.append("int classInstanceOfArr"); bldM.append(counter); bldM.append("[] = {"); counter++; appendClassOffset(bc, instances); for (Integer i : instances) { bldM.append(i); bldM.append(", "); } instances.clear(); bldM.append("-1};\n"); } bld.append("extern int *classInstanceOf[];\n"); bldM.append("int *classInstanceOf["); bldM.append(classes.size()); bldM.append("] = {"); first = true; counter = 0; for (ByteCodeClass bc : classes) { if (first) { bldM.append("\n "); } else { bldM.append(",\n "); } first = false; bldM.append("classInstanceOfArr"); bldM.append(counter); counter++; } bldM.append("};\n\n"); bld.append("#define CN1_CONSTANT_POOL_SIZE "); bld.append(constantPool.size()); bld.append("\n\nextern const char * const constantPool[];\n"); bldM.append("\n\nconst char * const constantPool[] = {\n"); first = true; int offset = 0; for (String con : constantPool) { if (first) { bldM.append("\n \""); } else { bldM.append(",\n \""); } first = false; try { bldM.append(encodeString(con)); } catch (Throwable t) { t.printStackTrace(); System.out.println("Error writing the constant pool string: '" + con + "'"); System.exit(1); } bldM.append("\" /* "); bldM.append(offset); offset++; bldM.append(" */"); } bldM.append("};\n\nint classListSize = "); bldM.append(classes.size()); bldM.append(";\n"); for (ByteCodeClass bc : classes) { bldM.append("extern struct clazz class__"); bldM.append(bc.getClsName().replace('/', '_').replace('$', '_')); bldM.append(";\n"); } bldM.append("\n\nstruct clazz* classesList[] = {"); first = true; for (ByteCodeClass bc : classes) { if (first) { bldM.append("\n "); } else { bldM.append(",\n "); } first = false; bldM.append(" &class__"); bldM.append(bc.getClsName().replace('/', '_').replace('$', '_')); } bldM.append("};\n\n\n"); // generate the markStatics method for (ByteCodeClass bc : classes) { bc.appendStaticFieldsExtern(bldM); } bldM.append( "\n\nextern int recursionKey;\nvoid markStatics(CODENAME_ONE_THREAD_STATE) {\n recursionKey++;\n"); for (ByteCodeClass bc : classes) { bc.appendStaticFieldsMark(bldM); } bldM.append("}\n\n"); bld.append("\n\n#endif // __CN1_CLASS_METHOD_INDEX_H__\n"); FileOutputStream fos = new FileOutputStream(new File(outputDirectory, "cn1_class_method_index.h")); fos.write(bld.toString().getBytes("UTF-8")); fos.close(); fos = new FileOutputStream(new File(outputDirectory, "cn1_class_method_index.m")); fos.write(bldM.toString().getBytes("UTF-8")); fos.close(); }