001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.bc2ir;
014    
015    import java.util.Enumeration;
016    import java.util.HashMap;
017    import java.util.HashSet;
018    import java.util.Iterator;
019    import java.util.Map;
020    
021    import org.jikesrvm.ArchitectureSpecificOpt.RegisterPool;
022    import org.jikesrvm.VM;
023    import org.jikesrvm.classloader.RVMMethod;
024    import org.jikesrvm.classloader.NormalMethod;
025    import org.jikesrvm.classloader.RVMType;
026    import org.jikesrvm.classloader.TypeReference;
027    import org.jikesrvm.compilers.baseline.BranchProfile;
028    import org.jikesrvm.compilers.baseline.BranchProfiles;
029    import org.jikesrvm.compilers.baseline.ConditionalBranchProfile;
030    import org.jikesrvm.compilers.baseline.EdgeCounts;
031    import org.jikesrvm.compilers.baseline.SwitchBranchProfile;
032    import org.jikesrvm.compilers.common.CompiledMethod;
033    import org.jikesrvm.compilers.opt.ClassLoaderProxy;
034    import org.jikesrvm.compilers.opt.OptOptions;
035    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
036    import org.jikesrvm.compilers.opt.inlining.InlineOracle;
037    import org.jikesrvm.compilers.opt.inlining.InlineSequence;
038    import org.jikesrvm.compilers.opt.ir.BasicBlock;
039    import org.jikesrvm.compilers.opt.ir.Call;
040    import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
041    import org.jikesrvm.compilers.opt.ir.Empty;
042    import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
043    import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag;
044    import org.jikesrvm.compilers.opt.ir.IRTools;
045    import org.jikesrvm.compilers.opt.ir.Instruction;
046    import org.jikesrvm.compilers.opt.ir.MonitorOp;
047    import org.jikesrvm.compilers.opt.ir.Move;
048    import org.jikesrvm.compilers.opt.ir.Nullary;
049    import org.jikesrvm.compilers.opt.ir.Operators;
050    import org.jikesrvm.compilers.opt.ir.Prologue;
051    import org.jikesrvm.compilers.opt.ir.Register;
052    import org.jikesrvm.compilers.opt.ir.Return;
053    import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
054    import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
055    import org.jikesrvm.compilers.opt.ir.operand.ClassConstantOperand;
056    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
057    import org.jikesrvm.compilers.opt.ir.operand.Operand;
058    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
059    import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
060    import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
061    import org.jikesrvm.runtime.Entrypoints;
062    import org.jikesrvm.runtime.Statics;
063    import org.vmmagic.unboxed.Offset;
064    
065    /**
066     * Defines the context in which BC2IR will abstractly interpret
067     * a method's bytecodes and populate targetIR with instructions.
068     *
069     **/
070    public final class GenerationContext implements org.jikesrvm.compilers.opt.driver.OptConstants, Operators {
071    
072      //////////
073      // These fields are used to communicate information from its
074      // caller to BC2IR
075      //////////
076      /**
077       * The original method (root of the calling context tree)
078       */
079      NormalMethod original_method;
080    
081      /**
082       * The compiled method assigned for this compilation of original_method
083       */
084      CompiledMethod original_cm;
085    
086      /**
087       * The method to be generated
088       */
089      public NormalMethod method;
090    
091      /**
092       * The BranchProfile data for method, if available
093       */
094      BranchProfiles branchProfiles;
095    
096      /**
097       * The options to control the generation
098       */
099      public OptOptions options;
100    
101      /**
102       * The CFG object into which instructions should be generated.
103       */
104      public ControlFlowGraph cfg;
105    
106      /**
107       * The register pool to be used during generation
108       */
109      public RegisterPool temps;
110    
111      /**
112       * The parameters which BC2IR should use to seed the local state
113       * for the entry basic block.
114       */
115      Operand[] arguments;
116    
117      /**
118       * The basic block into which BC2IR's caller will generate a "prologue."
119       * BC2IR will add a CFG edge from prologue to the block containing the
120       * instructions generated for bytecode 0, but it is its caller's
121       * responsibility to populate the prologue with instructions.
122       * All blocks generated by BC2IR will be injected by BC2IR.doFinalPass
123       * immediately
124       * after prologue in the code ordering
125       * (ie prologue can assume it will fallthrough
126       * to the first basic block in the ir generated for method.
127       */
128      public BasicBlock prologue;
129    
130      /**
131       * The basic block into which BC2IR's caller will generate an epilogue.
132       * BC2IR will add CFG edges to this node, but it is its caller's
133       * responsibility to populate it with instructions.
134       * NOTE: After IR is generated one of two conditions will hold:
135       * <ul>
136       * <li> epilogue == cfg.lastInCodeOrder():  (if it is to be inlined,
137       *                                           then the generated cfg
138       *                                           is expecting to "fallthrough"
139       *                                           to the next bblock)
140       * <li> epilogue == null:  implies that there is no "normal" exit from
141       *                         the callee (all exits via throw)
142       * </ul>
143       * NOTE: BC2IR assumes that epilogue is a single basic block
144       *       (i.e. it has no out edges)
145       */
146      public BasicBlock epilogue;
147    
148      /**
149       * The exit node of the outermost CFG
150       * (used by BC2IR for not-definitely caught athrows and by OSR_Yieldpoints)
151       */
152      public BasicBlock exit;
153    
154      /**
155       * A catch, unlock, and rethrow exception handler used for
156       * synchronized methods.
157       */
158      BasicBlock unlockAndRethrow;
159    
160      /**
161       * The Register to which BC2IR should assign the return value(s)
162       * of the method. It will be null when the method has a void return.
163       */
164      Register resultReg;
165    
166      /**
167       * The enclosing exception handlers (null if there are none).
168       */
169      ExceptionHandlerBasicBlockBag enclosingHandlers;
170    
171      /**
172       * Inlining context of the method to be generated
173       */
174      public InlineSequence inlineSequence;
175    
176      /**
177       * The InlineOracle to be consulted for all inlining decisions during
178       * the generation of this IR.
179       */
180      InlineOracle inlinePlan;
181    
182      //////////
183      // These fields are used to communicate information from BC2IR to its caller
184      //////////
185      /**
186       * Did BC2IR generate a reachable exception handler while generating
187       * the IR for this method
188       */
189      public boolean generatedExceptionHandlers;
190    
191      /**
192       * Did BC2IR encounter a magic that requires us to allocate a stack frame?
193       */
194      public boolean allocFrame;
195    
196      /**
197       * Used to communicate the meet of the return values back to the caller
198       * Mainly useful when BC2IR is doing inlining....allows the caller
199       * BC2IR object
200       * to exploit knowledge the callee BC2IR object had about the result.
201       */
202      public Operand result;
203      /**
204       * Do we do check stores?
205       */
206      boolean doesCheckStore;
207    
208      //////////
209      // Main public methods
210      /////////
211    
212      /**
213       * Use this constructor to create an outermost (non-inlined)
214       * GenerationContext.
215       *
216       * @param meth The NormalMethod whose IR will be generated
217       * @param params The known types of the parameters to the method. For method specialization.
218       * @param cm   The compiled method id to be used for this compilation
219       * @param opts The Options to be used for the generation
220       * @param ip   The InlineOracle to be used for the generation
221       */
222      GenerationContext(NormalMethod meth, TypeReference[] params, CompiledMethod cm, OptOptions opts, InlineOracle ip) {
223        original_method = meth;
224        original_cm = cm;
225        method = meth;
226        if (opts.frequencyCounters() || opts.inverseFrequencyCounters()) {
227          branchProfiles = EdgeCounts.getBranchProfiles(meth);
228        }
229        options = opts;
230        inlinePlan = ip;
231        inlineSequence = new InlineSequence(meth);
232        doesCheckStore = !meth.hasNoCheckStoreAnnotation();
233    
234        // Create the CFG. Initially contains prologue, epilogue, and exit.
235        cfg = new ControlFlowGraph(0);
236        prologue = new BasicBlock(PROLOGUE_BLOCK_BCI, inlineSequence, cfg);
237        epilogue = new BasicBlock(EPILOGUE_BLOCK_BCI, inlineSequence, cfg);
238        cfg.addLastInCodeOrder(prologue);
239        cfg.addLastInCodeOrder(epilogue);
240        exit = cfg.exit();
241        epilogue.insertOut(exit);
242    
243        // Create register pool, initialize arguments, resultReg.
244        temps = new RegisterPool(meth);
245        _ncGuards = new HashMap<Register, RegisterOperand>();
246        initLocalPool();
247        TypeReference[] definedParams = meth.getParameterTypes();
248        if (params == null) params = definedParams;
249        int numParams = params.length;
250        int argIdx = 0;
251        int localNum = 0;
252        arguments = new Operand[method.isStatic() ? numParams : numParams + 1];
253        // Insert IR_PROLOGUE instruction.  Loop below will fill in its operands
254        Instruction prologueInstr = Prologue.create(IR_PROLOGUE, arguments.length);
255        appendInstruction(prologue, prologueInstr, PROLOGUE_BCI);
256    
257        if (!method.isStatic()) {
258          TypeReference thisType = meth.getDeclaringClass().getTypeRef();
259          RegisterOperand thisOp = makeLocal(localNum, thisType);
260          // The this param of a virtual method is by definition non null
261          RegisterOperand guard = makeNullCheckGuard(thisOp.getRegister());
262          BC2IR.setGuard(thisOp, guard);
263          appendInstruction(prologue, Move.create(GUARD_MOVE, guard.copyRO(), new TrueGuardOperand()), PROLOGUE_BCI);
264          thisOp.setDeclaredType();
265          thisOp.setExtant();
266          if (method.getDeclaringClass().isFinal()) {
267            thisOp.setPreciseType();
268          }
269          arguments[0] = thisOp;
270          Prologue.setFormal(prologueInstr, 0, thisOp.copyU2D());
271          argIdx++;
272          localNum++;
273        }
274        for (int paramIdx = 0; paramIdx < numParams; paramIdx++) {
275          TypeReference argType = params[paramIdx];
276          RegisterOperand argOp = makeLocal(localNum, argType);
277          argOp.setDeclaredType();
278          if (argType.isClassType()) {
279            argOp.setExtant();
280          }
281          arguments[argIdx] = argOp;
282          Prologue.setFormal(prologueInstr, argIdx, argOp.copyU2D());
283          argIdx++;
284          localNum++;
285          if (argType.isLongType() || argType.isDoubleType()) {
286            localNum++; // longs & doubles take two words of local space
287          }
288        }
289        TypeReference returnType = meth.getReturnType();
290        if (returnType != TypeReference.Void) {
291          resultReg = temps.makeTemp(returnType).getRegister();
292        }
293    
294        enclosingHandlers = null;
295    
296        completePrologue(true);
297        completeEpilogue(true);
298        completeExceptionHandlers(true);
299      }
300    
301      /**
302       * Create a child generation context from parent & callerBB to
303       * generate IR for callsite.
304       * Make this 'static' to avoid confusing parent/child fields.
305       *
306       * @param parent the parent gc
307       * @param ebag the enclosing exception handlers (null if none)
308       * @param callee the callee method to be inlined
309       *        (may _not_ be equal to Call.getMethod(callSite).method)
310       * @param callSite the Call instruction to be inlined.
311       * @return the child context
312       */
313      public static GenerationContext createChildContext(GenerationContext parent, ExceptionHandlerBasicBlockBag ebag,
314                                                      NormalMethod callee, Instruction callSite) {
315        GenerationContext child = new GenerationContext();
316        child.method = callee;
317        if (parent.options.frequencyCounters() || parent.options.inverseFrequencyCounters()) {
318          child.branchProfiles = EdgeCounts.getBranchProfiles(callee);
319        }
320        child.original_method = parent.original_method;
321        child.original_cm = parent.original_cm;
322    
323        // Some state gets directly copied to the child
324        child.options = parent.options;
325        child.temps = parent.temps;
326        child._ncGuards = parent._ncGuards;
327        child.exit = parent.exit;
328        child.inlinePlan = parent.inlinePlan;
329    
330        // Now inherit state based on callSite
331        child.inlineSequence = new InlineSequence(child.method, callSite.position, callSite);
332        child.enclosingHandlers = ebag;
333        child.arguments = new Operand[Call.getNumberOfParams(callSite)];
334        for (int i = 0; i < child.arguments.length; i++) {
335          child.arguments[i] = Call.getParam(callSite, i).copy(); // copy instead
336          // of clearing in case inlining aborts.
337        }
338        if (Call.hasResult(callSite)) {
339          child.resultReg = Call.getResult(callSite).copyD2D().getRegister();
340          child.resultReg.setSpansBasicBlock(); // it will...
341        }
342    
343        // Initialize the child CFG, prologue, and epilogue blocks
344        child.cfg = new ControlFlowGraph(parent.cfg.numberOfNodes());
345        child.prologue = new BasicBlock(PROLOGUE_BCI, child.inlineSequence, child.cfg);
346        child.prologue.exceptionHandlers = ebag;
347        child.epilogue = new BasicBlock(EPILOGUE_BCI, child.inlineSequence, child.cfg);
348        child.epilogue.exceptionHandlers = ebag;
349        child.cfg.addLastInCodeOrder(child.prologue);
350        child.cfg.addLastInCodeOrder(child.epilogue);
351    
352        // Set up the local pool
353        child.initLocalPool();
354    
355        // Insert moves from child.arguments to child's locals in prologue
356        TypeReference[] params = child.method.getParameterTypes();
357        int numParams = params.length;
358        int argIdx = 0;
359        int localNum = 0;
360        if (!child.method.isStatic()) {
361          Operand receiver = child.arguments[argIdx];
362          argIdx++;
363          RegisterOperand local = null;
364          if (receiver.isRegister()) {
365            RegisterOperand objPtr = receiver.asRegister();
366            if (ClassLoaderProxy.includesType(child.method.getDeclaringClass().getTypeRef(), objPtr.getType()) != YES) {
367              // narrow type of actual to match formal static type implied by method
368              objPtr.clearPreciseType(); // Can be precise but not assignable if enough classes aren't loaded
369              objPtr.setDeclaredType();
370              objPtr.setType(child.method.getDeclaringClass().getTypeRef());
371            }
372            local = child.makeLocal(localNum, objPtr);
373            localNum++;
374            child.arguments[0] = local; // Avoid confusion in BC2IR of callee
375            // when objPtr is a local in the caller.
376          } else if (receiver.isConstant()) {
377            local = child.makeLocal(localNum, receiver.getType());
378            localNum++;
379            local.setPreciseType();
380            // Constants trivially non-null
381            RegisterOperand guard = child.makeNullCheckGuard(local.getRegister());
382            BC2IR.setGuard(local, guard);
383            child.prologue.appendInstruction(Move.create(GUARD_MOVE, guard.copyRO(), new TrueGuardOperand()));
384          } else {
385            OptimizingCompilerException.UNREACHABLE("Unexpected receiver operand");
386          }
387          Instruction s = Move.create(REF_MOVE, local, receiver);
388          s.bcIndex = PROLOGUE_BCI;
389          s.position = callSite.position;
390          child.prologue.appendInstruction(s);
391        }
392        for (int paramIdx = 0; paramIdx < numParams; paramIdx++, argIdx++) {
393          TypeReference argType = params[paramIdx];
394          RegisterOperand formal;
395          Operand actual = child.arguments[argIdx];
396          if (actual.isRegister()) {
397            RegisterOperand rActual = actual.asRegister();
398            if (ClassLoaderProxy.includesType(argType, rActual.getType()) != YES) {
399              // narrow type of actual to match formal static type implied by method
400              rActual.clearPreciseType(); // Can be precise but not
401              // assignable if enough classes aren't loaded
402              rActual.setDeclaredType();
403              rActual.setType(argType);
404            }
405            formal = child.makeLocal(localNum, rActual);
406            localNum++;
407            child.arguments[argIdx] = formal;  // Avoid confusion in BC2IR of
408            // callee when arg is a local in the caller.
409          } else {
410            formal = child.makeLocal(localNum, argType);
411            localNum++;
412          }
413          Instruction s = Move.create(IRTools.getMoveOp(argType), formal, actual);
414          s.bcIndex = PROLOGUE_BCI;
415          s.position = callSite.position;
416          child.prologue.appendInstruction(s);
417          if (argType.isLongType() || argType.isDoubleType()) {
418            localNum++; // longs and doubles take two local words
419          }
420        }
421    
422        child.completePrologue(false);
423        child.completeEpilogue(false);
424        child.completeExceptionHandlers(false);
425    
426        return child;
427      }
428    
429      /**
430       * Only for internal use by Inliner (when inlining multiple targets)
431       * This is probably not the prettiest way to handle this, but it requires
432       * no changes to BC2IR's & Inliner's high level control logic.
433       *
434       * @param parent the parent GC
435       * @param ebag the enclosing exception handlers (null if none)
436       * @return the synthetic context
437       */
438      public static GenerationContext createSynthetic(GenerationContext parent, ExceptionHandlerBasicBlockBag ebag) {
439        // Create the CFG. Initially contains prologue and epilogue
440        GenerationContext child = new GenerationContext();
441    
442        child.cfg = new ControlFlowGraph(-100000);
443    
444        // It may be wrong to use the parent inline sequence as the
445        // position here, but it seems to work out.  This is a synthetic
446        // context that is just used as a container for multiple inlined
447        // targets, so in the cases that I've observed where the prologue
448        // and epilogue don't disappear, it was correct to have the
449        // parent's position. -- Matt
450        child.prologue = new BasicBlock(PROLOGUE_BCI, parent.inlineSequence, parent.cfg);
451        child.prologue.exceptionHandlers = ebag;
452        child.epilogue = new BasicBlock(EPILOGUE_BCI, parent.inlineSequence, parent.cfg);
453        child.epilogue.exceptionHandlers = ebag;
454        child.cfg.addLastInCodeOrder(child.prologue);
455        child.cfg.addLastInCodeOrder(child.epilogue);
456    
457        // All other fields are intentionally left null.
458        // We are only really using this context to transfer a synthetic CFG
459        // from the low-level Inliner.execute back to its caller.
460        // TODO: Rewrite GenerationContext to be a subclass of a root
461        // class that is just a CFG wrapper.  Then, have an instance of this
462        // new parent
463        // class be the return value for the main entrypoints in Inliner
464        // and create an instance of the root class instead of GC when
465        // inlining multiple targets.
466    
467        return child;
468      }
469    
470      /**
471       * Use this to transfer state back from a child context back to its parent.
472       *
473       * @param parent the parent context that will receive the state
474       * @param child  the child context from which the state will be taken
475       */
476      public static void transferState(GenerationContext parent, GenerationContext child) {
477        parent.cfg.setNumberOfNodes(child.cfg.numberOfNodes());
478        if (child.generatedExceptionHandlers) {
479          parent.generatedExceptionHandlers = true;
480        }
481        if (child.allocFrame) {
482          parent.allocFrame = true;
483        }
484      }
485    
486      ///////////
487      // Local variables
488      ///////////
489    
490      // The registers to use for various types of locals.
491      // Note that "int" really means 32-bit gpr.
492      private Register[] intLocals;
493      private Register[] addressLocals;
494      private Register[] floatLocals;
495      private Register[] longLocals;
496      private Register[] doubleLocals;
497    
498      private void initLocalPool() {
499        int numLocals = method.getLocalWords();
500        intLocals = new Register[numLocals];
501        addressLocals = new Register[numLocals];
502        floatLocals = new Register[numLocals];
503        longLocals = new Register[numLocals];
504        doubleLocals = new Register[numLocals];
505      }
506    
507      private Register[] getPool(TypeReference type) {
508        if (type == TypeReference.Float) {
509          return floatLocals;
510        } else if (type == TypeReference.Long) {
511          return longLocals;
512        } else if (type == TypeReference.Double) {
513          return doubleLocals;
514        } else if (type.isReferenceType() || type.isWordLikeType()) {
515          return addressLocals;
516        } else {
517          return intLocals;
518        }
519      }
520    
521      /**
522       * Return the Register used to for local i of TypeReference type
523       */
524      public Register localReg(int i, TypeReference type) {
525        Register[] pool = getPool(type);
526        if (pool[i] == null) {
527          pool[i] = temps.getReg(type);
528          pool[i].setLocal();
529        }
530        return pool[i];
531      }
532    
533      /**
534       * Should null checks be generated?
535       */
536      boolean noNullChecks() {
537        return method.hasNoNullCheckAnnotation();
538      }
539    
540      /**
541       * Should bounds checks be generated?
542       */
543      boolean noBoundsChecks() {
544        return method.hasNoBoundsCheckAnnotation();
545      }
546    
547      /**
548       * Make a register operand that refers to the given local variable number
549       * and has the given type.
550       *
551       * @param i local variable number
552       * @param type desired data type
553       */
554      public RegisterOperand makeLocal(int i, TypeReference type) {
555        return new RegisterOperand(localReg(i, type), type);
556      }
557    
558      /**
559       * Make a register operand that refers to the given local variable number,
560       * and inherits its properties (type, flags) from props
561       *
562       * @param i local variable number
563       * @param props RegisterOperand to inherit flags from
564       */
565      RegisterOperand makeLocal(int i, RegisterOperand props) {
566        RegisterOperand local = makeLocal(i, props.getType());
567        local.setInheritableFlags(props);
568        BC2IR.setGuard(local, BC2IR.getGuard(props));
569        return local;
570      }
571    
572      /**
573       * Get the local number for a given register
574       */
575      public int getLocalNumberFor(Register reg, TypeReference type) {
576        Register[] pool = getPool(type);
577        for (int i = 0; i < pool.length; i++) {
578          if (pool[i] == reg) return i;
579        }
580        return -1;
581      }
582    
583      /**
584       * Is the operand a particular bytecode local?
585       */
586      public boolean isLocal(Operand op, int i, TypeReference type) {
587        if (op instanceof RegisterOperand) {
588          if (getPool(type)[i] == ((RegisterOperand) op).getRegister()) return true;
589        }
590        return false;
591      }
592    
593      ///////////
594      // Validation operands (guards)
595      ///////////
596    
597      // For each register, we always use the same register as a validation operand.
598      // This helps us avoid needlessly losing information at CFG join points.
599      private HashMap<Register, RegisterOperand> _ncGuards;
600    
601      /**
602       * Make a register operand to use as a null check guard for the
603       * given register.
604       */
605      RegisterOperand makeNullCheckGuard(Register ref) {
606        RegisterOperand guard = _ncGuards.get(ref);
607        if (guard == null) {
608          guard = temps.makeTempValidation();
609          _ncGuards.put(ref, guard.copyRO());
610        } else {
611          guard = guard.copyRO();
612        }
613        return guard;
614      }
615    
616      ///////////
617      // Profile data
618      ///////////
619      public BranchProfileOperand getConditionalBranchProfileOperand(int bcIndex, boolean backwards) {
620        float prob;
621        BranchProfile bp;
622        if (branchProfiles != null && ((bp = branchProfiles.getEntry(bcIndex)) != null)) {
623          prob = ((ConditionalBranchProfile) bp).getTakenProbability();
624        } else {
625          if (branchProfiles != null) {
626            VM.sysWrite("Warning: conditional branch profile entry not found");
627          }
628          if (backwards) {
629            prob = 0.9f;
630          } else {
631            prob = 0.5f;
632          }
633        }
634        // experimental option: flip the probability to see how bad things would be if
635        // we were completely wrong.
636        if (options.inverseFrequencyCounters()) {
637          prob = 1f - prob;
638        }
639        return new BranchProfileOperand(prob);
640      }
641    
642      public SwitchBranchProfile getSwitchProfile(int bcIndex) {
643        if (branchProfiles != null) {
644          BranchProfile bp = branchProfiles.getEntry(bcIndex);
645          return (SwitchBranchProfile) bp;
646        } else {
647          return null;
648        }
649      }
650    
651      ///////////
652      // Implementation
653      ///////////
654    
655      /**
656       * for internal use only (in createInlinedContext)
657       */
658      private GenerationContext() {}
659    
660      /**
661       * Fill in the rest of the method prologue.
662       * PRECONDITION: arguments & temps have been setup/initialized.
663       */
664      private void completePrologue(boolean isOutermost) {
665        // Deal with Uninteruptible code.
666        if (!isOutermost && requiresUnintMarker()) {
667          Instruction s = Empty.create(UNINT_BEGIN);
668          appendInstruction(prologue, s, PROLOGUE_BCI);
669        }
670    
671        // Deal with implicit monitorenter for synchronized methods.
672        // When working with the class writer do not expand static
673        // synchronization headers as there is no easy way to get at
674        // class object
675    
676        // OSR: if this is a specialized method, no monitor enter at the beginging
677        // since it's the second time reenter
678        if (method.isForOsrSpecialization()) {
679          // do nothing
680        } else if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
681          Operand lockObject = getLockObject();
682          Instruction s = MonitorOp.create(MONITORENTER, lockObject, new TrueGuardOperand());
683          appendInstruction(prologue, s, SYNCHRONIZED_MONITORENTER_BCI);
684        }
685      }
686    
687      /**
688       * Fill in the rest of the method epilogue.
689       * PRECONDITION: arguments & temps have been setup/initialized.
690       */
691      private void completeEpilogue(boolean isOutermost) {
692        // Deal with implicit monitorexit for synchronized methods.
693        if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
694          Operand lockObject = getLockObject();
695          Instruction s = MonitorOp.create(MONITOREXIT, lockObject, new TrueGuardOperand());
696          appendInstruction(epilogue, s, SYNCHRONIZED_MONITOREXIT_BCI);
697        }
698    
699        // Deal with Uninterruptible code.
700        if (!isOutermost && requiresUnintMarker()) {
701          Instruction s = Empty.create(UNINT_END);
702          appendInstruction(epilogue, s, EPILOGUE_BCI);
703        }
704    
705        if (isOutermost) {
706          TypeReference returnType = method.getReturnType();
707          Operand retVal = returnType.isVoidType() ? null : new RegisterOperand(resultReg, returnType);
708          Instruction s = Return.create(RETURN, retVal);
709          appendInstruction(epilogue, s, EPILOGUE_BCI);
710        }
711      }
712    
713      /**
714       * If the method is synchronized then we wrap it in a
715       * synthetic exception handler that unlocks & rethrows
716       * PRECONDITION: cfg, arguments & temps have been setup/initialized.
717       */
718      private void completeExceptionHandlers(boolean isOutermost) {
719        if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
720          ExceptionHandlerBasicBlock rethrow =
721              new ExceptionHandlerBasicBlock(SYNTH_CATCH_BCI,
722                                                 inlineSequence,
723                                                 new TypeOperand(RVMType.JavaLangThrowableType),
724                                                 cfg);
725          rethrow.exceptionHandlers = enclosingHandlers;
726          RegisterOperand ceo = temps.makeTemp(TypeReference.JavaLangThrowable);
727          Instruction s = Nullary.create(GET_CAUGHT_EXCEPTION, ceo);
728          appendInstruction(rethrow, s, SYNTH_CATCH_BCI);
729          Operand lockObject = getLockObject();
730    
731          RVMMethod target = Entrypoints.unlockAndThrowMethod;
732          MethodOperand methodOp = MethodOperand.STATIC(target);
733          methodOp.setIsNonReturningCall(true); // Used to keep cfg correct
734          s =
735              Call.create2(CALL,
736                           null,
737                           new AddressConstantOperand(target.getOffset()),
738                           methodOp,
739                           lockObject,
740                           ceo.copyD2U());
741          appendInstruction(rethrow, s, RUNTIME_SERVICES_BCI);
742    
743          cfg.insertBeforeInCodeOrder(epilogue, rethrow);
744    
745          // May be overly conservative
746          // (if enclosed by another catch of Throwable...)
747          if (enclosingHandlers != null) {
748            for (Enumeration<BasicBlock> e = enclosingHandlers.enumerator(); e.hasMoreElements();) {
749              BasicBlock eh = e.nextElement();
750              rethrow.insertOut(eh);
751            }
752          }
753          rethrow.setCanThrowExceptions();
754          rethrow.setMayThrowUncaughtException();
755          rethrow.insertOut(exit);
756    
757          // save a reference to this block so we can discard it if unused.
758          unlockAndRethrow = rethrow;
759    
760          ExceptionHandlerBasicBlock[] sh = new ExceptionHandlerBasicBlock[1];
761          sh[0] = rethrow;
762          enclosingHandlers = new ExceptionHandlerBasicBlockBag(sh, enclosingHandlers);
763          generatedExceptionHandlers = true;
764        }
765      }
766    
767      /**
768       * Get the object for locking for synchronized methods.
769       * either the class object or the this ptr.
770       */
771      private Operand getLockObject() {
772        if (method.isStatic()) {
773          Class<?> klass = method.getDeclaringClass().getClassForType();
774          Offset offs = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(klass));
775          return new ClassConstantOperand(klass, offs);
776        } else {
777          return makeLocal(0, arguments[0].getType());
778        }
779      }
780    
781      private void appendInstruction(BasicBlock b, Instruction s, int bcIndex) {
782        s.position = inlineSequence;
783        s.bcIndex = bcIndex;
784        b.appendInstruction(s);
785      }
786    
787      private boolean requiresUnintMarker() {
788        if (method.isInterruptible()) return false;
789    
790        // supress redundant markers by detecting when we're inlining
791        // one Uninterruptible method into another one.
792        for (InlineSequence p = inlineSequence.getCaller(); p != null; p = p.getCaller()) {
793          if (!p.getMethod().isInterruptible()) return false;
794        }
795    
796        return true;
797      }
798    
799      /**
800       * Make sure, the generation context is still in sync with the IR, even if we applied some
801       * optimizations. This method should be called before hir2lir conversions
802       * which might trigger inlining.
803       */
804      public void resync() {
805        //make sure the _ncGuards contain no dangling mappings
806        resync_ncGuards();
807      }
808    
809      /**
810       * This method makes sure that _ncGuard only maps to registers that
811       * are actually in the IRs register pool.
812       */
813      private void resync_ncGuards() {
814        HashSet<Register> regPool = new HashSet<Register>();
815    
816        for (Register r = temps.getFirstSymbolicRegister(); r != null; r = r.getNext()) {
817          regPool.add(r);
818        }
819    
820        Iterator<Map.Entry<Register, RegisterOperand>> i = _ncGuards.entrySet().iterator();
821        while (i.hasNext()) {
822          Map.Entry<Register, RegisterOperand> entry = i.next();
823          if (!(regPool.contains(entry.getValue()))) i.remove();
824        }
825      }
826    
827      /**
828       * Kill ncGuards, so we do not use outdated mappings unintendedly later on
829       */
830      public void close() {
831        _ncGuards = null;
832      }
833    
834    }
835