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