/** Runs BLOAT on a method. */ public static void bloatMethod(final MethodEditor m, final BloatContext context) { try { if (Main.COMPACT_ARRAY_INIT) { // Compact the initialization of arrays of the basic types by // putting the values of the array into a string in the constant // pool. The initialization code is replaced with a loop that // loads the array from the string in the constant pool. if (Main.TRACE) { System.out.println(" Compacting Arrays: " + Main.dateFormat.format(new Date())); } CompactArrayInitializer.transform(m); if (Main.DEBUG) { System.out.println("---------- After compaction:"); m.print(System.out); System.out.println("---------- end print"); } } FlowGraph cfg; // The control flow graph for a method if (Main.TRACE) { System.out.println(" Constructing CFG: " + Main.dateFormat.format(new Date())); } try { // Construct the control flow graph for method m cfg = new FlowGraph(m); } catch (final ClassFormatException ex) { System.err.println(ex.getMessage()); context.release(m.methodInfo()); return; } // We separate out initialization since before this the FlowGraph // more exactly represents the input program. cfg.initialize(); if (Main.TRACE) { System.out.println(" Transforming to SSA: " + Main.dateFormat.format(new Date())); } SSA.transform(cfg); if (FlowGraph.DEBUG) { System.out.println("---------- After SSA:"); cfg.print(System.out); System.out.println("---------- end print"); } if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (!Tree.USE_STACK) { // Do copy propagation and value numbering first to get rid of // all the extra copies inserted for dups. If they're left in, // it really slows down value numbering. if (Main.PROP) { if (Main.DEBUG) { System.out.println("-----Before Copy Propagation-----"); } if (Main.TRACE) { System.out.println(" Copy propagation: " + Main.dateFormat.format(new Date())); } final ExprPropagation copy = new ExprPropagation(cfg); copy.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (Main.DEBUG) { System.out.println("------After Copy Propagation-----"); cfg.print(System.out); } } } DeadCodeElimination dce = null; if (Main.DCE) { if (Main.TRACE) { System.out.println(" Dead Code Elimination: " + Main.dateFormat.format(new Date())); } if (Main.DEBUG) { System.out.println("---Before Dead Code Elimination--"); } dce = new DeadCodeElimination(cfg); dce.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (Main.DEBUG) { System.out.println("---After Dead Code Elimination---"); cfg.print(System.out); } } if (Main.INFER) { if (Main.DEBUG) { System.out.println("---------Doing type inference--------"); } if (Main.TRACE) { System.out.println(" Type Inferencing: " + Main.dateFormat.format(new Date())); } TypeInference.transform(cfg, context.getHierarchy()); } if (Main.NUMBER) { if (Main.TRACE) { System.out.println(" Value Numbering: " + Main.dateFormat.format(new Date())); } if (Main.DEBUG) { System.out.println("--------Doing value numbering--------"); } (new ValueNumbering()).transform(cfg); } if (Main.FOLD) { if (Main.DEBUG) { System.out.println("--------Before Value Folding---------"); } if (Main.TRACE) { System.out.println(" Value Folding: " + Main.dateFormat.format(new Date())); } (new ValueFolding()).transform(cfg); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("---------After Value Folding---------"); cfg.print(System.out); } } if (Main.PRE) { if (Main.DEBUG) { System.out.println("-------------Before SSAPRE-----------"); } if (Main.TRACE) { System.out.println(" SSAPRE: " + Main.dateFormat.format(new Date())); } final SSAPRE pre = new SSAPRE(cfg, context); pre.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("-------------After SSAPRE------------"); cfg.print(System.out); } } if (Main.FOLD) { if (Main.DEBUG) { System.out.println("--------Before Value Folding---------"); } if (Main.TRACE) { System.out.println(" Value Folding: " + Main.dateFormat.format(new Date())); } (new ValueFolding()).transform(cfg); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("---------After Value Folding---------"); cfg.print(System.out); } } if (Main.PROP) { if (Main.DEBUG) { System.out.println("-------Before Copy Propagation-------"); } if (Main.TRACE) { System.out.println(" Copy Propagation " + Main.dateFormat.format(new Date())); } final ExprPropagation copy = new ExprPropagation(cfg); copy.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("--------After Copy Propagation-------"); cfg.print(System.out); } } // make sure we've done at least one thing since the last DCE if (Main.DCE && (Main.INFER || Main.NUMBER || Main.FOLD || Main.PRE || Main.PROP)) { if (Main.DEBUG) { System.out.println("-----Before Dead Code Elimination----"); } if (Main.TRACE) { System.out.println(" Dead Code Elimination: " + Main.dateFormat.format(new Date())); } dce = new DeadCodeElimination(cfg); dce.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("-----After Dead Code Elimination-----"); cfg.print(System.out); } } if (Main.PERSIST) { (new PersistentCheckElimination()).transform(cfg); } if (Main.DIVA) { if (Main.DEBUG) { System.out.println("-----Before DIVA------"); } if (Main.TRACE) { System.out.println(" DIVA: " + Main.dateFormat.format(new Date())); } (new InductionVarAnalyzer()).transform(cfg); if (Main.DEBUG) { System.out.println("-----After DIVA-----"); cfg.print(System.out); } } /* * if (STACK_ALLOC) { if (DEBUG) { * System.out.println("------------Before StackPRE----------"); } * * StackPRE pre = new StackPRE(cfg); pre.transform(); * * if (DEBUG) { cfg.visit(new VerifyCFG()); } * * if (DEBUG) { System.out.println("------------After * StackPRE-----------"); cfg.print(System.out); } } */ // Do the new stack optimization if (Main.OPT_STACK_2) { if (Main.TRACE) { System.out.println(" New stack optimization: " + Main.dateFormat.format(new Date())); } // generate code without doing liveness or register allocation final CodeGenerator codegen = new CodeGenerator(m); codegen.replacePhis(cfg); m.clearCode2(); cfg.visit(codegen); // do stack optimization on the bytecode final StackOpt so = new StackOpt(); so.transform(m); // convert it back to a cfg cfg = new FlowGraph(m); cfg.initialize(); // convert it back to SSA SSA.transform(cfg); // do more dead code elimination (eliminate stores) dce = new DeadCodeElimination(cfg); dce.transform(); } if (Main.TRACE) { System.out.println(" Register allocation: " + Main.dateFormat.format(new Date())); } if (Main.VERIFY) { try { cfg.visit(new VerifyCFG()); } catch (final IllegalArgumentException ee) { System.out.println( " NOTE: CFG did not verify while " + "bloating " + m.name() + " after all optimizations. Exception: " + ee); } } // We're all done performing optimizations. Let's generate some code // and go home. // Perform liveness analysis of variables in the method. // Assign local variables ("registers") to expression values. final Liveness liveness = new Liveness(cfg); final RegisterAllocator alloc = new RegisterAllocator(cfg, liveness); // Gather information which can be used to optimize use of the stack if (CodeGenerator.OPT_STACK) { if (Main.TRACE) { System.out.println(" Old stack optimization: " + Main.dateFormat.format(new Date())); } StackOptimizer.optimizeCFG(cfg); } if (Main.TRACE) { System.out.println(" Code Generation: " + Main.dateFormat.format(new Date())); } // Start the code generation process. final CodeGenerator codegen = new CodeGenerator(m); codegen.replacePhis(cfg); if (Main.DEBUG) { System.out.println("After fixing Phis------------------------"); cfg.print(System.out); System.out.println("End print--------------------------------"); } codegen.simplifyControlFlow(cfg); codegen.allocReturnAddresses(cfg, alloc); if (Main.DEBUG) { System.out.println("After removing empty blocks--------------"); cfg.print(System.out); System.out.println("End print--------------------------------"); } // Clear the old contents of the bytecode store and generate new // code. // Code is generated using a visitor pattern on the CFG. m.clearCode(); cfg.visit(codegen); Peephole.transform(m); // Commit any changes that have been made to the method context.commit(m.methodInfo()); } catch (final Exception ex99) { final String msg = "** Exception while optimizing " + m.name() + m.type() + " of class " + m.declaringClass().name(); System.err.println(msg); System.err.println(ex99.getMessage()); ex99.printStackTrace(System.err); System.exit(1); } }
/** * Inserts residency/update/swizzle checks into a method. Iterates over the bytecodes in the * method and inserts the appropriate residency opcode. * * @param method The method to which to add checks. * @see MethodEditor#code */ private static void transform(final MethodEditor method) { if (Main.VERBOSE > 1) { System.out.println("Decorating method " + method); } // Optimize initialization of arrays to speed things up. CompactArrayInitializer.transform(method); final ListIterator iter = method.code().listIterator(); // Go through the code (Instructions and Labels) in the method INST: while (iter.hasNext()) { final Object ce = iter.next(); if (Main.VERBOSE > 2) { System.out.println("Examining " + ce); } if (ce instanceof Instruction) { final Instruction inst = (Instruction) ce; int uctype = Main.NONE; // Type of update check (POINTER or // SCALAR) boolean insert_sc = false; // Insert swizzle check (aaload // only)? final int opc = inst.opcodeClass(); int depth; switch (opc) { case opcx_arraylength: case opcx_athrow: case opcx_getfield: case opcx_instanceof: { depth = 0; break; } case opcx_iaload: case opcx_laload: case opcx_faload: case opcx_daload: case opcx_baload: case opcx_caload: case opcx_saload: { depth = 1; break; } case opcx_aaload: { depth = 1; insert_sc = true; break; } case opcx_iastore: case opcx_fastore: case opcx_aastore: case opcx_bastore: case opcx_castore: case opcx_sastore: { depth = 2; break; } case opcx_lastore: case opcx_dastore: { depth = 3; break; } case opcx_putfield: { final MemberRef ref = (MemberRef) inst.operand(); depth = ref.type().stackHeight(); if (ref.type().isReference()) { uctype = Main.POINTER; } else { uctype = Main.SCALAR; } break; } case opcx_invokevirtual: case opcx_invokespecial: case opcx_invokeinterface: { final MemberRef ref = (MemberRef) inst.operand(); depth = ref.type().stackHeight(); break; } case opcx_rc: { // Skip any existing residency checks. iter.remove(); continue INST; } case opcx_aupdate: { // Skip any existing update checks. iter.remove(); continue INST; } case opcx_supdate: { // Skip any existing update checks. iter.remove(); continue INST; } default: { continue INST; } } Instruction addInst; // Insert a residency check... if (Main.RC) { Object t; // ////////////////////////////////// // Before... // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next // // After... // +-----+----+------+-----------+ // | ... | RC | inst | afterInst | // +-----+----+------+-----------+ // ^prev ^next // ////////////////////////////////// // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next addInst = new Instruction(Opcode.opcx_rc, new Integer(depth)); iter.add(addInst); // +-----+----+------+-----------+ // | ... | RC | inst | afterInst | // +-----+----+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+----+------+-----------+ // | ... | RC | inst | afterInst | // +-----+----+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+----+------+-----------+ // | ... | RC | inst | afterInst | // +-----+----+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+----+------+-----------+ // | ... | RC | inst | afterInst | // +-----+----+------+-----------+ // ^prev ^next if (Main.VERBOSE > 2) { System.out.println("Inserting " + addInst + " before " + inst); } } else { if (Main.VERBOSE > 2) { System.out.println("Not inserting rc before " + inst); } } // Insert a swizzle check... if (insert_sc) { if (Main.SC) { Object t; // //////////////////////////////////////////// // Before... // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next // // After... // +-----+------+----------+------+-----------+ // | ... | dup2 | aswizzle | inst | afterInst | // +-----+------+----------+------+-----------+ // ^prev ^next // ///////////////////////////////////////////// // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next addInst = new Instruction(Opcode.opcx_dup2); iter.add(addInst); // +-----+------+------+-----------+ // | ... | dup2 | inst | afterInst | // +-----+------+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+------+------+-----------+ // | ... | dup2 | inst | afterInst | // +-----+------+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+------+------+-----------+ // | ... | dup2 | inst | afterInst | // +-----+------+------+-----------+ // ^prev ^next addInst = new Instruction(Opcode.opcx_aswizzle); iter.add(addInst); // +-----+------+----------+------+-----------+ // | ... | dup2 | aswizzle | inst | afterInst | // +-----+------+----------+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+------+----------+------+-----------+ // | ... | dup2 | aswizzle | inst | afterInst | // +-----+------+----------+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+------+----------+------+-----------+ // | ... | dup2 | aswizzle | inst | afterInst | // +-----+------+----------+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+------+----------+------+-----------+ // | ... | dup2 | aswizzle | inst | afterInst | // +-----+------+----------+------+-----------+ // ^prev ^next if (Main.VERBOSE > 2) { System.out.println("Inserting dup2,aswizzle before " + inst); } } else { if (Main.VERBOSE > 2) { System.out.println("Not inserting aswizzle before " + inst); } } } // Insert an update check... if (uctype != Main.NONE) { if (Main.UC) { Object t; // //////////////////////////////////////////// // Before... // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next // // After... // +-----+---------+------+-----------+ // | ... | aupdate | inst | afterInst | // +-----+---------+------+-----------+ // ^prev ^next // ///////////////////////////////////////////// // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+------+-----------+ // | ... | inst | afterInst | // +-----+------+-----------+ // ^prev ^next addInst = new Instruction(Opcode.opcx_aupdate, new Integer(depth)); /* * if (uctype == POINTER) { addInst = new * Instruction(opcx_aupdate, new Integer(depth)); } else { * addInst = new Instruction(opcx_supdate, new * Integer(depth)); } */ iter.add(addInst); // +-----+---------+------+-----------+ // | ... | aupdate | inst | afterInst | // +-----+---------+------+-----------+ // ^prev ^next t = iter.previous(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+---------+------+-----------+ // | ... | aupdate | inst | afterInst | // +-----+---------+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == addInst, t + " != " + addInst); // +-----+---------+------+-----------+ // | ... | aupdate | inst | afterInst | // +-----+---------+------+-----------+ // ^prev ^next t = iter.next(); Assert.isTrue(t == inst, t + " != " + inst); // +-----+---------+------+-----------+ // | ... | aupdate | inst | afterInst | // +-----+---------+------+-----------+ // ^prev ^next if (Main.VERBOSE > 2) { System.out.println("Inserting " + addInst + " before " + inst); } } else if (Main.VERBOSE > 2) { System.out.println("Not inserting uc before " + inst); } } } } }