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.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
016    import static org.jikesrvm.compilers.opt.ir.Operators.ATHROW_opcode;
017    import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
018    import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
019    import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
020    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE;
021    import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode;
022    import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode;
023    import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_UNRESOLVED_opcode;
024    import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY;
025    import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_opcode;
026    import static org.jikesrvm.compilers.opt.ir.Operators.NEWOBJMULTIARRAY_opcode;
027    import static org.jikesrvm.compilers.opt.ir.Operators.NEW_UNRESOLVED_opcode;
028    import static org.jikesrvm.compilers.opt.ir.Operators.NEW_opcode;
029    import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
030    import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
031    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
032    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
033    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
034    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
035    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
036    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
037    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
038    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
039    import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
040    import static org.jikesrvm.mm.mminterface.Barriers.*;
041    
042    import java.lang.reflect.Constructor;
043    
044    import org.jikesrvm.VM;
045    import org.jikesrvm.classloader.RVMArray;
046    import org.jikesrvm.classloader.RVMClass;
047    import org.jikesrvm.classloader.RVMField;
048    import org.jikesrvm.classloader.FieldReference;
049    import org.jikesrvm.classloader.RVMMethod;
050    import org.jikesrvm.classloader.RVMType;
051    import org.jikesrvm.classloader.TypeReference;
052    import org.jikesrvm.compilers.opt.OptOptions;
053    import org.jikesrvm.compilers.opt.Simple;
054    import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
055    import org.jikesrvm.compilers.opt.driver.CompilerPhase;
056    import org.jikesrvm.compilers.opt.inlining.InlineDecision;
057    import org.jikesrvm.compilers.opt.inlining.Inliner;
058    import org.jikesrvm.compilers.opt.ir.ALoad;
059    import org.jikesrvm.compilers.opt.ir.AStore;
060    import org.jikesrvm.compilers.opt.ir.Athrow;
061    import org.jikesrvm.compilers.opt.ir.Call;
062    import org.jikesrvm.compilers.opt.ir.GetField;
063    import org.jikesrvm.compilers.opt.ir.GetStatic;
064    import org.jikesrvm.compilers.opt.ir.IR;
065    import org.jikesrvm.compilers.opt.ir.IRTools;
066    import org.jikesrvm.compilers.opt.ir.Instruction;
067    import org.jikesrvm.compilers.opt.ir.MonitorOp;
068    import org.jikesrvm.compilers.opt.ir.Multianewarray;
069    import org.jikesrvm.compilers.opt.ir.Move;
070    import org.jikesrvm.compilers.opt.ir.New;
071    import org.jikesrvm.compilers.opt.ir.NewArray;
072    import org.jikesrvm.compilers.opt.ir.PutField;
073    import org.jikesrvm.compilers.opt.ir.PutStatic;
074    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
075    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
076    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
077    import org.jikesrvm.compilers.opt.ir.operand.Operand;
078    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
079    import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
080    import org.jikesrvm.mm.mminterface.MemoryManager;
081    import org.jikesrvm.objectmodel.ObjectModel;
082    import org.jikesrvm.runtime.Entrypoints;
083    
084    /**
085     * As part of the expansion of HIR into LIR, this compile phase
086     * replaces all HIR operators that are implemented as calls to
087     * VM service routines with CALLs to those routines.
088     * For some (common and performance critical) operators, we
089     * may optionally inline expand the call (depending on the
090     * the values of the relevant compiler options and/or Controls).
091     * This pass is also responsible for inserting write barriers
092     * if we are using an allocator that requires them. Write barriers
093     * are always inline expanded.
094     */
095    public final class ExpandRuntimeServices extends CompilerPhase {
096      /** Cache of simple optimizations if used to tidy up */
097      private Simple _os;
098      /** Cache of branch optimizations if used to tidy up */
099      private BranchOptimizations branchOpts;
100      /** Did we expand something? */
101      private boolean didSomething = false;
102    
103      /**
104       * Constructor for this compiler phase
105       */
106      private static final Constructor<CompilerPhase> constructor =
107          getCompilerPhaseConstructor(ExpandRuntimeServices.class);
108    
109      /**
110       * Get a constructor object for this compiler phase
111       * @return compiler phase constructor
112       */
113      public Constructor<CompilerPhase> getClassConstructor() {
114        return constructor;
115      }
116    
117      public boolean shouldPerform(OptOptions options) {
118        return true;
119      }
120    
121      public String getName() {
122        return "Expand Runtime Services";
123      }
124    
125      public void reportAdditionalStats() {
126        VM.sysWrite("  ");
127        VM.sysWrite(container.counter1 / container.counter2 * 100, 2);
128        VM.sysWrite("% Infrequent RS calls");
129      }
130    
131      /**
132       * Given an HIR, expand operators that are implemented as calls to
133       * runtime service methods. This method should be called as one of the
134       * first steps in lowering HIR into LIR.
135       *
136       * @param ir  The HIR to expand
137       */
138      public void perform(IR ir) {
139        ir.gc.resync(); // resync generation context -- yuck...
140    
141        Instruction next;
142        for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst = next) {
143          next = inst.nextInstructionInCodeOrder();
144          int opcode = inst.getOpcode();
145    
146          switch (opcode) {
147    
148            case NEW_opcode: {
149              TypeOperand Type = New.getClearType(inst);
150              RVMClass cls = (RVMClass) Type.getVMType();
151              IntConstantOperand hasFinalizer = IRTools.IC(cls.hasFinalizer() ? 1 : 0);
152              RVMMethod callSite = inst.position.getMethod();
153              IntConstantOperand allocator = IRTools.IC(MemoryManager.pickAllocator(cls, callSite));
154              IntConstantOperand align = IRTools.IC(ObjectModel.getAlignment(cls));
155              IntConstantOperand offset = IRTools.IC(ObjectModel.getOffsetForAlignment(cls, false));
156              Operand tib = ConvertToLowLevelIR.getTIB(inst, ir, Type);
157              if (VM.BuildForIA32 && VM.runningVM) {
158                // shield BC2IR from address constants
159                RegisterOperand tmp = ir.regpool.makeTemp(TypeReference.TIB);
160                inst.insertBefore(Move.create(REF_MOVE, tmp, tib));
161                tib = tmp.copyRO();
162              }
163              IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
164              RVMMethod target = Entrypoints.resolvedNewScalarMethod;
165              Call.mutate7(inst,
166                           CALL,
167                           New.getClearResult(inst),
168                           IRTools.AC(target.getOffset()),
169                           MethodOperand.STATIC(target),
170                           IRTools.IC(cls.getInstanceSize()),
171                           tib,
172                           hasFinalizer,
173                           allocator,
174                           align,
175                           offset,
176                           site);
177              next = inst.prevInstructionInCodeOrder();
178              if (ir.options.H2L_INLINE_NEW) {
179                if (inst.getBasicBlock().getInfrequent()) container.counter1++;
180                container.counter2++;
181                if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
182                  inline(inst, ir);
183                }
184              }
185            }
186            break;
187    
188            case NEW_UNRESOLVED_opcode: {
189              int typeRefId = New.getType(inst).getTypeRef().getId();
190              RVMMethod target = Entrypoints.unresolvedNewScalarMethod;
191              IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
192              Call.mutate2(inst,
193                           CALL,
194                           New.getClearResult(inst),
195                           IRTools.AC(target.getOffset()),
196                           MethodOperand.STATIC(target),
197                           IRTools.IC(typeRefId),
198                           site);
199            }
200            break;
201    
202            case NEWARRAY_opcode: {
203              TypeOperand Array = NewArray.getClearType(inst);
204              RVMArray array = (RVMArray) Array.getVMType();
205              Operand numberElements = NewArray.getClearSize(inst);
206              boolean inline = numberElements instanceof IntConstantOperand;
207              Operand width = IRTools.IC(array.getLogElementSize());
208              Operand headerSize = IRTools.IC(ObjectModel.computeArrayHeaderSize(array));
209              RVMMethod callSite = inst.position.getMethod();
210              IntConstantOperand allocator = IRTools.IC(MemoryManager.pickAllocator(array, callSite));
211              IntConstantOperand align = IRTools.IC(ObjectModel.getAlignment(array));
212              IntConstantOperand offset = IRTools.IC(ObjectModel.getOffsetForAlignment(array, false));
213              Operand tib = ConvertToLowLevelIR.getTIB(inst, ir, Array);
214              if (VM.BuildForIA32 && VM.runningVM) {
215                // shield BC2IR from address constants
216                RegisterOperand tmp = ir.regpool.makeTemp(TypeReference.TIB);
217                inst.insertBefore(Move.create(REF_MOVE, tmp, tib));
218                tib = tmp.copyRO();
219              }
220              IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
221              RVMMethod target = Entrypoints.resolvedNewArrayMethod;
222              Call.mutate8(inst,
223                           CALL,
224                           NewArray.getClearResult(inst),
225                           IRTools.AC(target.getOffset()),
226                           MethodOperand.STATIC(target),
227                           numberElements,
228                           width,
229                           headerSize,
230                           tib,
231                           allocator,
232                           align,
233                           offset,
234                           site);
235              next = inst.prevInstructionInCodeOrder();
236              if (inline && ir.options.H2L_INLINE_NEW) {
237                if (inst.getBasicBlock().getInfrequent()) container.counter1++;
238                container.counter2++;
239                if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
240                  inline(inst, ir);
241                }
242              }
243            }
244            break;
245    
246            case NEWARRAY_UNRESOLVED_opcode: {
247              int typeRefId = NewArray.getType(inst).getTypeRef().getId();
248              Operand numberElements = NewArray.getClearSize(inst);
249              RVMMethod target = Entrypoints.unresolvedNewArrayMethod;
250              IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
251              Call.mutate3(inst,
252                           CALL,
253                           NewArray.getClearResult(inst),
254                           IRTools.AC(target.getOffset()),
255                           MethodOperand.STATIC(target),
256                           numberElements,
257                           IRTools.IC(typeRefId),
258                           site);
259            }
260            break;
261    
262            case NEWOBJMULTIARRAY_opcode: {
263              int dimensions = Multianewarray.getNumberOfDimensions(inst);
264              RVMMethod callSite = inst.position.getMethod();
265              int typeRefId = Multianewarray.getType(inst).getTypeRef().getId();
266              if (dimensions == 2) {
267                RVMMethod target = Entrypoints.optNew2DArrayMethod;
268                Call.mutate4(inst,
269                             CALL,
270                             Multianewarray.getClearResult(inst),
271                             IRTools.AC(target.getOffset()),
272                             MethodOperand.STATIC(target),
273                             IRTools.IC(callSite.getId()),
274                             Multianewarray.getClearDimension(inst, 0),
275                             Multianewarray.getClearDimension(inst, 1),
276                             IRTools.IC(typeRefId));
277              } else {
278                // Step 1: Create an int array to hold the dimensions.
279                TypeOperand dimArrayType = new TypeOperand(RVMArray.IntArray);
280                RegisterOperand dimArray = ir.regpool.makeTemp(TypeReference.IntArray);
281                dimArray.setPreciseType();
282                next =  NewArray.create(NEWARRAY, dimArray, dimArrayType, new IntConstantOperand(dimensions));
283                inst.insertBefore(next);
284                // Step 2: Assign the dimension values to dimArray
285                for (int i = 0; i < dimensions; i++) {
286                  LocationOperand loc = new LocationOperand(TypeReference.Int);
287                  inst.insertBefore(AStore.create(INT_ASTORE,
288                                    Multianewarray.getClearDimension(inst, i),
289                                    dimArray.copyD2U(),
290                                    IRTools.IC(i),
291                                    loc,
292                                    IRTools.TG()));
293                }
294                // Step 3. Plant call to OptLinker.newArrayArray
295                RVMMethod target = Entrypoints.optNewArrayArrayMethod;
296                Call.mutate3(inst,
297                             CALL,
298                             Multianewarray.getClearResult(inst),
299                             IRTools.AC(target.getOffset()),
300                             MethodOperand.STATIC(target),
301                             IRTools.IC(callSite.getId()),
302                             dimArray.copyD2U(),
303                             IRTools.IC(typeRefId));
304              }
305            }
306            break;
307    
308            case ATHROW_opcode: {
309              RVMMethod target = Entrypoints.athrowMethod;
310              MethodOperand methodOp = MethodOperand.STATIC(target);
311              methodOp.setIsNonReturningCall(true);   // Record the fact that this is a non-returning call.
312              Call.mutate1(inst, CALL, null, IRTools.AC(target.getOffset()), methodOp, Athrow.getClearValue(inst));
313            }
314            break;
315    
316            case MONITORENTER_opcode: {
317              Operand ref = MonitorOp.getClearRef(inst);
318              RVMType refType = ref.getType().peekType();
319              if (refType != null && !refType.getThinLockOffset().isMax()) {
320                RVMMethod target = Entrypoints.inlineLockMethod;
321                Call.mutate2(inst,
322                             CALL,
323                             null,
324                             IRTools.AC(target.getOffset()),
325                             MethodOperand.STATIC(target),
326                             MonitorOp.getClearGuard(inst),
327                             ref,
328                             IRTools.AC(refType.getThinLockOffset()));
329                next = inst.prevInstructionInCodeOrder();
330                if (inst.getBasicBlock().getInfrequent()) container.counter1++;
331                container.counter2++;
332                if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
333                  inline(inst, ir);
334                }
335              } else {
336                RVMMethod target = Entrypoints.lockMethod;
337                Call.mutate1(inst,
338                             CALL,
339                             null,
340                             IRTools.AC(target.getOffset()),
341                             MethodOperand.STATIC(target),
342                             MonitorOp.getClearGuard(inst),
343                             ref);
344              }
345            }
346            break;
347    
348            case MONITOREXIT_opcode: {
349              Operand ref = MonitorOp.getClearRef(inst);
350              RVMType refType = ref.getType().peekType();
351              if (refType != null && !refType.getThinLockOffset().isMax()) {
352                RVMMethod target = Entrypoints.inlineUnlockMethod;
353                Call.mutate2(inst,
354                             CALL,
355                             null,
356                             IRTools.AC(target.getOffset()),
357                             MethodOperand.STATIC(target),
358                             MonitorOp.getClearGuard(inst),
359                             ref,
360                             IRTools.AC(refType.getThinLockOffset()));
361                next = inst.prevInstructionInCodeOrder();
362                if (inst.getBasicBlock().getInfrequent()) container.counter1++;
363                container.counter2++;
364                if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
365                  inline(inst, ir);
366                }
367              } else {
368                RVMMethod target = Entrypoints.unlockMethod;
369                Call.mutate1(inst,
370                             CALL,
371                             null,
372                             IRTools.AC(target.getOffset()),
373                             MethodOperand.STATIC(target),
374                             MonitorOp.getClearGuard(inst),
375                             ref);
376              }
377            }
378            break;
379    
380            case REF_ASTORE_opcode: {
381              if (NEEDS_OBJECT_ASTORE_BARRIER) {
382                RVMMethod target = Entrypoints.objectArrayWriteBarrierMethod;
383                Instruction wb =
384                    Call.create3(CALL,
385                                 null,
386                                 IRTools.AC(target.getOffset()),
387                                 MethodOperand.STATIC(target),
388                                 AStore.getClearGuard(inst),
389                                 AStore.getArray(inst).copy(),
390                                 AStore.getIndex(inst).copy(),
391                                 AStore.getValue(inst).copy());
392                wb.bcIndex = RUNTIME_SERVICES_BCI;
393                wb.position = inst.position;
394                inst.replace(wb);
395                next = wb.prevInstructionInCodeOrder();
396                if (ir.options.H2L_INLINE_WRITE_BARRIER) {
397                  inline(wb, ir, true);
398                }
399              }
400            }
401            break;
402    
403            case BYTE_ASTORE_opcode: {
404              if (NEEDS_BYTE_ASTORE_BARRIER) {
405                primitiveArrayStoreHelper(Entrypoints.byteArrayWriteBarrierMethod, inst, next, ir);
406              }
407            }
408            break;
409    
410            case DOUBLE_ASTORE_opcode: {
411              if (NEEDS_DOUBLE_ASTORE_BARRIER) {
412                primitiveArrayStoreHelper(Entrypoints.doubleArrayWriteBarrierMethod, inst, next, ir);
413              }
414            }
415            break;
416    
417            case FLOAT_ASTORE_opcode: {
418              if (NEEDS_FLOAT_ASTORE_BARRIER) {
419                primitiveArrayStoreHelper(Entrypoints.floatArrayWriteBarrierMethod, inst, next, ir);
420              }
421            }
422            break;
423    
424            case INT_ASTORE_opcode: {
425              if (NEEDS_INT_ASTORE_BARRIER) {
426                primitiveArrayStoreHelper(Entrypoints.intArrayWriteBarrierMethod, inst, next, ir);
427              }
428            }
429            break;
430    
431            case LONG_ASTORE_opcode: {
432              if (NEEDS_LONG_ASTORE_BARRIER) {
433                primitiveArrayStoreHelper(Entrypoints.longArrayWriteBarrierMethod, inst, next, ir);
434              }
435            }
436            break;
437    
438            case SHORT_ASTORE_opcode: {
439              TypeReference type = AStore.getLocation(inst).getElementType();
440              if (NEEDS_SHORT_ASTORE_BARRIER && type.isShortType()) {
441                primitiveArrayStoreHelper(Entrypoints.shortArrayWriteBarrierMethod, inst, next, ir);
442              } else if (NEEDS_CHAR_ASTORE_BARRIER) {
443                if (VM.VerifyAssertions) VM._assert(type.isCharType());
444                primitiveArrayStoreHelper(Entrypoints.charArrayWriteBarrierMethod, inst, next, ir);
445              }
446            }
447            break;
448    
449            case REF_ALOAD_opcode: {
450              if (NEEDS_OBJECT_ALOAD_BARRIER) {
451                RVMMethod target = Entrypoints.objectArrayReadBarrierMethod;
452                Instruction rb =
453                  Call.create2(CALL,
454                               ALoad.getClearResult(inst),
455                               IRTools.AC(target.getOffset()),
456                               MethodOperand.STATIC(target),
457                               ALoad.getClearGuard(inst),
458                               ALoad.getArray(inst).copy(),
459                               ALoad.getIndex(inst).copy());
460                rb.bcIndex = RUNTIME_SERVICES_BCI;
461                rb.position = inst.position;
462                inst.replace(rb);
463                next = rb.prevInstructionInCodeOrder();
464                inline(rb, ir, true);
465              }
466            }
467            break;
468    
469            case PUTFIELD_opcode: {
470              if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
471                LocationOperand loc = PutField.getLocation(inst);
472                FieldReference fieldRef = loc.getFieldRef();
473                if (!fieldRef.getFieldContentsType().isPrimitiveType()) {
474                  // reference PUTFIELD
475                  RVMField field = fieldRef.peekResolvedField();
476                  if (field == null || !field.isUntraced()) {
477                    RVMMethod target = Entrypoints.objectFieldWriteBarrierMethod;
478                    Instruction wb =
479                        Call.create4(CALL,
480                                     null,
481                                     IRTools.AC(target.getOffset()),
482                                     MethodOperand.STATIC(target),
483                                     PutField.getClearGuard(inst),
484                                     PutField.getRef(inst).copy(),
485                                     PutField.getValue(inst).copy(),
486                                     PutField.getOffset(inst).copy(),
487                                     IRTools.IC(fieldRef.getId()));
488                    wb.bcIndex = RUNTIME_SERVICES_BCI;
489                    wb.position = inst.position;
490                    inst.replace(wb);
491                    next = wb.prevInstructionInCodeOrder();
492                    if (ir.options.H2L_INLINE_WRITE_BARRIER) {
493                      inline(wb, ir, true);
494                    }
495                  }
496                } else {
497                  // primitive PUTFIELD
498                  if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isBooleanType()) {
499                    primitiveObjectFieldStoreHelper(Entrypoints.booleanFieldWriteBarrierMethod, inst, next, ir, fieldRef);
500                  } else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isByteType()) {
501                    primitiveObjectFieldStoreHelper(Entrypoints.byteFieldWriteBarrierMethod, inst, next, ir, fieldRef);
502                  } else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isCharType()) {
503                    primitiveObjectFieldStoreHelper(Entrypoints.charFieldWriteBarrierMethod, inst, next, ir, fieldRef);
504                  } else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isDoubleType()) {
505                    primitiveObjectFieldStoreHelper(Entrypoints.doubleFieldWriteBarrierMethod, inst, next, ir, fieldRef);
506                  } else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isFloatType()) {
507                    primitiveObjectFieldStoreHelper(Entrypoints.floatFieldWriteBarrierMethod, inst, next, ir, fieldRef);
508                  } else if (NEEDS_INT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isIntType()) {
509                    primitiveObjectFieldStoreHelper(Entrypoints.intFieldWriteBarrierMethod, inst, next, ir, fieldRef);
510                  } else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isLongType()) {
511                    primitiveObjectFieldStoreHelper(Entrypoints.longFieldWriteBarrierMethod, inst, next, ir, fieldRef);
512                  } else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isShortType()) {
513                    primitiveObjectFieldStoreHelper(Entrypoints.shortFieldWriteBarrierMethod, inst, next, ir, fieldRef);
514                  } else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isWordType()) {
515                    primitiveObjectFieldStoreHelper(Entrypoints.wordFieldWriteBarrierMethod, inst, next, ir, fieldRef);
516                  } else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isAddressType()) {
517                    primitiveObjectFieldStoreHelper(Entrypoints.addressFieldWriteBarrierMethod, inst, next, ir, fieldRef);
518                  } else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isExtentType()) {
519                    primitiveObjectFieldStoreHelper(Entrypoints.extentFieldWriteBarrierMethod, inst, next, ir, fieldRef);
520                  } else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isOffsetType()) {
521                    primitiveObjectFieldStoreHelper(Entrypoints.offsetFieldWriteBarrierMethod, inst, next, ir, fieldRef);
522                  }
523                }
524              }
525            }
526            break;
527    
528            case GETFIELD_opcode: {
529              if (NEEDS_OBJECT_GETFIELD_BARRIER) {
530                LocationOperand loc = GetField.getLocation(inst);
531                FieldReference fieldRef = loc.getFieldRef();
532                if (GetField.getResult(inst).getType().isReferenceType()) {
533                  RVMField field = fieldRef.peekResolvedField();
534                  if (field == null || !field.isUntraced()) {
535                    RVMMethod target = Entrypoints.objectFieldReadBarrierMethod;
536                    Instruction rb =
537                      Call.create3(CALL,
538                                   GetField.getClearResult(inst),
539                                   IRTools.AC(target.getOffset()),
540                                   MethodOperand.STATIC(target),
541                                   GetField.getClearGuard(inst),
542                                   GetField.getRef(inst).copy(),
543                                   GetField.getOffset(inst).copy(),
544                                   IRTools.IC(fieldRef.getId()));
545                    rb.bcIndex = RUNTIME_SERVICES_BCI;
546                    rb.position = inst.position;
547                    inst.replace(rb);
548                    next = rb.prevInstructionInCodeOrder();
549                    inline(rb, ir, true);
550                  }
551                }
552              }
553            }
554            break;
555    
556            case PUTSTATIC_opcode: {
557              if (NEEDS_OBJECT_PUTSTATIC_BARRIER) {
558                LocationOperand loc = PutStatic.getLocation(inst);
559                FieldReference field = loc.getFieldRef();
560                if (!field.getFieldContentsType().isPrimitiveType()) {
561                  RVMMethod target = Entrypoints.objectStaticWriteBarrierMethod;
562                  Instruction wb =
563                      Call.create3(CALL,
564                                   null,
565                                   IRTools.AC(target.getOffset()),
566                                   MethodOperand.STATIC(target),
567                                   PutStatic.getValue(inst).copy(),
568                                   PutStatic.getOffset(inst).copy(),
569                                   IRTools.IC(field.getId()));
570                  wb.bcIndex = RUNTIME_SERVICES_BCI;
571                  wb.position = inst.position;
572                  inst.replace(wb);
573                  next = wb.prevInstructionInCodeOrder();
574                  if (ir.options.H2L_INLINE_WRITE_BARRIER) {
575                    inline(wb, ir, true);
576                  }
577                }
578              }
579            }
580            break;
581    
582            case GETSTATIC_opcode: {
583              if (NEEDS_OBJECT_GETSTATIC_BARRIER) {
584                LocationOperand loc = GetStatic.getLocation(inst);
585                FieldReference field = loc.getFieldRef();
586                if (!field.getFieldContentsType().isPrimitiveType()) {
587                  RVMMethod target = Entrypoints.objectStaticReadBarrierMethod;
588                  Instruction rb =
589                      Call.create2(CALL,
590                                   GetStatic.getClearResult(inst),
591                                   IRTools.AC(target.getOffset()),
592                                   MethodOperand.STATIC(target),
593                                   GetStatic.getOffset(inst).copy(),
594                                   IRTools.IC(field.getId()));
595                  rb.bcIndex = RUNTIME_SERVICES_BCI;
596                  rb.position = inst.position;
597                  inst.replace(rb);
598                  next = rb.prevInstructionInCodeOrder();
599                  inline(rb, ir, true);
600                }
601              }
602            }
603            break;
604    
605            default:
606              break;
607          }
608        }
609    
610        // If we actually inlined anything, clean up the mess
611        if (didSomething) {
612          if (branchOpts == null) {
613            branchOpts = new BranchOptimizations(-1, true, true);
614          }
615          branchOpts.perform(ir, true);
616          if (_os == null) {
617            _os = new Simple(1, false, false, false, false);
618          }
619          _os.perform(ir);
620        }
621        // signal that we do not intend to use the gc in other phases anymore.
622        ir.gc.close();
623      }
624    
625      /**
626       * Inline a call instruction
627       */
628      private void inline(Instruction inst, IR ir) {
629        inline(inst, ir, false);
630      }
631    
632      /**
633       * Inline a call instruction
634       */
635      private void inline(Instruction inst, IR ir, boolean noCalleeExceptions) {
636        // Save and restore inlining control state.
637        // Some options have told us to inline this runtime service,
638        // so we have to be sure to inline it "all the way" not
639        // just 1 level.
640        boolean savedInliningOption = ir.options.INLINE;
641        boolean savedExceptionOption = ir.options.H2L_NO_CALLEE_EXCEPTIONS;
642        ir.options.INLINE = true;
643        ir.options.H2L_NO_CALLEE_EXCEPTIONS = noCalleeExceptions;
644        boolean savedOsrGI = ir.options.OSR_GUARDED_INLINING;
645        ir.options.OSR_GUARDED_INLINING = false;
646        try {
647          InlineDecision inlDec =
648              InlineDecision.YES(Call.getMethod(inst).getTarget(), "Expansion of runtime service");
649          Inliner.execute(inlDec, ir, inst);
650        } finally {
651          ir.options.INLINE = savedInliningOption;
652          ir.options.H2L_NO_CALLEE_EXCEPTIONS = savedExceptionOption;
653          ir.options.OSR_GUARDED_INLINING = savedOsrGI;
654        }
655        didSomething = true;
656      }
657    
658      /**
659       * Helper method to generate call to primitive arrayStore write barrier
660       * @param target entry point for write barrier method
661       * @param inst the current instruction
662       * @param next the next instruction
663       * @param ir the IR
664       */
665      private void primitiveArrayStoreHelper(RVMMethod target, Instruction inst, Instruction next, IR ir) {
666        Instruction wb =
667          Call.create3(CALL,
668                       null,
669                       IRTools.AC(target.getOffset()),
670                       MethodOperand.STATIC(target),
671                       AStore.getClearGuard(inst),
672                       AStore.getArray(inst).copy(),
673                       AStore.getIndex(inst).copy(),
674                       AStore.getValue(inst).copy());
675        wb.bcIndex = RUNTIME_SERVICES_BCI;
676        wb.position = inst.position;
677        inst.replace(wb);
678        next = wb.prevInstructionInCodeOrder();
679        if (ir.options.H2L_INLINE_WRITE_BARRIER) {
680          inline(wb, ir, true);
681        }
682      }
683    
684      /**
685       * Helper method to generate call to primitive putfield write barrier
686       * @param target entry point for write barrier method
687       * @param inst the current instruction
688       * @param next the next instruction
689       * @param ir the IR
690       */
691      private void primitiveObjectFieldStoreHelper(RVMMethod target, Instruction inst, Instruction next, IR ir, FieldReference fieldRef) {
692        Instruction wb =
693          Call.create4(CALL,
694                       null,
695                       IRTools.AC(target.getOffset()),
696                       MethodOperand.STATIC(target),
697                       PutField.getClearGuard(inst),
698                       PutField.getRef(inst).copy(),
699                       PutField.getValue(inst).copy(),
700                       PutField.getOffset(inst).copy(),
701                       IRTools.IC(fieldRef.getId()));
702        wb.bcIndex = RUNTIME_SERVICES_BCI;
703        wb.position = inst.position;
704        inst.replace(wb);
705        next = wb.prevInstructionInCodeOrder();
706        if (ir.options.H2L_INLINE_PRIMITIVE_WRITE_BARRIER) {
707          inline(wb, ir, true);
708        }
709      }
710    }