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.hir2lir;
014    
015    import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_ADDRESS;
016    import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_INT;
017    import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
018    import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
019    import static org.jikesrvm.compilers.opt.ir.Operators.BOUNDS_CHECK_opcode;
020    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode;
021    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
022    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD;
023    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE;
024    import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
025    import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
026    import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_NOTNULL_opcode;
027    import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_UNRESOLVED_opcode;
028    import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_opcode;
029    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode;
030    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
031    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD;
032    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE;
033    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode;
034    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
035    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD;
036    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE;
037    import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
038    import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
039    import static org.jikesrvm.compilers.opt.ir.Operators.GET_CLASS_TIB;
040    import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB;
041    import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
042    import static org.jikesrvm.compilers.opt.ir.Operators.IG_CLASS_TEST_opcode;
043    import static org.jikesrvm.compilers.opt.ir.Operators.IG_METHOD_TEST_opcode;
044    import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_NOTNULL_opcode;
045    import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_UNRESOLVED_opcode;
046    import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_opcode;
047    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt;
048    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
049    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
050    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode;
051    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
052    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
053    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
054    import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
055    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
056    import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
057    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ZERO_CHECK_opcode;
058    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode;
059    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
060    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD;
061    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE;
062    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ZERO_CHECK_opcode;
063    import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH;
064    import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH_opcode;
065    import static org.jikesrvm.compilers.opt.ir.Operators.LOWTABLESWITCH;
066    import static org.jikesrvm.compilers.opt.ir.Operators.MUST_IMPLEMENT_INTERFACE_opcode;
067    import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode;
068    import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_opcode;
069    import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
070    import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
071    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
072    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
073    import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
074    import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD;
075    import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE;
076    import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE;
077    import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE_MEMBER_opcode;
078    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode;
079    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
080    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD;
081    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE;
082    import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
083    import static org.jikesrvm.compilers.opt.ir.Operators.TABLESWITCH_opcode;
084    import static org.jikesrvm.compilers.opt.ir.Operators.TRAP_IF;
085    import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode;
086    import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD;
087    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode;
088    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
089    import static org.jikesrvm.objectmodel.TIBLayoutConstants.NEEDS_DYNAMIC_LINK;
090    import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_INTERFACE_DISPATCH_TABLE_INDEX;
091    
092    import org.jikesrvm.VM;
093    import org.jikesrvm.adaptive.AosEntrypoints;
094    import org.jikesrvm.classloader.RVMClass;
095    import org.jikesrvm.classloader.RVMField;
096    import org.jikesrvm.classloader.InterfaceInvocation;
097    import org.jikesrvm.classloader.InterfaceMethodSignature;
098    import org.jikesrvm.classloader.RVMMethod;
099    import org.jikesrvm.classloader.RVMType;
100    import org.jikesrvm.classloader.TypeReference;
101    import org.jikesrvm.compilers.opt.OptOptions;
102    import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
103    import org.jikesrvm.compilers.opt.ir.ALoad;
104    import org.jikesrvm.compilers.opt.ir.AStore;
105    import org.jikesrvm.compilers.opt.ir.BasicBlock;
106    import org.jikesrvm.compilers.opt.ir.Binary;
107    import org.jikesrvm.compilers.opt.ir.BoundsCheck;
108    import org.jikesrvm.compilers.opt.ir.CacheOp;
109    import org.jikesrvm.compilers.opt.ir.Call;
110    import org.jikesrvm.compilers.opt.ir.GetField;
111    import org.jikesrvm.compilers.opt.ir.GetStatic;
112    import org.jikesrvm.compilers.opt.ir.Goto;
113    import org.jikesrvm.compilers.opt.ir.GuardedUnary;
114    import org.jikesrvm.compilers.opt.ir.IR;
115    import org.jikesrvm.compilers.opt.ir.IRTools;
116    import org.jikesrvm.compilers.opt.ir.IfCmp;
117    import org.jikesrvm.compilers.opt.ir.IfCmp2;
118    import org.jikesrvm.compilers.opt.ir.InlineGuard;
119    import org.jikesrvm.compilers.opt.ir.Instruction;
120    import org.jikesrvm.compilers.opt.ir.Load;
121    import org.jikesrvm.compilers.opt.ir.LookupSwitch;
122    import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
123    import org.jikesrvm.compilers.opt.ir.Operator;
124    import org.jikesrvm.compilers.opt.ir.PutField;
125    import org.jikesrvm.compilers.opt.ir.PutStatic;
126    import org.jikesrvm.compilers.opt.ir.Store;
127    import org.jikesrvm.compilers.opt.ir.TableSwitch;
128    import org.jikesrvm.compilers.opt.ir.TrapIf;
129    import org.jikesrvm.compilers.opt.ir.Unary;
130    import org.jikesrvm.compilers.opt.ir.ZeroCheck;
131    import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
132    import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
133    import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
134    import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
135    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
136    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
137    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
138    import org.jikesrvm.compilers.opt.ir.operand.Operand;
139    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
140    import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
141    import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
142    import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
143    import org.jikesrvm.compilers.opt.specialization.SpecializedMethod;
144    import org.jikesrvm.mm.mminterface.MemoryManagerConstants;
145    import org.jikesrvm.runtime.Entrypoints;
146    import org.jikesrvm.runtime.Magic;
147    import org.vmmagic.unboxed.Address;
148    import org.vmmagic.unboxed.Offset;
149    
150    /**
151     * Converts all remaining instructions with HIR-only operators into
152     * an equivalent sequence of LIR operators.
153     */
154    public abstract class ConvertToLowLevelIR extends IRTools {
155    
156      /**
157       * We have slightly different ideas of what the LIR should look like
158       * for IA32 and PowerPC.  The main difference is that for IA32
159       * instead of bending over backwards in BURS to rediscover array
160       * loads, (where we can use base + index*scale addressing modes),
161       * we'll leave array loads in the LIR.
162       */
163      public static final boolean LOWER_ARRAY_ACCESS = VM.BuildForPowerPC;
164    
165      /**
166       * Converts the given HIR to LIR.
167       *
168       * @param ir IR to convert
169       */
170      static void convert(IR ir, OptOptions options) {
171        boolean didArrayStoreCheck = false;
172        for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
173    
174          switch (s.getOpcode()) {
175            case GETSTATIC_opcode: {
176              LocationOperand loc = GetStatic.getClearLocation(s);
177              RegisterOperand result = GetStatic.getClearResult(s);
178              Operand address = ir.regpool.makeJTOCOp(ir, s);
179              Operand offset = GetStatic.getClearOffset(s);
180              Load.mutate(s, IRTools.getLoadOp(loc.getFieldRef(), true), result, address, offset, loc);
181            }
182            break;
183    
184            case PUTSTATIC_opcode: {
185              LocationOperand loc = PutStatic.getClearLocation(s);
186              Operand value = PutStatic.getClearValue(s);
187              Operand address = ir.regpool.makeJTOCOp(ir, s);
188              Operand offset = PutStatic.getClearOffset(s);
189              Store.mutate(s, IRTools.getStoreOp(loc.getFieldRef(), true), value, address, offset, loc);
190            }
191            break;
192    
193            case PUTFIELD_opcode: {
194              LocationOperand loc = PutField.getClearLocation(s);
195              Operand value = PutField.getClearValue(s);
196              Operand address = PutField.getClearRef(s);
197              Operand offset = PutField.getClearOffset(s);
198              Store.mutate(s,
199                           IRTools.getStoreOp(loc.getFieldRef(), false),
200                           value,
201                           address,
202                           offset,
203                           loc,
204                           PutField.getClearGuard(s));
205            }
206            break;
207    
208            case GETFIELD_opcode: {
209              LocationOperand loc = GetField.getClearLocation(s);
210              RegisterOperand result = GetField.getClearResult(s);
211              Operand address = GetField.getClearRef(s);
212              Operand offset = GetField.getClearOffset(s);
213              Load.mutate(s,
214                          IRTools.getLoadOp(loc.getFieldRef(), false),
215                          result,
216                          address,
217                          offset,
218                          loc,
219                          GetField.getClearGuard(s));
220            }
221            break;
222    
223            case INT_ALOAD_opcode:
224              doArrayLoad(s, ir, INT_LOAD, 2);
225              break;
226    
227            case LONG_ALOAD_opcode:
228              doArrayLoad(s, ir, LONG_LOAD, 3);
229              break;
230    
231            case FLOAT_ALOAD_opcode:
232              doArrayLoad(s, ir, FLOAT_LOAD, 2);
233              break;
234    
235            case DOUBLE_ALOAD_opcode:
236              doArrayLoad(s, ir, DOUBLE_LOAD, 3);
237              break;
238    
239            case REF_ALOAD_opcode:
240              doArrayLoad(s, ir, REF_LOAD, LOG_BYTES_IN_ADDRESS);
241              break;
242    
243            case BYTE_ALOAD_opcode:
244              doArrayLoad(s, ir, BYTE_LOAD, 0);
245              break;
246    
247            case UBYTE_ALOAD_opcode:
248              doArrayLoad(s, ir, UBYTE_LOAD, 0);
249              break;
250    
251            case USHORT_ALOAD_opcode:
252              doArrayLoad(s, ir, USHORT_LOAD, 1);
253              break;
254    
255            case SHORT_ALOAD_opcode:
256              doArrayLoad(s, ir, SHORT_LOAD, 1);
257              break;
258    
259            case INT_ASTORE_opcode:
260              doArrayStore(s, ir, INT_STORE, 2);
261              break;
262    
263            case LONG_ASTORE_opcode:
264              doArrayStore(s, ir, LONG_STORE, 3);
265              break;
266    
267            case FLOAT_ASTORE_opcode:
268              doArrayStore(s, ir, FLOAT_STORE, 2);
269              break;
270    
271            case DOUBLE_ASTORE_opcode:
272              doArrayStore(s, ir, DOUBLE_STORE, 3);
273              break;
274    
275            case REF_ASTORE_opcode:
276              doArrayStore(s, ir, REF_STORE, LOG_BYTES_IN_ADDRESS);
277              break;
278    
279            case BYTE_ASTORE_opcode:
280              doArrayStore(s, ir, BYTE_STORE, 0);
281              break;
282    
283            case SHORT_ASTORE_opcode:
284              doArrayStore(s, ir, SHORT_STORE, 1);
285              break;
286    
287            case CALL_opcode:
288              s = callHelper(s, ir);
289              break;
290    
291            case SYSCALL_opcode:
292              // If the SYSCALL is using a symbolic address, convert that to
293              // a sequence of loads off the BootRecord to find the appropriate field.
294              if (Call.getMethod(s) != null) {
295                expandSysCallTarget(s, ir);
296              }
297              break;
298    
299            case TABLESWITCH_opcode:
300              s = tableswitch(s, ir);
301              break;
302    
303            case LOOKUPSWITCH_opcode:
304              s = lookup(s, ir);
305              break;
306    
307            case OBJARRAY_STORE_CHECK_opcode:
308              s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, true);
309              didArrayStoreCheck = true;
310              break;
311    
312            case OBJARRAY_STORE_CHECK_NOTNULL_opcode:
313              s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, false);
314              didArrayStoreCheck = true;
315              break;
316    
317            case CHECKCAST_opcode:
318            case CHECKCAST_UNRESOLVED_opcode:
319              s = DynamicTypeCheckExpansion.checkcast(s, ir);
320              break;
321    
322            case CHECKCAST_NOTNULL_opcode:
323              s = DynamicTypeCheckExpansion.checkcastNotNull(s, ir);
324              break;
325    
326            case MUST_IMPLEMENT_INTERFACE_opcode:
327              s = DynamicTypeCheckExpansion.mustImplementInterface(s, ir);
328              break;
329    
330            case IG_CLASS_TEST_opcode:
331              IfCmp.mutate(s,
332                           REF_IFCMP,
333                           ir.regpool.makeTempValidation(),
334                           getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s)),
335                           getTIB(s, ir, InlineGuard.getGoal(s).asType()),
336                           ConditionOperand.NOT_EQUAL(),
337                           InlineGuard.getClearTarget(s),
338                           InlineGuard.getClearBranchProfile(s));
339              break;
340    
341            case IG_METHOD_TEST_opcode: {
342              MethodOperand methOp = InlineGuard.getClearGoal(s).asMethod();
343              Operand t1 = getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s));
344              Operand t2 = getTIB(s, ir, methOp.getTarget().getDeclaringClass());
345              IfCmp.mutate(s,
346                           REF_IFCMP,
347                           ir.regpool.makeTempValidation(),
348                           getInstanceMethod(s, ir, t1, methOp.getTarget()),
349                           getInstanceMethod(s, ir, t2, methOp.getTarget()),
350                           ConditionOperand.NOT_EQUAL(),
351                           InlineGuard.getClearTarget(s),
352                           InlineGuard.getClearBranchProfile(s));
353              break;
354            }
355    
356            case INSTANCEOF_opcode:
357            case INSTANCEOF_UNRESOLVED_opcode:
358              s = DynamicTypeCheckExpansion.instanceOf(s, ir);
359              break;
360    
361            case INSTANCEOF_NOTNULL_opcode:
362              s = DynamicTypeCheckExpansion.instanceOfNotNull(s, ir);
363              break;
364    
365            case INT_ZERO_CHECK_opcode: {
366              TrapIf.mutate(s,
367                            TRAP_IF,
368                            ZeroCheck.getClearGuardResult(s),
369                            ZeroCheck.getClearValue(s),
370                            IC(0),
371                            ConditionOperand.EQUAL(),
372                            TrapCodeOperand.DivByZero());
373            }
374            break;
375    
376            case LONG_ZERO_CHECK_opcode: {
377              TrapIf.mutate(s,
378                            TRAP_IF,
379                            ZeroCheck.getClearGuardResult(s),
380                            ZeroCheck.getClearValue(s),
381                            LC(0),
382                            ConditionOperand.EQUAL(),
383                            TrapCodeOperand.DivByZero());
384            }
385            break;
386    
387            case BOUNDS_CHECK_opcode: {
388              // get array_length from array_ref
389              RegisterOperand array_length =
390                  InsertGuardedUnary(s,
391                                     ir,
392                                     ARRAYLENGTH,
393                                     TypeReference.Int,
394                                     BoundsCheck.getClearRef(s),
395                                     BoundsCheck.getClearGuard(s));
396              //  In UN-signed comparison, a negative index will look like a very
397              //  large positive number, greater than array length.
398              //  Thus length LLT index is false iff 0 <= index <= length
399              TrapIf.mutate(s,
400                            TRAP_IF,
401                            BoundsCheck.getClearGuardResult(s),
402                            array_length.copyD2U(),
403                            BoundsCheck.getClearIndex(s),
404                            ConditionOperand.LOWER_EQUAL(),
405                            TrapCodeOperand.ArrayBounds());
406            }
407            break;
408    
409            case RESOLVE_MEMBER_opcode:
410              s = resolveMember(s, ir);
411              break;
412    
413            default:
414              break;
415          }
416        }
417        // Eliminate possible redundant trap block from array store checks
418        if (didArrayStoreCheck) {
419          branchOpts.perform(ir, true);
420        }
421      }
422    
423      private static BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true);
424    
425      /**
426       * Expand a tableswitch.
427       * @param s the instruction to expand
428       * @param ir the containing IR
429       * @return the last Instruction in the generated LIR sequence.
430       */
431      static Instruction tableswitch(Instruction s, IR ir) {
432    
433        Instruction s2;
434        int lowLimit = TableSwitch.getLow(s).value;
435        int highLimit = TableSwitch.getHigh(s).value;
436        int number = highLimit - lowLimit + 1;
437        if (VM.VerifyAssertions) {
438          VM._assert(number > 0);    // also checks that there are < 2^31 targets
439        }
440        Operand val = TableSwitch.getClearValue(s);
441        BranchOperand defaultLabel = TableSwitch.getClearDefault(s);
442        if (number < ir.options.CONTROL_TABLESWITCH_CUTOFF) { // convert into a lookupswitch
443          Instruction l =
444              LookupSwitch.create(LOOKUPSWITCH,
445                                  val,
446                                  null,
447                                  null,
448                                  defaultLabel,
449                                  TableSwitch.getClearDefaultBranchProfile(s),
450                                  number * 3);
451          for (int i = 0; i < number; i++) {
452            LookupSwitch.setMatch(l, i, IC(lowLimit + i));
453            LookupSwitch.setTarget(l, i, TableSwitch.getClearTarget(s, i));
454            LookupSwitch.setBranchProfile(l, i, TableSwitch.getClearBranchProfile(s, i));
455          }
456          s.insertAfter(CPOS(s, l));
457          return s.remove();
458        }
459        RegisterOperand reg = val.asRegister();
460        BasicBlock BB1 = s.getBasicBlock();
461        BasicBlock BB2 = BB1.splitNodeAt(s, ir);
462        BasicBlock defaultBB = defaultLabel.target.getBasicBlock();
463    
464        /******* First basic block */
465        RegisterOperand t;
466        if (lowLimit != 0) {
467          t = insertBinary(s, ir, INT_ADD, TypeReference.Int, reg, IC(-lowLimit));
468        } else {
469          t = reg.copyU2U();
470        }
471        BranchProfileOperand defaultProb = TableSwitch.getClearDefaultBranchProfile(s);
472        s.replace(CPOS(s, IfCmp.create(INT_IFCMP,
473                            ir.regpool.makeTempValidation(),
474                            t,
475                            IC(highLimit - lowLimit),
476                            ConditionOperand.HIGHER(),
477                            defaultLabel,
478                            defaultProb)));
479        // Reweight branches to account for the default branch going. If
480        // the default probability was ALWAYS then when we recompute the
481        // weight to be a proportion of the total number of branches.
482        final boolean defaultIsAlways = defaultProb.takenProbability >= 1f;
483        final float weight = defaultIsAlways ? 1f / number : 1f / (1f - defaultProb.takenProbability);
484    
485        /********** second Basic Block ******/
486        s2 = CPOS(s, LowTableSwitch.create(LOWTABLESWITCH, t.copyRO(), number * 2));
487        boolean containsDefault = false;
488        for (int i = 0; i < number; i++) {
489          BranchOperand b = TableSwitch.getClearTarget(s, i);
490          LowTableSwitch.setTarget(s2, i, b);
491          BranchProfileOperand bp = TableSwitch.getClearBranchProfile(s, i);
492          if (defaultIsAlways) {
493            bp.takenProbability = weight;
494          } else {
495            bp.takenProbability *= weight;
496          }
497          LowTableSwitch.setBranchProfile(s2, i, bp);
498          if (b.target == defaultLabel.target) {
499            containsDefault = true;
500          }
501        }
502        // Fixup the CFG and code order.
503        BB1.insertOut(BB2);
504        BB1.insertOut(defaultBB);
505        ir.cfg.linkInCodeOrder(BB1, BB2);
506        if (!containsDefault) {
507          BB2.deleteOut(defaultBB);
508        }
509        // Simplify a fringe case...
510        // if all targets of the LOWTABLESWITCH are the same,
511        // then just use a GOTO instead of the LOWTABLESWITCH.
512        // This actually happens (very occasionally), and is easy to test for.
513        if (BB2.getNumberOfNormalOut() == 1) {
514          BB2.appendInstruction(CPOS(s, Goto.create(GOTO, LowTableSwitch.getTarget(s2, 0))));
515        } else {
516          BB2.appendInstruction(s2);
517        }
518        // continue at next BB
519        s = BB2.lastInstruction();
520    
521        return s;
522      }
523    
524      /**
525       * Expand a lookupswitch.
526       * @param switchInstr  The instruction to expand
527       * @param ir           The containing IR
528       * @return the next {@link Instruction} after the generated LIR sequence.
529       */
530      static Instruction lookup(Instruction switchInstr, IR ir) {
531        Instruction bbend = switchInstr.nextInstructionInCodeOrder();
532        BasicBlock thisBB = bbend.getBasicBlock();
533        BasicBlock nextBB = thisBB.nextBasicBlockInCodeOrder();
534        // Blow away the old Normal ControlFlowGraph edges to prepare for new links
535        thisBB.deleteNormalOut();
536        switchInstr.remove();
537        BranchOperand defTarget = LookupSwitch.getClearDefault(switchInstr);
538        BasicBlock defaultBB = defTarget.target.getBasicBlock();
539        int high = LookupSwitch.getNumberOfTargets(switchInstr) - 1;
540        if (high < 0) {
541          // no cases in switch; just jump to defaultBB
542          thisBB.appendInstruction(Goto.create(GOTO, defTarget));
543          thisBB.insertOut(defaultBB);
544        } else {
545          Operand match = LookupSwitch.getValue(switchInstr);
546          if (match.isConstant()) {
547            // switch on a constant
548            int value = match.asIntConstant().value;
549            int numMatches = LookupSwitch.getNumberOfMatches(switchInstr);
550            BranchOperand target = LookupSwitch.getDefault(switchInstr);
551            for (int i = 0; i < numMatches; i++) {
552              if (value == LookupSwitch.getMatch(switchInstr, i).value) {
553                target = LookupSwitch.getTarget(switchInstr, i);
554                break;
555              }
556            }
557            thisBB.appendInstruction(Goto.create(GOTO, target));
558            thisBB.insertOut(target.target.getBasicBlock());
559          } else {
560            RegisterOperand reg = match.asRegister();
561    
562            // If you're not already at the end of the code order
563            if (nextBB != null) {
564              ir.cfg.breakCodeOrder(thisBB, nextBB);
565            }
566            // generate the binary search tree into thisBB
567            BasicBlock lastNewBB =
568                _lookupswitchHelper(switchInstr, reg, defaultBB, ir, thisBB, 0, high, Integer.MIN_VALUE, Integer.MAX_VALUE);
569            if (nextBB != null) {
570              ir.cfg.linkInCodeOrder(lastNewBB, nextBB);
571            }
572          }
573        }
574    
575        // skip all the instrs just inserted by _lookupswitchHelper
576        if (nextBB != null) {
577          return nextBB.firstInstruction();
578        } else {
579          return thisBB.lastInstruction();
580        }
581      }
582    
583      /**
584       * Helper function to generate the binary search tree for
585       * a lookupswitch bytecode
586       *
587       * @param switchInstr the lookupswitch instruction
588       * @param defaultBB the basic block of the default case
589       * @param ir the ir object
590       * @param curBlock the basic block to insert instructions into
591       * @param reg the RegisterOperand that contains the valued being switched on
592       * @param low the low index of cases (operands of switchInstr)
593       * @param high the high index of cases (operands of switchInstr)
594       * @param min
595       * @param max
596       * @return the last basic block created
597       */
598      private static BasicBlock _lookupswitchHelper(Instruction switchInstr, RegisterOperand reg,
599                                                        BasicBlock defaultBB, IR ir, BasicBlock curBlock,
600                                                        int low, int high, int min, int max) {
601        if (VM.VerifyAssertions) {
602          VM._assert(low <= high, "broken control logic in _lookupswitchHelper");
603        }
604    
605        int middle = (low + high) >> 1;             // find middle
606    
607        // The following are used below to store the computed branch
608        // probabilities for the branches that are created to implement
609        // the binary search.  Used only if basic block frequencies available
610        float lessProb = 0.0f;
611        float greaterProb = 0.0f;
612        float equalProb = 0.0f;
613        float sum = 0.0f;
614    
615        // Sum the probabilities for all targets < middle
616        for (int i = low; i < middle; i++) {
617          lessProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
618        }
619    
620        // Sum the probabilities for all targets > middle
621        for (int i = middle + 1; i <= high; i++) {
622          greaterProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
623        }
624        equalProb = LookupSwitch.getBranchProfile(switchInstr, middle).takenProbability;
625    
626        // The default case is a bit of a kludge.  We know the total
627        // probability of executing the default case, but we have no
628        // idea which paths are taken to get there.  For now, we'll
629        // assume that all paths that went to default were because the
630        // value was less than the smallest switch value.  This ensures
631        // that all basic block appearing in the switch will have the
632        // correct weights (but the blocks in the binary switch
633        // generated may not).
634        if (low == 0) {
635          lessProb += LookupSwitch.getDefaultBranchProfile(switchInstr).takenProbability;
636        }
637    
638        // Now normalize them so they are relative to the sum of the
639        // branches being considered in this piece of the subtree
640        sum = lessProb + equalProb + greaterProb;
641        if (sum > 0) {  // check for divide by zero
642          lessProb /= sum;
643          equalProb /= sum;
644          greaterProb /= sum;
645        }
646    
647        IntConstantOperand val = LookupSwitch.getClearMatch(switchInstr, middle);
648        int value = val.value;
649        BasicBlock greaterBlock = middle == high ? defaultBB : curBlock.createSubBlock(0, ir);
650        BasicBlock lesserBlock = low == middle ? defaultBB : curBlock.createSubBlock(0, ir);
651        // Generate this level of tests
652        BranchOperand branch = LookupSwitch.getClearTarget(switchInstr, middle);
653        BasicBlock branchBB = branch.target.getBasicBlock();
654        curBlock.insertOut(branchBB);
655        if (low != high) {
656          if (value == min) {
657            curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
658                ir.regpool.makeTempValidation(),
659                reg.copy(),
660                val,
661                ConditionOperand.EQUAL(),
662                branchBB.makeJumpTarget(),
663                new BranchProfileOperand(equalProb)));
664          } else {
665    
666            // To compute the probability of the second compare, the first
667            // probability must be removed since the second branch is
668            // considered only if the first fails.
669            float secondIfProb = 0.0f;
670            sum = equalProb + greaterProb;
671            if (sum > 0) {
672              // if divide by zero, leave as is
673              secondIfProb = equalProb / sum;
674            }
675    
676            curBlock.appendInstruction(IfCmp2.create(INT_IFCMP2,
677                ir.regpool.makeTempValidation(),
678                reg.copy(),
679                val,
680                ConditionOperand.LESS(),
681                lesserBlock.makeJumpTarget(),
682                new BranchProfileOperand(lessProb),
683                ConditionOperand.EQUAL(),
684                branchBB.makeJumpTarget(),
685                new BranchProfileOperand(secondIfProb)));
686            curBlock.insertOut(lesserBlock);
687          }
688        } else {      // Base case: middle was the only case left to consider
689          if (min == max) {
690            curBlock.appendInstruction(Goto.create(GOTO, branch));
691            curBlock.insertOut(branchBB);
692          } else {
693            curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
694                ir.regpool.makeTempValidation(),
695                reg.copy(),
696                val,
697                ConditionOperand.EQUAL(),
698                branchBB.makeJumpTarget(),
699                new BranchProfileOperand(equalProb)));
700            BasicBlock newBlock = curBlock.createSubBlock(0, ir);
701            curBlock.insertOut(newBlock);
702            ir.cfg.linkInCodeOrder(curBlock, newBlock);
703            curBlock = newBlock;
704            curBlock.appendInstruction(defaultBB.makeGOTO());
705            curBlock.insertOut(defaultBB);
706          }
707        }
708        // Generate sublevels as needed and splice together instr & bblist
709        if (middle < high) {
710          curBlock.insertOut(greaterBlock);
711          ir.cfg.linkInCodeOrder(curBlock, greaterBlock);
712          curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, greaterBlock, middle + 1, high, value + 1, max);
713        }
714        if (low < middle) {
715          ir.cfg.linkInCodeOrder(curBlock, lesserBlock);
716          curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, lesserBlock, low, middle - 1, min, value - 1);
717        }
718        return curBlock;
719      }
720    
721      /**
722       * Expand an array load.
723       * @param s the instruction to expand
724       * @param ir the containing IR
725       * @param op the load operator to use
726       * @param logwidth the log base 2 of the element type's size
727       */
728      public static void doArrayLoad(Instruction s, IR ir, Operator op, int logwidth) {
729        if (LOWER_ARRAY_ACCESS) {
730          RegisterOperand result = ALoad.getClearResult(s);
731          Operand array = ALoad.getClearArray(s);
732          Operand index = ALoad.getClearIndex(s);
733          Operand offset;
734          LocationOperand loc = ALoad.getClearLocation(s);
735          if (index instanceof IntConstantOperand) {  // constant propagation
736            offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
737          } else {
738            if (logwidth != 0) {
739              offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
740              offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
741            } else {
742              offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
743            }
744          }
745          Load.mutate(s, op, result, array, offset, loc, ALoad.getClearGuard(s));
746        }
747      }
748    
749      /**
750       * Expand an array store.
751       * @param s the instruction to expand
752       * @param ir the containing IR
753       * @param op the store operator to use
754       * @param logwidth the log base 2 of the element type's size
755       */
756      public static void doArrayStore(Instruction s, IR ir, Operator op, int logwidth) {
757        if (LOWER_ARRAY_ACCESS) {
758          Operand value = AStore.getClearValue(s);
759          Operand array = AStore.getClearArray(s);
760          Operand index = AStore.getClearIndex(s);
761          Operand offset;
762          LocationOperand loc = AStore.getClearLocation(s);
763          if (index instanceof IntConstantOperand) {// constant propagation
764            offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
765          } else {
766            if (logwidth != 0) {
767              offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
768              offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
769            } else {
770              offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
771            }
772          }
773          Store.mutate(s, op, value, array, offset, loc, AStore.getClearGuard(s));
774        }
775      }
776    
777      /**
778       * Helper method for call expansion.
779       * @param v the call instruction
780       * @param ir the containing IR
781       * @return the last expanded instruction
782       */
783      static Instruction callHelper(Instruction v, IR ir) {
784        if (!Call.hasMethod(v)) {
785          if (VM.VerifyAssertions) VM._assert(Call.getAddress(v) instanceof RegisterOperand);
786          return v; // nothing to do....very low level call to address already in the register.
787        }
788    
789        MethodOperand methOp = Call.getMethod(v);
790    
791        // Handle recursive invocations.
792        if (methOp.hasPreciseTarget() && methOp.getTarget() == ir.method) {
793          Call.setAddress(v, new BranchOperand(ir.firstInstructionInCodeOrder()));
794          return v;
795        }
796    
797        /* RRB 100500 */
798        // generate direct call to specialized method if the method operand
799        // has been marked as a specialized call.
800        if (VM.runningVM) {
801          SpecializedMethod spMethod = methOp.spMethod;
802          if (spMethod != null) {
803            int smid = spMethod.getSpecializedMethodIndex();
804            Call.setAddress(v, getSpecialMethod(v, ir, smid));
805            return v;
806          }
807        }
808    
809        // Used mainly (only?) by OSR
810        if (methOp.hasDesignatedTarget()) {
811          Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, methOp.jtocOffset));
812          return v;
813        }
814    
815        if (methOp.isStatic()) {
816          if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
817          Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
818        } else if (methOp.isVirtual()) {
819          if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
820          if (ir.options.H2L_CALL_VIA_JTOC && methOp.hasPreciseTarget()) {
821            // Call to precise type can go via JTOC
822            RVMMethod target = methOp.getTarget();
823            Call.setAddress(v,
824                            InsertLoadOffsetJTOC(v,
825                                                 ir,
826                                                 REF_LOAD,
827                                                 TypeReference.CodeArray,
828                                                 target.findOrCreateJtocOffset()));
829          } else {
830            Operand tib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
831            Call.setAddress(v,
832                            InsertLoadOffset(v,
833                                             ir,
834                                             REF_LOAD,
835                                             TypeReference.CodeArray,
836                                             tib,
837                                             Call.getClearAddress(v),
838                                             null,
839                                             TG()));
840          }
841        } else if (methOp.isSpecial()) {
842          RVMMethod target = methOp.getTarget();
843          if (target == null || target.isObjectInitializer() || target.isStatic()) {
844            // target == null => we are calling an unresolved <init> method.
845            Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
846          } else {
847            if (ir.options.H2L_CALL_VIA_JTOC) {
848              Call.setAddress(v,
849                              InsertLoadOffsetJTOC(v,
850                                                   ir,
851                                                   REF_LOAD,
852                                                   TypeReference.CodeArray,
853                                                   target.findOrCreateJtocOffset()));
854            } else {
855              // invoking a virtual method; do it via TIB of target's declaring class.
856              Operand tib = getTIB(v, ir, target.getDeclaringClass());
857              Call.setAddress(v,
858                              InsertLoadOffset(v,
859                                               ir,
860                                               REF_LOAD,
861                                               TypeReference.CodeArray,
862                                               tib,
863                                               Call.getClearAddress(v),
864                                               null,
865                                               TG()));
866            }
867          }
868        } else {
869          if (VM.VerifyAssertions) VM._assert(methOp.isInterface());
870          if (VM.VerifyAssertions) VM._assert(!Call.hasAddress(v));
871          if (VM.BuildForIMTInterfaceInvocation) {
872            // SEE ALSO: FinalMIRExpansion (for hidden parameter)
873            Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
874            InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methOp.getMemberRef());
875            Offset offset = sig.getIMTOffset();
876            RegisterOperand address = null;
877            RegisterOperand IMT =
878              InsertLoadOffset(v,
879                               ir,
880                               REF_LOAD,
881                               TypeReference.IMT,
882                               RHStib.copy(),
883                               Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS));
884            address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, IMT.copyD2U(), offset);
885    
886            Call.setAddress(v, address);
887          } else {
888            int itableIndex = -1;
889            if (VM.BuildForITableInterfaceInvocation && methOp.hasTarget()) {
890              RVMClass I = methOp.getTarget().getDeclaringClass();
891              // search ITable variant
892              itableIndex =
893                  InterfaceInvocation.getITableIndex(I,
894                                                        methOp.getMemberRef().getName(),
895                                                        methOp.getMemberRef().getDescriptor());
896            }
897            if (itableIndex == -1) {
898              // itable index is not known at compile-time.
899              // call "invokeinterface" to resolve the object and method id
900              // into a method address
901              RegisterOperand realAddrReg = ir.regpool.makeTemp(TypeReference.CodeArray);
902              RVMMethod target = Entrypoints.invokeInterfaceMethod;
903              Instruction vp =
904                  Call.create2(CALL,
905                               realAddrReg,
906                               AC(target.getOffset()),
907                               MethodOperand.STATIC(target),
908                               Call.getParam(v, 0).asRegister().copyU2U(),
909                               IC(methOp.getMemberRef().getId()));
910              vp.position = v.position;
911              vp.bcIndex = RUNTIME_SERVICES_BCI;
912              v.insertBefore(vp);
913              callHelper(vp, ir);
914              Call.setAddress(v, realAddrReg.copyD2U());
915              return v;
916            } else {
917              // itable index is known at compile-time.
918              // call "findITable" to resolve object + interface id into
919              // itable address
920              RegisterOperand iTable = ir.regpool.makeTemp(TypeReference.ITable);
921              Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
922              RVMMethod target = Entrypoints.findItableMethod;
923              Instruction fi =
924                  Call.create2(CALL,
925                               iTable,
926                               AC(target.getOffset()),
927                               MethodOperand.STATIC(target),
928                               RHStib,
929                               IC(methOp.getTarget().getDeclaringClass().getInterfaceId()));
930              fi.position = v.position;
931              fi.bcIndex = RUNTIME_SERVICES_BCI;
932              v.insertBefore(fi);
933              callHelper(fi, ir);
934              RegisterOperand address =
935                  InsertLoadOffset(v,
936                                   ir,
937                                   REF_LOAD,
938                                   TypeReference.CodeArray,
939                                   iTable.copyD2U(),
940                                   Offset.fromIntZeroExtend(itableIndex << LOG_BYTES_IN_ADDRESS));
941              Call.setAddress(v, address);
942              return v;
943            }
944          }
945        }
946        return v;
947      }
948    
949      /**
950       * Generate the code to resolve a member (field/method) reference.
951       * @param s the RESOLVE_MEMBER instruction to expand
952       * @param ir the containing ir object
953       * @return the last expanded instruction
954       */
955      private static Instruction resolveMember(Instruction s, IR ir) {
956        Operand memberOp = Unary.getClearVal(s);
957        RegisterOperand offset = Unary.getClearResult(s);
958        int dictId;
959        if (memberOp instanceof LocationOperand) {
960          dictId = ((LocationOperand) memberOp).getFieldRef().getId();
961        } else {
962          dictId = ((MethodOperand) memberOp).getMemberRef().getId();
963        }
964    
965        BranchProfileOperand bp = BranchProfileOperand.never();
966        BasicBlock predBB = s.getBasicBlock();
967        BasicBlock succBB = predBB.splitNodeAt(s.prevInstructionInCodeOrder(), ir);
968        BasicBlock testBB = predBB.createSubBlock(s.bcIndex, ir, 1f - bp.takenProbability);
969        BasicBlock resolveBB = predBB.createSubBlock(s.bcIndex, ir, bp.takenProbability);
970        s.remove();
971    
972        // Get the offset from the appropriate RVMClassLoader array
973        // and check to see if it is valid
974        RegisterOperand offsetTable = getStatic(testBB.lastInstruction(), ir, Entrypoints.memberOffsetsField);
975        testBB.appendInstruction(Load.create(INT_LOAD,
976                                             offset.copyRO(),
977                                             offsetTable,
978                                             AC(Offset.fromIntZeroExtend(dictId << LOG_BYTES_IN_INT)),
979                                             new LocationOperand(TypeReference.Int),
980                                             TG()));
981        testBB.appendInstruction(Unary.create(INT_2ADDRSigExt, offset, offset.copy()));
982        testBB.appendInstruction(IfCmp.create(REF_IFCMP,
983            ir.regpool.makeTempValidation(),
984            offset.copy(),
985            AC(Address.fromIntSignExtend(NEEDS_DYNAMIC_LINK)),
986            ConditionOperand.EQUAL(),
987            resolveBB.makeJumpTarget(),
988            bp));
989    
990        // Handle the offset being invalid
991        resolveBB.appendInstruction(CacheOp.mutate(s, RESOLVE, memberOp));
992        resolveBB.appendInstruction(testBB.makeGOTO());
993    
994        // Put together the CFG links & code order
995        predBB.insertOut(testBB);
996        ir.cfg.linkInCodeOrder(predBB, testBB);
997        testBB.insertOut(succBB);
998        testBB.insertOut(resolveBB);
999        ir.cfg.linkInCodeOrder(testBB, succBB);
1000        resolveBB.insertOut(testBB);              // backedge
1001        ir.cfg.addLastInCodeOrder(resolveBB);  // stick resolution code in outer space.
1002        return testBB.lastInstruction();
1003      }
1004    
1005      /**
1006       * Insert a binary instruction before s in the instruction stream.
1007       * @param s the instruction to insert before
1008       * @param ir the containing IR
1009       * @param operator the operator to insert
1010       * @param type the type of the result
1011       * @param o1 the first operand
1012       * @param o2 the second operand
1013       * @return the result operand of the inserted instruction
1014       */
1015      public static RegisterOperand insertBinary(Instruction s, IR ir, Operator operator,
1016                                                     TypeReference type, Operand o1, Operand o2) {
1017        RegisterOperand t = ir.regpool.makeTemp(type);
1018        s.insertBefore(CPOS(s, Binary.create(operator, t, o1, o2)));
1019        return t.copyD2U();
1020      }
1021    
1022      /**
1023       * Insert a unary instruction before s in the instruction stream.
1024       * @param s the instruction to insert before
1025       * @param ir the containing IR
1026       * @param operator the operator to insert
1027       * @param type the type of the result
1028       * @param o1 the operand
1029       * @return the result operand of the inserted instruction
1030       */
1031      static RegisterOperand InsertUnary(Instruction s, IR ir, Operator operator, TypeReference type,
1032                                             Operand o1) {
1033        RegisterOperand t = ir.regpool.makeTemp(type);
1034        s.insertBefore(CPOS(s, Unary.create(operator, t, o1)));
1035        return t.copyD2U();
1036      }
1037    
1038      /**
1039       * Insert a guarded unary instruction before s in the instruction stream.
1040       * @param s the instruction to insert before
1041       * @param ir the containing IR
1042       * @param operator the operator to insert
1043       * @param type the type of the result
1044       * @param o1 the operand
1045       * @param guard the guard operand
1046       * @return the result operand of the inserted instruction
1047       */
1048      static RegisterOperand InsertGuardedUnary(Instruction s, IR ir, Operator operator,
1049                                                    TypeReference type, Operand o1, Operand guard) {
1050        RegisterOperand t = ir.regpool.makeTemp(type);
1051        s.insertBefore(GuardedUnary.create(operator, t, o1, guard));
1052        return t.copyD2U();
1053      }
1054    
1055      /**
1056       * Insert a load off the JTOC before s in the instruction stream.
1057       * @param s the instruction to insert before
1058       * @param ir the containing IR
1059       * @param operator the operator to insert
1060       * @param type the type of the result
1061       * @param offset the offset to load at
1062       * @return the result operand of the inserted instruction
1063       */
1064      static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1065                                                      TypeReference type, Offset offset) {
1066        return InsertLoadOffset(s,
1067                                ir,
1068                                operator,
1069                                type,
1070                                ir.regpool.makeJTOCOp(ir, s),
1071                                AC(offset),
1072                                new LocationOperand(offset),
1073                                null);
1074      }
1075    
1076      /**
1077       * Insert a load off the JTOC before s in the instruction stream.
1078       * @param s the instruction to insert before
1079       * @param ir the containing IR
1080       * @param operator the operator to insert
1081       * @param type the type of the result
1082       * @param offset the offset to load at
1083       * @return the result operand of the inserted instruction
1084       */
1085      static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1086                                                      TypeReference type, Operand offset) {
1087        return InsertLoadOffset(s, ir, operator, type, ir.regpool.makeJTOCOp(ir, s), offset, null, null);
1088      }
1089    
1090      /**
1091       * Insert a load off before s in the instruction stream.
1092       * @param s the instruction to insert before
1093       * @param ir the containing IR
1094       * @param operator the operator to insert
1095       * @param type the type of the result
1096       * @param reg2 the base to load from
1097       * @param offset the offset to load at
1098       * @return the result operand of the inserted instruction
1099       */
1100      static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1101                                                  TypeReference type, Operand reg2, Offset offset) {
1102        return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, null);
1103      }
1104    
1105      /**
1106       * Insert a load off before s in the instruction stream.
1107       * @param s the instruction to insert before
1108       * @param ir the containing IR
1109       * @param operator the operator to insert
1110       * @param type the type of the result
1111       * @param reg2 the base to load from
1112       * @param offset the offset to load at
1113       * @param guard the guard operand
1114       * @return the result operand of the inserted instruction
1115       */
1116      static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1117                                                  TypeReference type, Operand reg2, Offset offset,
1118                                                  Operand guard) {
1119        return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, guard);
1120      }
1121    
1122      /**
1123       * Insert a load off before s in the instruction stream.
1124       * @param s the instruction to insert before
1125       * @param ir the containing IR
1126       * @param operator the operator to insert
1127       * @param type the type of the result
1128       * @param reg2 the base to load from
1129       * @param offset the offset to load at
1130       * @param loc the location operand
1131       * @param guard the guard operand
1132       * @return the result operand of the inserted instruction
1133       */
1134      static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1135                                                  TypeReference type, Operand reg2, Offset offset,
1136                                                  LocationOperand loc, Operand guard) {
1137        return InsertLoadOffset(s, ir, operator, type, reg2, AC(offset), loc, guard);
1138      }
1139    
1140      /**
1141       * Insert a load off before s in the instruction stream.
1142       * @param s the instruction to insert before
1143       * @param ir the containing IR
1144       * @param operator the operator to insert
1145       * @param type the type of the result
1146       * @param reg2 the base to load from
1147       * @param offset the offset to load at
1148       * @param loc the location operand
1149       * @param guard the guard operand
1150       * @return the result operand of the inserted instruction
1151       */
1152      static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1153                                                  TypeReference type, Operand reg2, Operand offset,
1154                                                  LocationOperand loc, Operand guard) {
1155        RegisterOperand regTarget = ir.regpool.makeTemp(type);
1156        Instruction s2 = Load.create(operator, regTarget, reg2, offset, loc, guard);
1157        s.insertBefore(s2);
1158        return regTarget.copyD2U();
1159      }
1160    
1161      /** get the tib from the object pointer to by obj */
1162      static Operand getTIB(Instruction s, IR ir, Operand obj, Operand guard) {
1163        if (obj.isObjectConstant()) {
1164          // NB Constant types must already be resolved
1165          try {
1166            RVMType type = obj.getType().resolve();
1167            return new TIBConstantOperand(type);
1168          } catch (NoClassDefFoundError e) {
1169            if (VM.runningVM) throw e;
1170            // Class not found during bootstrap due to chasing a class
1171            // only valid in the bootstrap JVM
1172          }
1173        }
1174        RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1175        Instruction s2 = GuardedUnary.create(GET_OBJ_TIB, res, obj, guard);
1176        s.insertBefore(s2);
1177        return res.copyD2U();
1178      }
1179    
1180      /** get the class tib for type */
1181      static Operand getTIB(Instruction s, IR ir, RVMType type) {
1182        return new TIBConstantOperand(type);
1183        //return getTIB(s, ir, new TypeOperand(type));
1184      }
1185    
1186      /** get the class tib for type */
1187      static Operand getTIB(Instruction s, IR ir, TypeOperand type) {
1188        RVMType t = type.getVMType();
1189        if (VM.BuildForIA32 && !MemoryManagerConstants.MOVES_TIBS && VM.runningVM && t != null && t.isResolved()) {
1190          Address addr = Magic.objectAsAddress(t.getTypeInformationBlock());
1191          return new AddressConstantOperand(addr);
1192        } else if (!t.isResolved()) {
1193          RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1194          s.insertBefore(Unary.create(GET_CLASS_TIB, res, type));
1195          return res.copyD2U();
1196        } else {
1197          return new TIBConstantOperand(t);
1198        }
1199      }
1200    
1201      /**
1202       * Get an instance method from a TIB
1203       */
1204      static RegisterOperand getInstanceMethod(Instruction s, IR ir, Operand tib, RVMMethod method) {
1205        return InsertLoadOffset(s, ir, REF_LOAD, TypeReference.CodeArray, tib, method.getOffset());
1206      }
1207    
1208      /**
1209       * Load an instance field.
1210       * @param s
1211       * @param ir
1212       * @param obj
1213       * @param field
1214       */
1215      public static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field) {
1216        return getField(s, ir, obj, field, null);
1217      }
1218    
1219      /**
1220       * Load an instance field.
1221       * @param s
1222       * @param ir
1223       * @param obj
1224       * @param field
1225       * @param guard
1226       */
1227      static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field,
1228                                          Operand guard) {
1229        return InsertLoadOffset(s,
1230                                ir,
1231                                IRTools.getLoadOp(field.getType(), field.isStatic()),
1232                                field.getType(),
1233                                obj,
1234                                field.getOffset(),
1235                                new LocationOperand(field),
1236                                guard);
1237      }
1238    
1239      /*  RRB 100500 */
1240      /**
1241       * support for direct call to specialized method.
1242       */
1243      static RegisterOperand getSpecialMethod(Instruction s, IR ir, int smid) {
1244        //  First, get the pointer to the JTOC offset pointing to the
1245        //  specialized Method table
1246        RegisterOperand reg =
1247            InsertLoadOffsetJTOC(s,
1248                                 ir,
1249                                 REF_LOAD,
1250                                 TypeReference.JavaLangObjectArray,
1251                                 AosEntrypoints.specializedMethodsField.getOffset());
1252        RegisterOperand instr =
1253            InsertLoadOffset(s,
1254                             ir,
1255                             REF_LOAD,
1256                             TypeReference.CodeArray,
1257                             reg,
1258                             Offset.fromIntZeroExtend(smid << LOG_BYTES_IN_INT));
1259        return instr;
1260      }
1261    
1262      /**
1263       * Expand symbolic SysCall target into a chain of loads from the bootrecord to
1264       * the desired target address.
1265       */
1266      public static void expandSysCallTarget(Instruction s, IR ir) {
1267        MethodOperand sysM = Call.getMethod(s);
1268        if (sysM.getMemberRef().isFieldReference()) {
1269          RegisterOperand t1 = getStatic(s, ir, Entrypoints.the_boot_recordField);
1270          RVMField target = sysM.getMemberRef().asFieldReference().resolve();
1271          Operand ip = getField(s, ir, t1, target);
1272          Call.setAddress(s, ip);
1273        }
1274      }
1275    
1276      /**
1277       * Load a static field.
1278       * @param s
1279       * @param ir
1280       * @param field
1281       */
1282      public static RegisterOperand getStatic(Instruction s, IR ir, RVMField field) {
1283        return InsertLoadOffsetJTOC(s,
1284                                    ir,
1285                                    IRTools.getLoadOp(field.getType(), field.isStatic()),
1286                                    field.getType(),
1287                                    field.getOffset());
1288      }
1289    }