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 */
013package org.jikesrvm.compilers.opt.bc2ir;
014
015import static org.jikesrvm.compilers.opt.driver.OptConstants.EPILOGUE_BCI;
016import static org.jikesrvm.compilers.opt.driver.OptConstants.EPILOGUE_BLOCK_BCI;
017import static org.jikesrvm.compilers.opt.driver.OptConstants.PROLOGUE_BCI;
018import static org.jikesrvm.compilers.opt.driver.OptConstants.PROLOGUE_BLOCK_BCI;
019import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
020import static org.jikesrvm.compilers.opt.driver.OptConstants.SYNCHRONIZED_MONITORENTER_BCI;
021import static org.jikesrvm.compilers.opt.driver.OptConstants.SYNCHRONIZED_MONITOREXIT_BCI;
022import static org.jikesrvm.compilers.opt.driver.OptConstants.SYNTH_CATCH_BCI;
023import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
024import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
025import static org.jikesrvm.compilers.opt.ir.Operators.GET_CAUGHT_EXCEPTION;
026import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
027import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE;
028import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER;
029import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT;
030import static org.jikesrvm.compilers.opt.ir.Operators.OSR_BARRIER;
031import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
032import static org.jikesrvm.compilers.opt.ir.Operators.RETURN;
033import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_BEGIN;
034import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_END;
035import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR;
036
037import java.util.Enumeration;
038import java.util.HashMap;
039import java.util.HashSet;
040import java.util.Iterator;
041import java.util.LinkedHashMap;
042import java.util.Map;
043
044import org.jikesrvm.VM;
045import org.jikesrvm.classloader.NormalMethod;
046import org.jikesrvm.classloader.RVMMethod;
047import org.jikesrvm.classloader.RVMType;
048import org.jikesrvm.classloader.TypeReference;
049import org.jikesrvm.compilers.baseline.BranchProfile;
050import org.jikesrvm.compilers.baseline.BranchProfiles;
051import org.jikesrvm.compilers.baseline.ConditionalBranchProfile;
052import org.jikesrvm.compilers.baseline.EdgeCounts;
053import org.jikesrvm.compilers.baseline.SwitchBranchProfile;
054import org.jikesrvm.compilers.common.CompiledMethod;
055import org.jikesrvm.compilers.opt.ClassLoaderProxy;
056import org.jikesrvm.compilers.opt.OptOptions;
057import org.jikesrvm.compilers.opt.OptimizingCompilerException;
058import org.jikesrvm.compilers.opt.inlining.InlineOracle;
059import org.jikesrvm.compilers.opt.inlining.InlineSequence;
060import org.jikesrvm.compilers.opt.ir.BasicBlock;
061import org.jikesrvm.compilers.opt.ir.Call;
062import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
063import org.jikesrvm.compilers.opt.ir.Empty;
064import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
065import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag;
066import org.jikesrvm.compilers.opt.ir.GenericRegisterPool;
067import org.jikesrvm.compilers.opt.ir.IRTools;
068import org.jikesrvm.compilers.opt.ir.Instruction;
069import org.jikesrvm.compilers.opt.ir.MonitorOp;
070import org.jikesrvm.compilers.opt.ir.Move;
071import org.jikesrvm.compilers.opt.ir.Nullary;
072import org.jikesrvm.compilers.opt.ir.Prologue;
073import org.jikesrvm.compilers.opt.ir.Register;
074import org.jikesrvm.compilers.opt.ir.Return;
075import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
076import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
077import org.jikesrvm.compilers.opt.ir.operand.ClassConstantOperand;
078import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
079import org.jikesrvm.compilers.opt.ir.operand.Operand;
080import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
081import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
082import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
083import org.jikesrvm.runtime.Entrypoints;
084import org.jikesrvm.runtime.Statics;
085import org.vmmagic.unboxed.Offset;
086
087/**
088 * Defines the context in which BC2IR will abstractly interpret
089 * a method's bytecodes and populate targetIR with instructions.
090 *
091 **/
092public final class GenerationContext {
093
094  //////////
095  // These fields are used to communicate information from its
096  // caller to BC2IR
097  //////////
098
099  /**
100   * The parent of this context is the context that the method
101   * {@link #createChildContext(ExceptionHandlerBasicBlockBag, NormalMethod, Instruction)}
102   * was called upon in order to create this context. This field is {@code null}
103   * if this context is the outermost one.
104   */
105  private GenerationContext parent;
106
107  /**
108   * The compiled method assigned for this compilation of original_method
109   */
110  private CompiledMethod original_cm;
111
112  /**
113   * The method to be generated
114   */
115  private NormalMethod method;
116
117  /**
118   * The BranchProfile data for method, if available
119   */
120  private BranchProfiles branchProfiles;
121
122  /**
123   * The options to control the generation
124   */
125  private OptOptions options;
126
127  /**
128   * The CFG object into which instructions should be generated.
129   */
130  private ControlFlowGraph cfg;
131
132  /**
133   * The register pool to be used during generation
134   */
135  private GenericRegisterPool temps;
136
137  /**
138   * The parameters which BC2IR should use to seed the local state
139   * for the entry basic block.
140   */
141  private Operand[] arguments;
142
143  /**
144   * The basic block into which BC2IR's caller will generate a "prologue."
145   * BC2IR will add a CFG edge from prologue to the block containing the
146   * instructions generated for bytecode 0, but it is its caller's
147   * responsibility to populate the prologue with instructions.
148   * All blocks generated by BC2IR will be injected by BC2IR.doFinalPass
149   * immediately
150   * after prologue in the code ordering
151   * (ie prologue can assume it will fallthrough
152   * to the first basic block in the ir generated for method.
153   */
154  private BasicBlock prologue;
155
156  /**
157   * The basic block into which BC2IR's caller will generate an epilogue.
158   * BC2IR will add CFG edges to this node, but it is its caller's
159   * responsibility to populate it with instructions.
160   * NOTE: After IR is generated one of two conditions will hold:
161   * <ul>
162   * <li> epilogue == cfg.lastInCodeOrder():  (if it is to be inlined,
163   *                                           then the generated cfg
164   *                                           is expecting to "fallthrough"
165   *                                           to the next bblock)
166   * <li> epilogue == null:  implies that there is no "normal" exit from
167   *                         the callee (all exits via throw)
168   * </ul>
169   * NOTE: BC2IR assumes that epilogue is a single basic block
170   *       (i.e. it has no out edges)
171   */
172  private BasicBlock epilogue;
173
174  /**
175   * The exit node of the outermost CFG
176   * (used by BC2IR for not-definitely caught athrows and by OSR_Yieldpoints)
177   */
178  private BasicBlock exit;
179
180  /**
181   * A catch, unlock, and rethrow exception handler used for
182   * synchronized methods.
183   */
184  private BasicBlock unlockAndRethrow;
185
186  /**
187   * The Register to which BC2IR should assign the return value(s)
188   * of the method. It will be null when the method has a void return.
189   */
190  private Register resultReg;
191
192  /**
193   * The enclosing exception handlers (null if there are none).
194   */
195  private ExceptionHandlerBasicBlockBag enclosingHandlers;
196
197  /**
198   * Inlining context of the method to be generated
199   */
200  private InlineSequence inlineSequence;
201
202  /**
203   * The InlineOracle to be consulted for all inlining decisions during
204   * the generation of this IR.
205   */
206  private InlineOracle inlinePlan;
207
208  //////////
209  // These fields are used to communicate information from BC2IR to its caller
210  //////////
211  /**
212   * Did BC2IR generate a reachable exception handler while generating
213   * the IR for this method
214   */
215  private boolean generatedExceptionHandlers;
216
217  /**
218   * Did BC2IR encounter a magic that requires us to allocate a stack frame?
219   */
220  private boolean allocFrame;
221
222  /**
223   * Used to communicate the meet of the return values back to the caller
224   * Mainly useful when BC2IR is doing inlining....allows the caller
225   * BC2IR object
226   * to exploit knowledge the callee BC2IR object had about the result.
227   */
228  private Operand result;
229
230  /////////
231  // Information for on-stack replacement barriers
232  /////////
233
234  /**
235   * Mapping of instructions to on-stack replacement (OSR) barriers. The
236   * key is always a call instruction or an OSR yieldpoint instruction,
237   * the value is an OSR barrier instruction.
238   * <p>
239   * Child contexts save this information in their outermost parent
240   * context, so this field will be {@code null} for child contexts.
241   */
242  private Map<Instruction, Instruction> instToOSRBarriers;
243
244  //////////
245  // Main public methods
246  /////////
247
248  /**
249   * Use this constructor to create an outermost (non-inlined)
250   * GenerationContext.
251   *
252   * @param meth The NormalMethod whose IR will be generated
253   * @param params The known types of the parameters to the method. For method specialization.
254   * @param cm   The compiled method id to be used for this compilation
255   * @param opts The Options to be used for the generation
256   * @param ip   The InlineOracle to be used for the generation
257   */
258  GenerationContext(NormalMethod meth, TypeReference[] params, CompiledMethod cm, OptOptions opts, InlineOracle ip) {
259    original_cm = cm;
260    method = meth;
261    if (opts.frequencyCounters() || opts.inverseFrequencyCounters()) {
262      branchProfiles = EdgeCounts.getBranchProfiles(meth);
263    }
264    options = opts;
265    inlinePlan = ip;
266    inlineSequence = new InlineSequence(meth);
267
268    // Create the CFG. Initially contains prologue, epilogue, and exit.
269    cfg = new ControlFlowGraph(0);
270    prologue = new BasicBlock(PROLOGUE_BLOCK_BCI, inlineSequence, cfg);
271    epilogue = new BasicBlock(EPILOGUE_BLOCK_BCI, inlineSequence, cfg);
272    cfg.addLastInCodeOrder(prologue);
273    cfg.addLastInCodeOrder(epilogue);
274    exit = cfg.exit();
275    epilogue.insertOut(exit);
276
277    // Create register pool, initialize arguments, resultReg.
278    if (VM.BuildForIA32) {
279      temps = new org.jikesrvm.compilers.opt.ir.ia32.RegisterPool(meth);
280    } else {
281      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
282      temps = new org.jikesrvm.compilers.opt.ir.ppc.RegisterPool(meth);
283    }
284    _ncGuards = new HashMap<Register, RegisterOperand>();
285    initLocalPool();
286    TypeReference[] definedParams = meth.getParameterTypes();
287    if (params == null) params = definedParams;
288    int numParams = params.length;
289    int argIdx = 0;
290    int localNum = 0;
291    arguments = new Operand[method.isStatic() ? numParams : numParams + 1];
292    // Insert IR_PROLOGUE instruction.  Loop below will fill in its operands
293    Instruction prologueInstr = Prologue.create(IR_PROLOGUE, arguments.length);
294    appendInstruction(prologue, prologueInstr, PROLOGUE_BCI);
295
296    if (!method.isStatic()) {
297      TypeReference thisType = meth.getDeclaringClass().getTypeRef();
298      RegisterOperand thisOp = makeLocal(localNum, thisType);
299      // The this param of a virtual method is by definition non null
300      RegisterOperand guard = makeNullCheckGuard(thisOp.getRegister());
301      BC2IR.setGuardForRegOp(thisOp, guard);
302      appendInstruction(prologue, Move.create(GUARD_MOVE, guard.copyRO(), new TrueGuardOperand()), PROLOGUE_BCI);
303      thisOp.setDeclaredType();
304      thisOp.setExtant();
305      if (method.getDeclaringClass().isFinal()) {
306        thisOp.setPreciseType();
307      }
308      arguments[0] = thisOp;
309      Prologue.setFormal(prologueInstr, 0, thisOp.copyU2D());
310      argIdx++;
311      localNum++;
312    }
313    for (int paramIdx = 0; paramIdx < numParams; paramIdx++) {
314      TypeReference argType = params[paramIdx];
315      RegisterOperand argOp = makeLocal(localNum, argType);
316      argOp.setDeclaredType();
317      if (argType.isClassType()) {
318        argOp.setExtant();
319      }
320      arguments[argIdx] = argOp;
321      Prologue.setFormal(prologueInstr, argIdx, argOp.copyU2D());
322      argIdx++;
323      localNum++;
324      if (argType.isLongType() || argType.isDoubleType()) {
325        localNum++; // longs & doubles take two words of local space
326      }
327    }
328    TypeReference returnType = meth.getReturnType();
329    if (returnType != TypeReference.Void) {
330      resultReg = temps.makeTemp(returnType).getRegister();
331    }
332
333    enclosingHandlers = null;
334    instToOSRBarriers = new LinkedHashMap<Instruction, Instruction>();
335
336    completePrologue(true);
337    completeEpilogue(true);
338    completeExceptionHandlers(true);
339  }
340
341  /**
342   * Creates a child generation context from this context
343   * and callerBB to generate IR for callsite.
344   *
345   * @param ebag the enclosing exception handlers (null if none)
346   * @param callee the callee method to be inlined
347   *        (may _not_ be equal to Call.getMethod(callSite).method)
348   * @param callSite the Call instruction to be inlined.
349   * @return the child context
350   */
351  public GenerationContext createChildContext(ExceptionHandlerBasicBlockBag ebag,
352                                                  NormalMethod callee, Instruction callSite) {
353    // Note: In this method, use "this" explicitly to refer to parent fields in order
354    // to avoid confusing parent/child fields.
355
356    GenerationContext child = new GenerationContext();
357    child.method = callee;
358    if (this.options.frequencyCounters() || this.options.inverseFrequencyCounters()) {
359      child.branchProfiles = EdgeCounts.getBranchProfiles(callee);
360    }
361    child.parent = this;
362    child.original_cm = this.original_cm;
363
364    // Some state gets directly copied to the child
365    child.options = this.options;
366    child.temps = this.temps;
367    child._ncGuards = this._ncGuards;
368    child.exit = this.exit;
369    child.inlinePlan = this.inlinePlan;
370
371    // Now inherit state based on callSite
372    child.inlineSequence = new InlineSequence(child.method, callSite.position, callSite);
373    child.enclosingHandlers = ebag;
374    child.arguments = new Operand[Call.getNumberOfParams(callSite)];
375    for (int i = 0; i < child.arguments.length; i++) {
376      child.arguments[i] = Call.getParam(callSite, i).copy(); // copy instead
377      // of clearing in case inlining aborts.
378    }
379    if (Call.hasResult(callSite)) {
380      child.resultReg = Call.getResult(callSite).copyD2D().getRegister();
381      child.resultReg.setSpansBasicBlock(); // it will...
382    }
383
384    // Initialize the child CFG, prologue, and epilogue blocks
385    child.cfg = new ControlFlowGraph(this.cfg.numberOfNodes());
386    child.prologue = new BasicBlock(PROLOGUE_BCI, child.inlineSequence, child.cfg);
387    child.prologue.exceptionHandlers = ebag;
388    child.epilogue = new BasicBlock(EPILOGUE_BCI, child.inlineSequence, child.cfg);
389    child.epilogue.exceptionHandlers = ebag;
390    child.cfg.addLastInCodeOrder(child.prologue);
391    child.cfg.addLastInCodeOrder(child.epilogue);
392
393    // Set up the local pool
394    child.initLocalPool();
395
396    // Insert moves from child.arguments to child's locals in prologue
397    TypeReference[] params = child.method.getParameterTypes();
398    int numParams = params.length;
399    int argIdx = 0;
400    int localNum = 0;
401    if (!child.method.isStatic()) {
402      Operand receiver = child.arguments[argIdx];
403      argIdx++;
404      RegisterOperand local = null;
405      if (receiver.isRegister()) {
406        RegisterOperand objPtr = receiver.asRegister();
407        if (ClassLoaderProxy.includesType(child.method.getDeclaringClass().getTypeRef(), objPtr.getType()) != YES) {
408          // narrow type of actual to match formal static type implied by method
409          objPtr.clearPreciseType(); // Can be precise but not assignable if enough classes aren't loaded
410          objPtr.setDeclaredType();
411          objPtr.setType(child.method.getDeclaringClass().getTypeRef());
412        }
413        local = child.makeLocal(localNum, objPtr);
414        localNum++;
415        child.arguments[0] = local; // Avoid confusion in BC2IR of callee
416        // when objPtr is a local in the caller.
417      } else if (receiver.isConstant()) {
418        local = child.makeLocal(localNum, receiver.getType());
419        localNum++;
420        local.setPreciseType();
421        // Constants trivially non-null
422        RegisterOperand guard = child.makeNullCheckGuard(local.getRegister());
423        BC2IR.setGuardForRegOp(local, guard);
424        child.prologue.appendInstruction(Move.create(GUARD_MOVE, guard.copyRO(), new TrueGuardOperand()));
425      } else {
426        OptimizingCompilerException.UNREACHABLE("Unexpected receiver operand");
427      }
428      Instruction s = Move.create(REF_MOVE, local, receiver);
429      s.bcIndex = PROLOGUE_BCI;
430      s.position = callSite.position;
431      child.prologue.appendInstruction(s);
432    }
433    for (int paramIdx = 0; paramIdx < numParams; paramIdx++, argIdx++) {
434      TypeReference argType = params[paramIdx];
435      RegisterOperand formal;
436      Operand actual = child.arguments[argIdx];
437      if (actual.isRegister()) {
438        RegisterOperand rActual = actual.asRegister();
439        if (ClassLoaderProxy.includesType(argType, rActual.getType()) != YES) {
440          // narrow type of actual to match formal static type implied by method
441          rActual.clearPreciseType(); // Can be precise but not
442          // assignable if enough classes aren't loaded
443          rActual.setDeclaredType();
444          rActual.setType(argType);
445        }
446        formal = child.makeLocal(localNum, rActual);
447        localNum++;
448        child.arguments[argIdx] = formal;  // Avoid confusion in BC2IR of
449        // callee when arg is a local in the caller.
450      } else {
451        formal = child.makeLocal(localNum, argType);
452        localNum++;
453      }
454      Instruction s = Move.create(IRTools.getMoveOp(argType), formal, actual);
455      s.bcIndex = PROLOGUE_BCI;
456      s.position = callSite.position;
457      child.prologue.appendInstruction(s);
458      if (argType.isLongType() || argType.isDoubleType()) {
459        localNum++; // longs and doubles take two local words
460      }
461    }
462
463    child.completePrologue(false);
464    child.completeEpilogue(false);
465    child.completeExceptionHandlers(false);
466
467    return child;
468  }
469
470  /**
471   * Only for internal use by Inliner (when inlining multiple targets)
472   * This is probably not the prettiest way to handle this, but it requires
473   * no changes to BC2IR's &amp; Inliner's high level control logic.
474   *
475   * @param parent the parent GC
476   * @param ebag the enclosing exception handlers (null if none)
477   * @return the synthetic context
478   */
479  public static GenerationContext createSynthetic(GenerationContext parent, ExceptionHandlerBasicBlockBag ebag) {
480    // Create the CFG. Initially contains prologue and epilogue
481    GenerationContext child = new GenerationContext();
482
483    child.cfg = new ControlFlowGraph(-100000);
484
485    // It may be wrong to use the parent inline sequence as the
486    // position here, but it seems to work out.  This is a synthetic
487    // context that is just used as a container for multiple inlined
488    // targets, so in the cases that I've observed where the prologue
489    // and epilogue don't disappear, it was correct to have the
490    // parent's position. -- Matt
491    child.prologue = new BasicBlock(PROLOGUE_BCI, parent.inlineSequence, parent.cfg);
492    child.prologue.exceptionHandlers = ebag;
493    child.epilogue = new BasicBlock(EPILOGUE_BCI, parent.inlineSequence, parent.cfg);
494    child.epilogue.exceptionHandlers = ebag;
495    child.cfg.addLastInCodeOrder(child.prologue);
496    child.cfg.addLastInCodeOrder(child.epilogue);
497
498    // All other fields are intentionally left null.
499    // We are only really using this context to transfer a synthetic CFG
500    // from the low-level Inliner.execute back to its caller.
501    // TODO: Rewrite GenerationContext to be a subclass of a root
502    // class that is just a CFG wrapper.  Then, have an instance of this
503    // new parent
504    // class be the return value for the main entrypoints in Inliner
505    // and create an instance of the root class instead of GC when
506    // inlining multiple targets.
507
508    return child;
509  }
510
511  /**
512   * Transfers the state from this context back to its direct
513   * parent.
514   *
515   * @throws IllegalStateException when this context does not have a parent
516   */
517  public void transferStateToParent() {
518    if (parent == null) {
519      throw new IllegalStateException("This method may only be called on contexts that have a parent.");
520    }
521
522    parent.cfg.setNumberOfNodes(this.cfg.numberOfNodes());
523    if (this.generatedExceptionHandlers) {
524      parent.generatedExceptionHandlers = true;
525    }
526    if (this.allocFrame) {
527      parent.allocFrame = true;
528    }
529  }
530
531  ///////////
532  // Local variables
533  ///////////
534
535  // The registers to use for various types of locals.
536  // Note that "int" really means 32-bit gpr.
537  private Register[] intLocals;
538  private Register[] addressLocals;
539  private Register[] floatLocals;
540  private Register[] longLocals;
541  private Register[] doubleLocals;
542
543  private void initLocalPool() {
544    int numLocals = method.getLocalWords();
545    intLocals = new Register[numLocals];
546    addressLocals = new Register[numLocals];
547    floatLocals = new Register[numLocals];
548    longLocals = new Register[numLocals];
549    doubleLocals = new Register[numLocals];
550  }
551
552  private Register[] getPool(TypeReference type) {
553    if (type == TypeReference.Float) {
554      return floatLocals;
555    } else if (type == TypeReference.Long) {
556      return longLocals;
557    } else if (type == TypeReference.Double) {
558      return doubleLocals;
559    } else if (type.isReferenceType() || type.isWordLikeType()) {
560      return addressLocals;
561    } else {
562      return intLocals;
563    }
564  }
565
566  /**
567   * Returns the Register used to for local i of TypeReference type.
568   *
569   * @param i local number
570   * @param type local's type
571   * @return the Register for the local
572   */
573  Register localReg(int i, TypeReference type) {
574    Register[] pool = getPool(type);
575    if (pool[i] == null) {
576      pool[i] = temps.getReg(type);
577      pool[i].setLocal();
578    }
579    return pool[i];
580  }
581
582  /**
583   * @return {@code true} if and only if null checks should be generated
584   */
585  boolean noNullChecks() {
586    return method.hasNoNullCheckAnnotation();
587  }
588
589  /**
590   * @return {@code true} if and only if bounds checks should be generated
591   */
592  boolean noBoundsChecks() {
593    return method.hasNoBoundsCheckAnnotation();
594  }
595
596  /**
597   * @return {@code true} if and only if checkstore checks should be generated
598   */
599  boolean noCheckStoreChecks() {
600    return method.hasNoCheckStoreAnnotation();
601  }
602
603  /**
604   * Makes a register operand that refers to the given local variable number
605   * and has the given type.
606   *
607   * @param i local variable number
608   * @param type desired data type
609   * @return the newly created register operand
610   */
611  RegisterOperand makeLocal(int i, TypeReference type) {
612    return new RegisterOperand(localReg(i, type), type);
613  }
614
615  /**
616   * Makes a register operand that refers to the given local variable number,
617   * and inherits its properties (type, flags) from props
618   *
619   * @param i local variable number
620   * @param props RegisterOperand to inherit flags from
621   * @return the newly created register operand
622   */
623  RegisterOperand makeLocal(int i, RegisterOperand props) {
624    RegisterOperand local = makeLocal(i, props.getType());
625    local.setInheritableFlags(props);
626    BC2IR.setGuardForRegOp(local, BC2IR.copyGuardFromOperand(props));
627    return local;
628  }
629
630  /**
631   * Gets the local number for a given register
632   * @param reg the register whose local number should be found out
633   * @param type the register's type
634   * @return the local number of -1 if not found
635   */
636  int getLocalNumberFor(Register reg, TypeReference type) {
637    Register[] pool = getPool(type);
638    for (int i = 0; i < pool.length; i++) {
639      if (pool[i] == reg) return i;
640    }
641    return -1;
642  }
643
644  /**
645   * Is the operand a particular bytecode local?
646   *
647   * @param op the operand to check
648   * @param i the local's index
649   * @param type the local's type
650   *
651   * @return {@code true} if and only if the given operand is a
652   *  an operand for the given bytecode local
653   */
654  boolean isLocal(Operand op, int i, TypeReference type) {
655    if (op instanceof RegisterOperand) {
656      if (getPool(type)[i] == ((RegisterOperand) op).getRegister()) return true;
657    }
658    return false;
659  }
660
661  ///////////
662  // Validation operands (guards)
663  ///////////
664
665  // For each register, we always use the same register as a validation operand.
666  // This helps us avoid needlessly losing information at CFG join points.
667  private HashMap<Register, RegisterOperand> _ncGuards;
668
669  /**
670   * Makes a register operand to use as a null check guard for the
671   * given register.
672   *
673   * @param ref the register to check for null
674   * @return the guard operand
675   */
676  RegisterOperand makeNullCheckGuard(Register ref) {
677    RegisterOperand guard = _ncGuards.get(ref);
678    if (guard == null) {
679      guard = temps.makeTempValidation();
680      _ncGuards.put(ref, guard.copyRO());
681    } else {
682      guard = guard.copyRO();
683    }
684    return guard;
685  }
686
687  ///////////
688  // Profile data
689  ///////////
690  BranchProfileOperand getConditionalBranchProfileOperand(int bcIndex, boolean backwards) {
691    float prob;
692    BranchProfile bp;
693    if (branchProfiles != null && ((bp = branchProfiles.getEntry(bcIndex)) != null)) {
694      prob = ((ConditionalBranchProfile) bp).getTakenProbability();
695    } else {
696      if (branchProfiles != null) {
697        VM.sysWrite("Warning: conditional branch profile entry not found");
698      }
699      if (backwards) {
700        prob = 0.9f;
701      } else {
702        prob = 0.5f;
703      }
704    }
705    // experimental option: flip the probability to see how bad things would be if
706    // we were completely wrong.
707    if (options.inverseFrequencyCounters()) {
708      prob = 1f - prob;
709    }
710    return new BranchProfileOperand(prob);
711  }
712
713  SwitchBranchProfile getSwitchProfile(int bcIndex) {
714    if (branchProfiles != null) {
715      return (SwitchBranchProfile) branchProfiles.getEntry(bcIndex);
716    } else {
717      return null;
718    }
719  }
720
721  ///////////
722  // Implementation
723  ///////////
724
725  /**
726   * for internal use only (in createInlinedContext)
727   */
728  private GenerationContext() {}
729
730  /**
731   * Fills in the rest of the method prologue.
732   * PRECONDITION: arguments &amp; temps have been setup/initialized.
733   *
734   * @param isOutermost is this the outermost context (i.e. not an inlined context)
735   */
736  private void completePrologue(boolean isOutermost) {
737    // Deal with Uninteruptible code.
738    if (!isOutermost && requiresUnintMarker()) {
739      Instruction s = Empty.create(UNINT_BEGIN);
740      appendInstruction(prologue, s, PROLOGUE_BCI);
741    }
742
743    // Deal with implicit monitorenter for synchronized methods.
744    // When working with the class writer do not expand static
745    // synchronization headers as there is no easy way to get at
746    // class object
747
748    // OSR: if this is a specialized method, no monitor enter at the beginging
749    // since it's the second time reenter
750    if (method.isForOsrSpecialization()) {
751      // do nothing
752    } else if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
753      Operand lockObject = getLockObject();
754      Instruction s = MonitorOp.create(MONITORENTER, lockObject, new TrueGuardOperand());
755      appendInstruction(prologue, s, SYNCHRONIZED_MONITORENTER_BCI);
756    }
757  }
758
759  /**
760   * Fill in the rest of the method epilogue.
761   * PRECONDITION: arguments &amp; temps have been setup/initialized.
762   *
763   * @param isOutermost is this the outermost context (i.e. not an inlined context)
764   */
765  private void completeEpilogue(boolean isOutermost) {
766    // Deal with implicit monitorexit for synchronized methods.
767    if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
768      Operand lockObject = getLockObject();
769      Instruction s = MonitorOp.create(MONITOREXIT, lockObject, new TrueGuardOperand());
770      appendInstruction(epilogue, s, SYNCHRONIZED_MONITOREXIT_BCI);
771    }
772
773    // Deal with Uninterruptible code.
774    if (!isOutermost && requiresUnintMarker()) {
775      Instruction s = Empty.create(UNINT_END);
776      appendInstruction(epilogue, s, EPILOGUE_BCI);
777    }
778
779    if (isOutermost) {
780      TypeReference returnType = method.getReturnType();
781      Operand retVal = returnType.isVoidType() ? null : new RegisterOperand(resultReg, returnType);
782      Instruction s = Return.create(RETURN, retVal);
783      appendInstruction(epilogue, s, EPILOGUE_BCI);
784    }
785  }
786
787  /**
788   * If the method is synchronized then we wrap it in a
789   * synthetic exception handler that unlocks &amp; rethrows
790   * PRECONDITION: cfg, arguments &amp; temps have been setup/initialized.
791   *
792   * @param isOutermost is this the outermost context (i.e. not an inlined context)
793   */
794  private void completeExceptionHandlers(boolean isOutermost) {
795    if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
796      ExceptionHandlerBasicBlock rethrow =
797          new ExceptionHandlerBasicBlock(SYNTH_CATCH_BCI,
798                                             inlineSequence,
799                                             new TypeOperand(RVMType.JavaLangThrowableType),
800                                             cfg);
801      rethrow.exceptionHandlers = enclosingHandlers;
802      RegisterOperand ceo = temps.makeTemp(TypeReference.JavaLangThrowable);
803      Instruction s = Nullary.create(GET_CAUGHT_EXCEPTION, ceo);
804      appendInstruction(rethrow, s, SYNTH_CATCH_BCI);
805      Operand lockObject = getLockObject();
806
807      RVMMethod target = Entrypoints.unlockAndThrowMethod;
808      MethodOperand methodOp = MethodOperand.STATIC(target);
809      methodOp.setIsNonReturningCall(true); // Used to keep cfg correct
810      s =
811          Call.create2(CALL,
812                       null,
813                       new AddressConstantOperand(target.getOffset()),
814                       methodOp,
815                       lockObject,
816                       ceo.copyD2U());
817      appendInstruction(rethrow, s, RUNTIME_SERVICES_BCI);
818
819      cfg.insertBeforeInCodeOrder(epilogue, rethrow);
820
821      // May be overly conservative
822      // (if enclosed by another catch of Throwable...)
823      if (enclosingHandlers != null) {
824        for (Enumeration<BasicBlock> e = enclosingHandlers.enumerator(); e.hasMoreElements();) {
825          BasicBlock eh = e.nextElement();
826          rethrow.insertOut(eh);
827        }
828      }
829      rethrow.setCanThrowExceptions();
830      rethrow.setMayThrowUncaughtException();
831      rethrow.insertOut(exit);
832
833      // save a reference to this block so we can discard it if unused.
834      unlockAndRethrow = rethrow;
835
836      ExceptionHandlerBasicBlock[] sh = new ExceptionHandlerBasicBlock[1];
837      sh[0] = rethrow;
838      enclosingHandlers = new ExceptionHandlerBasicBlockBag(sh, enclosingHandlers);
839      generatedExceptionHandlers = true;
840    }
841  }
842
843  /**
844   * Get the object for locking for synchronized methods.
845   * either the class object or the this ptr.
846   *
847   * @return an operand for the appropriate lock object
848   */
849  private Operand getLockObject() {
850    if (method.isStatic()) {
851      Class<?> klass = method.getDeclaringClass().getClassForType();
852      Offset offs = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(klass));
853      return new ClassConstantOperand(klass, offs);
854    } else {
855      return makeLocal(0, arguments[0].getType());
856    }
857  }
858
859  private void appendInstruction(BasicBlock b, Instruction s, int bcIndex) {
860    s.position = inlineSequence;
861    s.bcIndex = bcIndex;
862    b.appendInstruction(s);
863  }
864
865  private boolean requiresUnintMarker() {
866    if (method.isInterruptible()) return false;
867
868    // supress redundant markers by detecting when we're inlining
869    // one Uninterruptible method into another one.
870    for (InlineSequence p = inlineSequence.getCaller(); p != null; p = p.getCaller()) {
871      if (!p.getMethod().isInterruptible()) return false;
872    }
873
874    return true;
875  }
876
877  /**
878   * Make sure, the generation context is still in sync with the IR, even if we applied some
879   * optimizations. This method should be called before hir2lir conversions
880   * which might trigger inlining.
881   */
882  public void resync() {
883    //make sure the _ncGuards contain no dangling mappings
884    resync_ncGuards();
885  }
886
887  /**
888   * This method makes sure that _ncGuard only maps to registers that
889   * are actually in the IRs register pool.
890   */
891  private void resync_ncGuards() {
892    HashSet<Register> regPool = new HashSet<Register>();
893
894    for (Register r = temps.getFirstSymbolicRegister(); r != null; r = r.getNext()) {
895      regPool.add(r);
896    }
897
898    Iterator<Map.Entry<Register, RegisterOperand>> i = _ncGuards.entrySet().iterator();
899    while (i.hasNext()) {
900      Map.Entry<Register, RegisterOperand> entry = i.next();
901      if (!(regPool.contains(entry.getKey()))) i.remove();
902    }
903  }
904
905  /**
906   * Kill ncGuards, so we do not use outdated mappings unintendedly later on
907   */
908  public void close() {
909    _ncGuards = null;
910  }
911
912  /**
913   * Is this method selected for debugging with method to print?<p>
914   *
915   * A method is selected if the name of the original method
916   * is contained in the set of methods to print. This ensures that debug
917   * output is not omitted during generation of IR for methods
918   * that are inlined into a method that is supposed to be printed.
919   *
920   * @return {@code true} if and only if this method is selected for
921   *  debugging as described above
922   *
923   * @see BC2IR#DBG_SELECTIVE
924   */
925  boolean methodIsSelectedForDebuggingWithMethodToPrint() {
926    boolean originalMethodSelected = options.hasMETHOD_TO_PRINT() &&
927        options.fuzzyMatchMETHOD_TO_PRINT(getOriginalMethod().toString());
928    return originalMethodSelected;
929  }
930
931  /**
932   * Forces allocation of a stack frame for this method.
933   */
934  public void forceFrameAllocation() {
935    this.allocFrame = true;
936  }
937
938  public boolean requiresStackFrame() {
939    return allocFrame;
940  }
941
942  public boolean generatedExceptionHandlers() {
943    return generatedExceptionHandlers;
944  }
945
946  public void markExceptionHandlersAsGenerated() {
947    this.generatedExceptionHandlers = true;
948  }
949
950  public void saveOSRBarrierForInst(Instruction osrBarrier,
951      Instruction inst) {
952    if (VM.VerifyAssertions) {
953      VM._assert(osrBarrier.operator() == OSR_BARRIER,
954          "Unexpected operator for OSR barrier");
955      boolean sourceInstOk = inst.operator() == CALL ||
956          inst.operator() == YIELDPOINT_OSR;
957      VM._assert(sourceInstOk,
958          "Unexpected operator for instruction that has a barrier");
959    }
960
961    getOutermostContext().instToOSRBarriers.put(inst, osrBarrier);
962  }
963
964  public Instruction getOSRBarrierFromInst(Instruction inst) {
965    return getOutermostContext().instToOSRBarriers.get(inst);
966  }
967
968  public void discardOSRBarrierInformation() {
969    instToOSRBarriers = null;
970  }
971
972
973  ///////////
974  // Getters and setters that need to be public
975  ///////////
976
977  public NormalMethod getMethod() {
978    return method;
979  }
980
981  public OptOptions getOptions() {
982    return options;
983  }
984
985  public ControlFlowGraph getCfg() {
986    return cfg;
987  }
988
989  public GenericRegisterPool getTemps() {
990    return temps;
991  }
992
993  public BasicBlock getPrologue() {
994    return prologue;
995  }
996
997  public BasicBlock getEpilogue() {
998    return epilogue;
999  }
1000
1001  public void setEpilogue(BasicBlock epilogue) {
1002    this.epilogue = epilogue;
1003  }
1004
1005  public BasicBlock getExit() {
1006    return exit;
1007  }
1008
1009  public InlineSequence getInlineSequence() {
1010    return inlineSequence;
1011  }
1012
1013  public Operand getResult() {
1014    return result;
1015  }
1016
1017  public void setResult(Operand result) {
1018    this.result = result;
1019  }
1020
1021  ///////////
1022  // Getters and setters that are only used by the initial transformation to IR
1023  ///////////
1024
1025  /**
1026   * @return the original method (root of the calling context tree)
1027   */
1028  NormalMethod getOriginalMethod() {
1029    return getOutermostContext().method;
1030  }
1031
1032  CompiledMethod getOriginalCompiledMethod() {
1033    return original_cm;
1034  }
1035
1036  BranchProfiles getBranchProfiles() {
1037    return branchProfiles;
1038  }
1039
1040  Operand[] getArguments() {
1041    return arguments;
1042  }
1043
1044  BasicBlock getUnlockAndRethrow() {
1045    return unlockAndRethrow;
1046  }
1047
1048  Register getResultReg() {
1049    return resultReg;
1050  }
1051
1052  ExceptionHandlerBasicBlockBag getEnclosingHandlers() {
1053    return enclosingHandlers;
1054  }
1055
1056  InlineOracle getInlinePlan() {
1057    return inlinePlan;
1058  }
1059
1060  private GenerationContext getOutermostContext() {
1061    GenerationContext outermostContext = this;
1062    while (outermostContext.parent != null) {
1063      outermostContext = outermostContext.parent;
1064    }
1065    return outermostContext;
1066  }
1067
1068}
1069