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; }
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; } } } } }
@Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { int[] keys = new int[labels.length]; int counter = min; for (int iter = 0; iter < keys.length; iter++) { keys[iter] = counter; counter++; } mtd.addSwitch(dflt, keys, labels); super.visitTableSwitchInsn(min, max, dflt, labels); }
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 void visitJumpInsn(int opcode, Label label) { mtd.addJump(opcode, label); super.visitJumpInsn(opcode, label); }
@Override public void visitLabel(Label label) { mtd.addLabel(label); super.visitLabel(label); }
@Override public void visitLdcInsn(Object cst) { mtd.addLdc(cst); super.visitLdcInsn(cst); }
@Override public void visitIincInsn(int var, int increment) { mtd.addIInc(var, increment); super.visitIincInsn(var, increment); }
@Override public void visitIntInsn(int opcode, int operand) { mtd.addVariableOperation(opcode, operand); super.visitIntInsn(opcode, operand); }
@Override public void visitTypeInsn(int opcode, String type) { mtd.addTypeInstruction(opcode, type); super.visitTypeInsn(opcode, type); }
@Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { mtd.addTryCatchBlock(start, end, handler, type); super.visitTryCatchBlock(start, end, handler, type); }
@Override public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index) { mtd.addLocalVariable(name, desc, signature, start, end, index); super.visitLocalVariable(name, desc, signature, start, end, index); }
@Override public void visitLineNumber(int line, Label start) { mtd.addDebugInfo(line); super.visitLineNumber(line, start); }
@Override public void visitMaxs(int maxStack, int maxLocals) { mtd.setMaxes(maxStack, maxLocals); super.visitMaxs(maxStack, maxLocals); }
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { mtd.addInvoke(opcode, owner, name, desc, itf); super.visitMethodInsn(opcode, owner, name, desc, itf); }
@Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { mtd.addField(opcode, owner, name, desc); super.visitFieldInsn(opcode, owner, name, desc); }
@Override public void visitMultiANewArrayInsn(String desc, int dims) { mtd.addMultiArray(desc, dims); super.visitMultiANewArrayInsn(desc, dims); }
@Override public void visitVarInsn(int opcode, int var) { mtd.addVariableOperation(opcode, var); super.visitVarInsn(opcode, var); }
@Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { mtd.addSwitch(dflt, keys, labels); super.visitLookupSwitchInsn(dflt, keys, labels); }
@Override public void visitInsn(int opcode) { mtd.addInstruction(opcode); super.visitInsn(opcode); }
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(); }