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}