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 }