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 }