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