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 org.jikesrvm.VM;
016 import org.jikesrvm.classloader.RVMArray;
017 import org.jikesrvm.classloader.RVMClass;
018 import org.jikesrvm.classloader.DynamicTypeCheck;
019 import org.jikesrvm.classloader.RVMMethod;
020 import org.jikesrvm.classloader.RVMType;
021 import org.jikesrvm.classloader.TypeReference;
022 import org.jikesrvm.compilers.opt.OptimizingCompilerException;
023 import org.jikesrvm.compilers.opt.ir.ALoad;
024 import org.jikesrvm.compilers.opt.ir.Binary;
025 import org.jikesrvm.compilers.opt.ir.BooleanCmp;
026 import org.jikesrvm.compilers.opt.ir.Call;
027 import org.jikesrvm.compilers.opt.ir.Goto;
028 import org.jikesrvm.compilers.opt.ir.IfCmp;
029 import org.jikesrvm.compilers.opt.ir.IfCmp2;
030 import org.jikesrvm.compilers.opt.ir.InstanceOf;
031 import org.jikesrvm.compilers.opt.ir.Load;
032 import org.jikesrvm.compilers.opt.ir.Move;
033 import org.jikesrvm.compilers.opt.ir.BasicBlock;
034 import org.jikesrvm.compilers.opt.ir.IR;
035 import org.jikesrvm.compilers.opt.ir.Instruction;
036 import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
037 import static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
038 import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR;
039 import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
040 import static org.jikesrvm.compilers.opt.ir.Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB;
041 import static org.jikesrvm.compilers.opt.ir.Operators.GET_DOES_IMPLEMENT_FROM_TIB;
042 import static org.jikesrvm.compilers.opt.ir.Operators.GET_SUPERCLASS_IDS_FROM_TIB;
043 import static org.jikesrvm.compilers.opt.ir.Operators.GET_TYPE_FROM_TIB;
044 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
045 import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COMBINE;
046 import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
047 import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
048 import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND;
049 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
050 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
051 import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
052 import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE;
053 import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
054 import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
055 import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
056 import static org.jikesrvm.compilers.opt.ir.Operators.TRAP;
057 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD;
058 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
059 import org.jikesrvm.compilers.opt.ir.StoreCheck;
060 import org.jikesrvm.compilers.opt.ir.Trap;
061 import org.jikesrvm.compilers.opt.ir.TypeCheck;
062 import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
063 import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
064 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
065 import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
066 import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
067 import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand;
068 import org.jikesrvm.compilers.opt.ir.operand.Operand;
069 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
070 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
071 import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
072 import org.jikesrvm.runtime.Entrypoints;
073 import org.vmmagic.unboxed.Address;
074 import org.vmmagic.unboxed.Offset;
075
076 /**
077 * Expansion of Dynamic Type Checking operations.
078 *
079 * @see DynamicTypeCheck
080 */
081 abstract class DynamicTypeCheckExpansion extends ConvertToLowLevelIR {
082
083 /**
084 * Expand an instanceof instruction into the LIR sequence that implements
085 * the dynamic type check. Ref may contain a null ptr at runtime.
086 *
087 * @param s an INSTANCEOF or INSTANCEOF_UNRESOLVED instruction to expand
088 * @param ir the enclosing IR
089 * @return the last Instruction in the generated LIR sequence.
090 */
091 static Instruction instanceOf(Instruction s, IR ir) {
092 RegisterOperand result = InstanceOf.getClearResult(s);
093 TypeReference LHStype = InstanceOf.getType(s).getTypeRef();
094 Operand ref = InstanceOf.getClearRef(s);
095 Instruction next = s.nextInstructionInCodeOrder();
096 if (next.operator() == INT_IFCMP &&
097 IfCmp.getVal1(next) instanceof RegisterOperand &&
098 result.similar(IfCmp.getVal1(next))) {
099 // The result of instanceof is being consumed by a conditional branch.
100 // Optimize this case by generating a branching type check
101 // instead of producing a value.
102 // TODO: This is really not safe: suppose the if is NOT the
103 // only use of the result of the instanceof.
104 // The way to fix this is to add ifInstanceOf and ifNotInstanceOf
105 // operators to the IR and have Simple transform
106 // instanceof, intIfCmp based on the U/D chains.
107 // See defect 2114.
108 Operand val2 = IfCmp.getVal2(next);
109 if (VM.VerifyAssertions) VM._assert(val2.isIntConstant());
110 int ival2 = ((IntConstantOperand) val2).value;
111 ConditionOperand cond = IfCmp.getCond(next);
112 boolean branchCondition =
113 (((ival2 == 0) && (cond.isNOT_EQUAL() || cond.isLESS_EQUAL())) ||
114 ((ival2 == 1) && (cond.isEQUAL() || cond.isGREATER_EQUAL())));
115 BasicBlock branchBB = next.getBranchTarget();
116 RegisterOperand oldGuard = IfCmp.getGuardResult(next);
117 next.remove();
118 BasicBlock fallThroughBB = fallThroughBB(s, ir);
119 BasicBlock falseBranch = branchCondition ? fallThroughBB : branchBB;
120 BasicBlock trueBranch = branchCondition ? branchBB : fallThroughBB;
121 BranchProfileOperand bp = IfCmp.getClearBranchProfile(next);
122 if (branchCondition) bp = bp.flip();
123 Instruction nullComp =
124 IfCmp.create(REF_IFCMP,
125 oldGuard.copyRO(),
126 ref.copy(),
127 new NullConstantOperand(),
128 ConditionOperand.EQUAL(),
129 falseBranch.makeJumpTarget(),
130 BranchProfileOperand.unlikely());
131 s.insertBefore(nullComp);
132 BasicBlock myBlock = s.getBasicBlock();
133 BasicBlock instanceOfBlock = myBlock.splitNodeAt(nullComp, ir);
134 myBlock.insertOut(instanceOfBlock);
135 myBlock.insertOut(falseBranch);
136 ir.cfg.linkInCodeOrder(myBlock, instanceOfBlock);
137 Operand RHStib = getTIB(s, ir, ref, oldGuard.copyRO());
138 return generateBranchingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, trueBranch, falseBranch, oldGuard, bp);
139 } else {
140 // Not a branching pattern
141 RegisterOperand guard = ir.regpool.makeTempValidation();
142 BasicBlock instanceOfBlock = s.getBasicBlock().segregateInstruction(s, ir);
143 BasicBlock prevBB = instanceOfBlock.prevBasicBlockInCodeOrder();
144 BasicBlock nextBB = instanceOfBlock.nextBasicBlockInCodeOrder();
145 BasicBlock nullCaseBB = instanceOfBlock.createSubBlock(s.bcIndex, ir, .01f);
146 prevBB.appendInstruction(IfCmp.create(REF_IFCMP,
147 guard,
148 ref.copy(),
149 new NullConstantOperand(),
150 ConditionOperand.EQUAL(),
151 nullCaseBB.makeJumpTarget(),
152 BranchProfileOperand.unlikely()));
153 nullCaseBB.appendInstruction(Move.create(INT_MOVE, result.copyD2D(), IC(0)));
154 nullCaseBB.appendInstruction(Goto.create(GOTO, nextBB.makeJumpTarget()));
155 // Stitch together the CFG; add nullCaseBB to the end of code array.
156 prevBB.insertOut(nullCaseBB);
157 nullCaseBB.insertOut(nextBB);
158 ir.cfg.addLastInCodeOrder(nullCaseBB);
159 Operand RHStib = getTIB(s, ir, ref, guard.copyD2U());
160 return generateValueProducingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, result);
161 }
162 }
163
164 /**
165 * Expand an instanceof instruction into the LIR sequence that implements
166 * the dynamic type check. Ref is known to never contain a null ptr at
167 * runtime.
168 *
169 * @param s an INSTANCEOF_NOTNULL instruction to expand
170 * @param ir the enclosing IR
171 * @return the last Instruction in the generated LIR sequence.
172 */
173 static Instruction instanceOfNotNull(Instruction s, IR ir) {
174 RegisterOperand result = InstanceOf.getClearResult(s);
175 TypeReference LHStype = InstanceOf.getType(s).getTypeRef();
176 Operand ref = InstanceOf.getClearRef(s);
177 Operand guard = InstanceOf.getClearGuard(s);
178 Instruction next = s.nextInstructionInCodeOrder();
179 if (next.operator() == INT_IFCMP &&
180 IfCmp.getVal1(next) instanceof RegisterOperand &&
181 result.similar(IfCmp.getVal1(next))) {
182 // The result of instanceof is being consumed by a conditional branch.
183 // Optimize this case by generating a branching type
184 // check instead of producing a value.
185 Operand val2 = IfCmp.getVal2(next);
186 if (VM.VerifyAssertions) {
187 VM._assert(val2.isIntConstant());
188 }
189 int ival2 = ((IntConstantOperand) val2).value;
190 ConditionOperand cond = IfCmp.getCond(next);
191 boolean branchCondition =
192 (((ival2 == 0) && (cond.isNOT_EQUAL() || cond.isLESS_EQUAL())) ||
193 ((ival2 == 1) && (cond.isEQUAL() || cond.isGREATER_EQUAL())));
194 BasicBlock branchBB = next.getBranchTarget();
195 RegisterOperand oldGuard = IfCmp.getGuardResult(next);
196 next.remove();
197 BasicBlock fallThroughBB = fallThroughBB(s, ir);
198 Operand RHStib = getTIB(s, ir, ref, guard);
199 if (branchCondition) {
200 return generateBranchingTypeCheck(s,
201 ir,
202 ref.copy(),
203 LHStype,
204 RHStib,
205 branchBB,
206 fallThroughBB,
207 oldGuard,
208 IfCmp.getClearBranchProfile(next).flip());
209 } else {
210 return generateBranchingTypeCheck(s,
211 ir,
212 ref.copy(),
213 LHStype,
214 RHStib,
215 fallThroughBB,
216 branchBB,
217 oldGuard,
218 IfCmp.getClearBranchProfile(next));
219 }
220 } else {
221 // Not a branching pattern
222 Operand RHStib = getTIB(s, ir, ref, guard);
223 return generateValueProducingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, result);
224 }
225 }
226
227 /**
228 * Expand a checkcast instruction into the LIR sequence that implements the
229 * dynamic type check, raising a ClassCastException when the type check
230 * fails. Ref may contain a null ptr at runtime.
231 *
232 * @param s a CHECKCAST or CHECKCAST_UNRESOLVED instruction to expand
233 * @param ir the enclosing IR
234 * @return the last Instruction in the generated LIR sequence.
235 */
236 static Instruction checkcast(Instruction s, IR ir) {
237 Operand ref = TypeCheck.getClearRef(s);
238 TypeReference LHStype = TypeCheck.getType(s).getTypeRef();
239 RegisterOperand guard = ir.regpool.makeTempValidation();
240 Instruction nullCond =
241 IfCmp.create(REF_IFCMP,
242 guard,
243 ref.copy(),
244 new NullConstantOperand(),
245 ConditionOperand.EQUAL(),
246 null,
247 // KLUDGE...we haven't created the block yet!
248 new BranchProfileOperand());
249 s.insertBefore(nullCond);
250 BasicBlock myBlock = s.getBasicBlock();
251 BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
252 BasicBlock instanceOfBlock = myBlock.splitNodeAt(nullCond, ir);
253 BasicBlock succBlock = instanceOfBlock.splitNodeAt(s, ir);
254 succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
255 IfCmp.setTarget(nullCond, succBlock.makeJumpTarget()); // fixup KLUDGE
256 myBlock.insertOut(instanceOfBlock);
257 myBlock.insertOut(succBlock);
258 instanceOfBlock.insertOut(failBlock);
259 instanceOfBlock.insertOut(succBlock);
260 ir.cfg.linkInCodeOrder(myBlock, instanceOfBlock);
261 ir.cfg.linkInCodeOrder(instanceOfBlock, succBlock);
262 ir.cfg.addLastInCodeOrder(failBlock);
263 Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.CheckCast());
264 raiseError.copyPosition(s);
265 failBlock.appendInstruction(raiseError);
266 Operand RHStib = getTIB(s, ir, ref, guard.copyD2U());
267 return generateBranchingTypeCheck(s,
268 ir,
269 ref.copy(),
270 LHStype,
271 RHStib,
272 succBlock,
273 failBlock,
274 guard.copyRO(),
275 BranchProfileOperand.never());
276 }
277
278 /**
279 * Expand a checkcast instruction into the LIR sequence that implements the
280 * dynamic type check, raising a ClassCastException when the type check
281 * fails. Ref is known to never contain a null ptr at runtime.
282 *
283 * @param s a CHECKCAST_NOTNULL instruction to expand
284 * @param ir the enclosing IR
285 * @return the last Instruction in the generated LIR sequence.
286 */
287 static Instruction checkcastNotNull(Instruction s, IR ir) {
288 Operand ref = TypeCheck.getClearRef(s);
289 TypeReference LHStype = TypeCheck.getType(s).getTypeRef();
290 Operand guard = TypeCheck.getClearGuard(s);
291 BasicBlock myBlock = s.getBasicBlock();
292 BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
293 BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
294 succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
295 myBlock.insertOut(failBlock);
296 myBlock.insertOut(succBlock);
297 ir.cfg.linkInCodeOrder(myBlock, succBlock);
298 ir.cfg.addLastInCodeOrder(failBlock);
299 Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.CheckCast());
300 raiseError.copyPosition(s);
301 failBlock.appendInstruction(raiseError);
302 Operand RHStib = getTIB(s, ir, ref, guard);
303 return generateBranchingTypeCheck(s,
304 ir,
305 ref.copy(),
306 LHStype,
307 RHStib,
308 succBlock,
309 failBlock,
310 ir.regpool.makeTempValidation(),
311 BranchProfileOperand.never());
312 }
313
314 /**
315 * Expand a checkcastInterface instruction into the LIR sequence that
316 * implements the dynamic type check, raising an IncompataibleClassChangeError
317 * if the type check fails.
318 * Ref is known to never contain a null ptr at runtime.
319 *
320 * @param s a MUST_IMPLEMENT_INTERFACE instruction to expand
321 * @param ir the enclosing IR
322 * @return the last Instruction in the generated LIR sequence.
323 */
324 static Instruction mustImplementInterface(Instruction s, IR ir) {
325 Operand ref = TypeCheck.getClearRef(s);
326 RVMClass LHSClass = (RVMClass) TypeCheck.getType(s).getVMType();
327 if (VM.VerifyAssertions) VM._assert(LHSClass != null, "Should be resolvable...");
328 int interfaceIndex = LHSClass.getDoesImplementIndex();
329 int interfaceMask = LHSClass.getDoesImplementBitMask();
330 Operand guard = TypeCheck.getClearGuard(s);
331 BasicBlock myBlock = s.getBasicBlock();
332 BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
333 BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
334 succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
335 myBlock.insertOut(failBlock);
336 myBlock.insertOut(succBlock);
337 ir.cfg.linkInCodeOrder(myBlock, succBlock);
338 ir.cfg.addLastInCodeOrder(failBlock);
339 Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.MustImplement());
340 raiseError.copyPosition(s);
341 failBlock.appendInstruction(raiseError);
342
343 Operand RHStib = getTIB(s, ir, ref, guard);
344 RegisterOperand doesImpl = InsertUnary(s, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
345
346 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
347 RegisterOperand doesImplLength =
348 InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
349 Instruction lengthCheck =
350 IfCmp.create(INT_IFCMP,
351 ir.regpool.makeTempValidation(),
352 doesImplLength,
353 IC(interfaceIndex),
354 ConditionOperand.LESS_EQUAL(),
355 failBlock.makeJumpTarget(),
356 BranchProfileOperand.never());
357 s.insertBefore(lengthCheck);
358 myBlock.splitNodeWithLinksAt(lengthCheck, ir);
359 myBlock.insertOut(failBlock); // required due to splitNode!
360 }
361 RegisterOperand entry =
362 InsertLoadOffset(s,
363 ir,
364 INT_LOAD,
365 TypeReference.Int,
366 doesImpl,
367 Offset.fromIntZeroExtend(interfaceIndex << 2),
368 new LocationOperand(TypeReference.Int),
369 TG());
370 RegisterOperand bit = insertBinary(s, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
371 IfCmp.mutate(s,
372 INT_IFCMP,
373 ir.regpool.makeTempValidation(),
374 bit,
375 IC(0),
376 ConditionOperand.EQUAL(),
377 failBlock.makeJumpTarget(),
378 BranchProfileOperand.never());
379 return s;
380 }
381
382 /**
383 * Expand an object array store check into the LIR sequence that
384 * implements it.
385 *
386 * @param s an OBJARRAY_STORE_CHECK instruction to expand
387 * @param ir the enclosing IR
388 * @param couldBeNull is it possible that the element being stored is null?
389 * @return the last Instruction in the generated LIR sequence.
390 */
391 static Instruction arrayStoreCheck(Instruction s, IR ir, boolean couldBeNull) {
392 RegisterOperand guardResult = StoreCheck.getGuardResult(s);
393 Operand arrayRef = StoreCheck.getClearRef(s);
394 Operand elemRef = StoreCheck.getClearVal(s);
395 Operand guard = StoreCheck.getClearGuard(s);
396 if (elemRef instanceof NullConstantOperand) {
397 Instruction continueAt = s.prevInstructionInCodeOrder();
398 s.remove();
399 return continueAt;
400 }
401 BasicBlock myBlock = s.getBasicBlock();
402 BasicBlock contBlock = myBlock.splitNodeAt(s, ir);
403 BasicBlock trapBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
404 BasicBlock curBlock = myBlock;
405 Move.mutate(s, GUARD_MOVE, guardResult, new TrueGuardOperand());
406
407 // Set up a block with a trap instruction that we can jump to if the
408 // store check fails
409 Instruction trap = Trap.create(TRAP, null, TrapCodeOperand.StoreCheck());
410 trap.copyPosition(s);
411 trapBlock.appendInstruction(trap);
412 ir.cfg.addLastInCodeOrder(trapBlock);
413
414 Operand rhsGuard = guard;
415 if (couldBeNull) {
416 // if rhs is null, then the checkcast succeeds
417 rhsGuard = ir.regpool.makeTempValidation();
418 contBlock.prependInstruction(Binary.create(GUARD_COMBINE,
419 guardResult.copyRO(),
420 guardResult.copyRO(),
421 rhsGuard.copy()));
422 curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
423 rhsGuard.asRegister(),
424 elemRef,
425 new NullConstantOperand(),
426 ConditionOperand.EQUAL(),
427 contBlock.makeJumpTarget(),
428 new BranchProfileOperand()));
429 curBlock.insertOut(contBlock);
430 curBlock = advanceBlock(s.bcIndex, curBlock, ir);
431 }
432
433 // Find out what we think the compile time type of the lhs is.
434 // Based on this, we can do one of several things:
435 // (1) If the compile time element type is a final proper class, then a
436 // TIB comparision of the runtime elemRef type and the
437 // compile time element type is definitive.
438 // (2) If the compile time type is known to be the declared type,
439 // then inject a short-circuit test to see if the
440 // runtime lhs type is the same as the compile-time lhs type.
441 // (3) If the compile time element type is a proper class other than
442 // java.lang.Object, then a subclass test of the runtime LHS elem type
443 // and the runtime elemRef type is definitive. Note: we must exclude
444 // java.lang.Object because if the compile time element type is
445 // java.lang.Object, then the runtime-element type might actually be
446 // an interface (ie not a proper class), and we won't be testing the right thing!
447 // If we think the compile time type is JavaLangObjectType then
448 // we lost type information due to unloaded classes causing
449 // imprecise meets. This should only happen once in a blue moon,
450 // so don't bother trying anything clever when it does.
451 RVMType compType = arrayRef.getType().peekType();
452 if (compType != null && !compType.isJavaLangObjectType()) {
453 // optionally (1) from above
454 if (compType.getDimensionality() == 1) {
455 RVMClass etc = (RVMClass) compType.asArray().getElementType();
456 if (etc.isResolved() && etc.isFinal()) {
457 if (VM.VerifyAssertions) VM._assert(!etc.isInterface());
458 Operand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());
459 Operand etTIB = getTIB(curBlock.lastInstruction(), ir, etc);
460 curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
461 guardResult.copyRO(),
462 rhsTIB,
463 etTIB,
464 ConditionOperand.NOT_EQUAL(),
465 trapBlock.makeJumpTarget(),
466 BranchProfileOperand.never()));
467 curBlock.insertOut(trapBlock);
468 curBlock.insertOut(contBlock);
469 ir.cfg.linkInCodeOrder(curBlock, contBlock);
470 return curBlock.lastInstruction();
471 }
472 }
473
474 // optionally (2) from above
475 Operand lhsTIB = getTIB(curBlock.lastInstruction(), ir, arrayRef, guard);
476 if (((arrayRef instanceof RegisterOperand) && ((RegisterOperand) arrayRef).isDeclaredType()) ||
477 compType == RVMType.JavaLangObjectArrayType) {
478 Operand declTIB = getTIB(curBlock.lastInstruction(), ir, compType);
479 curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
480 guardResult.copyRO(),
481 declTIB,
482 lhsTIB,
483 ConditionOperand.EQUAL(),
484 contBlock.makeJumpTarget(),
485 new BranchProfileOperand()));
486 curBlock.insertOut(contBlock);
487 curBlock = advanceBlock(s.bcIndex, curBlock, ir);
488 }
489
490 // On our way to doing (3) from above attempt another short-circuit.
491 // If lhsElemTIB == rhsTIB, then we are done.
492 Operand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());
493 RegisterOperand lhsElemTIB =
494 InsertUnary(curBlock.lastInstruction(),
495 ir,
496 GET_ARRAY_ELEMENT_TIB_FROM_TIB,
497 TypeReference.TIB,
498 lhsTIB.copy());
499 curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
500 guardResult.copyRO(),
501 rhsTIB,
502 lhsElemTIB,
503 ConditionOperand.EQUAL(),
504 contBlock.makeJumpTarget(),
505 new BranchProfileOperand()));
506 curBlock.insertOut(contBlock);
507 curBlock = advanceBlock(s.bcIndex, curBlock, ir);
508
509 // Optionally (3) from above
510 if (compType.getDimensionality() == 1) {
511 RVMClass etc = (RVMClass) compType.asArray().getElementType();
512 if (etc.isResolved() && !etc.isInterface() && !etc.isJavaLangObjectType()) {
513 RegisterOperand lhsElemType =
514 InsertUnary(curBlock.lastInstruction(),
515 ir,
516 GET_TYPE_FROM_TIB,
517 TypeReference.Type,
518 lhsElemTIB.copyU2U());
519 RegisterOperand rhsSuperclassIds =
520 InsertUnary(curBlock.lastInstruction(),
521 ir,
522 GET_SUPERCLASS_IDS_FROM_TIB,
523 TypeReference.ShortArray,
524 rhsTIB.copy());
525 RegisterOperand lhsElemDepth =
526 getField(curBlock.lastInstruction(), ir, lhsElemType, Entrypoints.depthField, TG());
527 RegisterOperand rhsSuperclassIdsLength =
528 InsertGuardedUnary(curBlock.lastInstruction(),
529 ir,
530 ARRAYLENGTH,
531 TypeReference.Int,
532 rhsSuperclassIds.copyD2U(),
533 TG());
534 curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
535 guardResult.copyRO(),
536 lhsElemDepth,
537 rhsSuperclassIdsLength,
538 ConditionOperand.GREATER_EQUAL(),
539 trapBlock.makeJumpTarget(),
540 BranchProfileOperand.never()));
541 curBlock.insertOut(trapBlock);
542 curBlock = advanceBlock(s.bcIndex, curBlock, ir);
543
544 RegisterOperand lhsElemId =
545 getField(curBlock.lastInstruction(), ir, lhsElemType.copyD2U(), Entrypoints.idField, TG());
546 RegisterOperand refCandidate = ir.regpool.makeTemp(TypeReference.Short);
547 LocationOperand loc = new LocationOperand(TypeReference.Short);
548 if (LOWER_ARRAY_ACCESS) {
549 RegisterOperand lhsDepthOffset =
550 insertBinary(curBlock.lastInstruction(),
551 ir,
552 INT_SHL,
553 TypeReference.Int,
554 lhsElemDepth.copyD2U(),
555 IC(1));
556 lhsDepthOffset =
557 InsertUnary(curBlock.lastInstruction(),
558 ir,
559 INT_2ADDRZerExt,
560 TypeReference.Offset,
561 lhsDepthOffset.copy());
562 curBlock.appendInstruction(Load.create(USHORT_LOAD,
563 refCandidate,
564 rhsSuperclassIds,
565 lhsDepthOffset,
566 loc,
567 TG()));
568 } else {
569 curBlock.appendInstruction(ALoad.create(USHORT_ALOAD,
570 refCandidate,
571 rhsSuperclassIds,
572 lhsElemDepth.copyRO(),
573 loc,
574 TG()));
575 }
576 curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
577 guardResult.copyRO(),
578 refCandidate.copyD2U(),
579 lhsElemId,
580 ConditionOperand.NOT_EQUAL(),
581 trapBlock.makeJumpTarget(),
582 BranchProfileOperand.never()));
583 curBlock.insertOut(trapBlock);
584 curBlock.insertOut(contBlock);
585 ir.cfg.linkInCodeOrder(curBlock, contBlock);
586 return curBlock.lastInstruction();
587 }
588 }
589 }
590
591 // Call RuntimeEntrypoints.checkstore.
592 RVMMethod target = Entrypoints.checkstoreMethod;
593 Instruction call =
594 Call.create2(CALL,
595 null,
596 AC(target.getOffset()),
597 MethodOperand.STATIC(target),
598 rhsGuard.copy(),
599 arrayRef.copy(),
600 elemRef.copy());
601 call.copyPosition(s);
602 curBlock.appendInstruction(call);
603 curBlock.insertOut(contBlock);
604 ir.cfg.linkInCodeOrder(curBlock, contBlock);
605 return callHelper(call, ir);
606 }
607
608 /**
609 * Generate a value-producing dynamic type check.
610 * This routine assumes that the CFG and code order are
611 * already correctly established.
612 * This routine must either remove s or mutuate it.
613 *
614 * @param s The Instruction that is to be replaced by
615 * a value producing type check
616 * @param ir The IR containing the instruction to be expanded.
617 * @param RHSobj The RegisterOperand containing the rhs object.
618 * @param LHStype The RVMType to be tested against.
619 * @param RHStib The Operand containing the TIB of the rhs.
620 * @param result The RegisterOperand that the result of dynamic
621 * type check is to be stored in.
622 * @return the opt instruction immediately before the
623 * instruction to continue expansion.
624 */
625 private static Instruction generateValueProducingTypeCheck(Instruction s, IR ir, Operand RHSobj,
626 TypeReference LHStype, Operand RHStib,
627 RegisterOperand result) {
628 // Is LHStype a class?
629 if (LHStype.isClassType()) {
630 RVMClass LHSclass = (RVMClass) LHStype.peekType();
631 if (LHSclass != null && LHSclass.isResolved()) {
632 // Cases 4, 5, and 6 of DynamicTypeCheck: LHSclass is a
633 // resolved class or interface
634 if (LHSclass.isInterface()) {
635 // A resolved interface (case 4)
636 int interfaceIndex = LHSclass.getDoesImplementIndex();
637 int interfaceMask = LHSclass.getDoesImplementBitMask();
638 RegisterOperand doesImpl =
639 InsertUnary(s, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
640 RegisterOperand entry =
641 InsertLoadOffset(s,
642 ir,
643 INT_LOAD,
644 TypeReference.Int,
645 doesImpl,
646 Offset.fromIntZeroExtend(interfaceIndex << 2),
647 new LocationOperand(TypeReference.Int),
648 TG());
649 RegisterOperand bit = insertBinary(s, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
650 //save to use the cheaper ADDR version of BOOLEAN_CMP
651 s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
652 result,
653 bit,
654 AC(Address.zero()),
655 ConditionOperand.NOT_EQUAL(),
656 new BranchProfileOperand()));
657
658 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
659 RegisterOperand doesImplLength =
660 InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copy(), TG());
661 RegisterOperand boundscheck = ir.regpool.makeTempInt();
662 //save to use the cheaper ADDR version of BOOLEAN_CMP
663 s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
664 boundscheck,
665 doesImplLength,
666 AC(Address.fromIntSignExtend(interfaceIndex)),
667 ConditionOperand.GREATER(),
668 new BranchProfileOperand()));
669 s.insertBefore(Binary.create(INT_AND, result.copyD2D(), result.copyD2U(), boundscheck.copyD2U()));
670 }
671 Instruction continueAt = s.prevInstructionInCodeOrder();
672 s.remove();
673 return continueAt;
674 } else {
675 // A resolved class (cases 5 and 6 in DynamicTypeCheck)
676 if (LHSclass.isFinal()) {
677 // For a final class, we can do a PTR compare of
678 // rhsTIB and the TIB of the class
679 Operand classTIB = getTIB(s, ir, LHSclass);
680 BooleanCmp.mutate(s,
681 BOOLEAN_CMP_ADDR,
682 result,
683 RHStib,
684 classTIB,
685 ConditionOperand.EQUAL(),
686 new BranchProfileOperand());
687 return s.prevInstructionInCodeOrder();
688 } else {
689 // Do the full blown case 5 or 6 typecheck.
690 int LHSDepth = LHSclass.getTypeDepth();
691 int LHSId = LHSclass.getId();
692 RegisterOperand superclassIds =
693 InsertUnary(s, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
694 RegisterOperand refCandidate =
695 InsertLoadOffset(s,
696 ir,
697 USHORT_LOAD,
698 TypeReference.Short,
699 superclassIds,
700 Offset.fromIntZeroExtend(LHSDepth << 1),
701 new LocationOperand(TypeReference.Short),
702 TG());
703 //save to use the cheaper ADDR version of BOOLEAN_CMP
704 s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
705 result,
706 refCandidate,
707 AC(Address.fromIntZeroExtend(LHSId)),
708 ConditionOperand.EQUAL(),
709 new BranchProfileOperand()));
710 if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
711 RegisterOperand superclassIdsLength =
712 InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
713 RegisterOperand boundscheck = ir.regpool.makeTempInt();
714 //save to use the cheaper ADDR version of BOOLEAN_CMP
715 s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
716 boundscheck,
717 superclassIdsLength,
718 AC(Address.fromIntSignExtend(LHSDepth)),
719 ConditionOperand.GREATER(),
720 new BranchProfileOperand()));
721 s.insertBefore(Binary.create(INT_AND, result.copyD2D(), result.copyD2U(), boundscheck.copyD2U()));
722 }
723 Instruction continueAt = s.prevInstructionInCodeOrder();
724 s.remove();
725 return continueAt;
726 }
727 }
728 } else {
729 // A non-resolved class or interface.
730 // We expect these to be extremely uncommon in opt code in AOS.
731 // Mutate s into a call to RuntimeEntrypoints.instanceOf
732 RVMMethod target = Entrypoints.instanceOfMethod;
733 Call.mutate2(s,
734 CALL,
735 result,
736 AC(target.getOffset()),
737 MethodOperand.STATIC(target),
738 RHSobj,
739 IC(LHStype.getId()));
740 return callHelper(s, ir);
741 }
742 }
743 if (LHStype.isArrayType()) {
744 // Case 2 of DynamicTypeCheck: LHS is an array.
745 RVMArray LHSArray = (RVMArray) LHStype.peekType();
746 if (LHSArray != null) {
747 RVMType innermostElementType = LHSArray.getInnermostElementType();
748 if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() ||
749 (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
750 // [^k of primitive or [^k of final class. Just like final classes,
751 // a PTR compare of rhsTIB and the TIB of the class gives the answer.
752 Operand classTIB = getTIB(s, ir, LHSArray);
753 BooleanCmp.mutate(s,
754 BOOLEAN_CMP_ADDR,
755 result,
756 RHStib,
757 classTIB,
758 ConditionOperand.EQUAL(),
759 new BranchProfileOperand());
760 return s;
761 }
762 }
763 // We're going to have to branch anyways, so reduce to a branching case
764 // and do the real work there.
765 return convertToBranchingTypeCheck(s, ir, RHSobj, LHStype, RHStib, result);
766 }
767 OptimizingCompilerException.UNREACHABLE();
768 return null;
769 }
770
771 /**
772 * Generate wrapper around branching type check to get a
773 * value producing type check.
774 * @param s The Instruction that is to be replaced by
775 * a value producing type check
776 * @param ir The IR containing the instruction to be expanded.
777 * @param RHSobj The RegisterOperand containing the rhs object.
778 * @param LHStype The TypeReference to be tested against.
779 * @param RHStib The Operand containing the TIB of the rhs.
780 * @param result The RegisterOperand that the result of dynamic
781 * @return the opt instruction immediately before the instruction to
782 * continue expansion.
783 */
784 private static Instruction convertToBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj,
785 TypeReference LHStype, Operand RHStib,
786 RegisterOperand result) {
787 BasicBlock myBlock = s.getBasicBlock();
788 BasicBlock contBlock = myBlock.splitNodeAt(s, ir);
789 BasicBlock trueBlock = myBlock.createSubBlock(s.bcIndex, ir);
790 BasicBlock falseBlock = myBlock.createSubBlock(s.bcIndex, ir);
791 myBlock.insertOut(trueBlock);
792 myBlock.insertOut(falseBlock);
793 trueBlock.insertOut(contBlock);
794 falseBlock.insertOut(contBlock);
795 ir.cfg.linkInCodeOrder(myBlock, trueBlock);
796 ir.cfg.linkInCodeOrder(trueBlock, falseBlock);
797 ir.cfg.linkInCodeOrder(falseBlock, contBlock);
798 trueBlock.appendInstruction(Move.create(INT_MOVE, result, IC(1)));
799 trueBlock.appendInstruction(Goto.create(GOTO, contBlock.makeJumpTarget()));
800 falseBlock.appendInstruction(Move.create(INT_MOVE, result.copyD2D(), IC(0)));
801 return generateBranchingTypeCheck(s,
802 ir,
803 RHSobj,
804 LHStype,
805 RHStib,
806 trueBlock,
807 falseBlock,
808 ir.regpool.makeTempValidation(),
809 new BranchProfileOperand());
810 }
811
812 /**
813 * Generate a branching dynamic type check.
814 * This routine assumes that the CFG and code order are already
815 * correctly established.
816 * This routine must either remove s or mutuate it.
817 *
818 * @param s The Instruction that is to be replaced by a
819 * branching type check
820 * @param ir The IR containing the instruction to be expanded.
821 * @param RHSobj The RegisterOperand containing the rhs object.
822 * @param LHStype The TypeReference to be tested against.
823 * @param RHStib The Operand containing the TIB of the rhs.
824 * @param trueBlock The BasicBlock to continue at if the typecheck
825 * evaluates to true
826 * @param falseBlock The BasicBlock to continue at if the typecheck
827 * evaluates to false.
828 * @param falseProb The probability that typecheck will branch to the falseBlock
829 * @return the opt instruction immediately before the instruction to
830 * continue expansion.
831 */
832 private static Instruction generateBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj,
833 TypeReference LHStype, Operand RHStib,
834 BasicBlock trueBlock, BasicBlock falseBlock,
835 RegisterOperand oldGuard,
836 BranchProfileOperand falseProb) {
837 Instruction continueAt = Goto.create(GOTO, trueBlock.makeJumpTarget());
838 continueAt.copyPosition(s);
839 s.insertBefore(continueAt);
840 s.remove();
841
842 if (LHStype.isClassType()) {
843 RVMClass LHSclass = (RVMClass) LHStype.peekType();
844 if (LHSclass != null && LHSclass.isResolved()) {
845 // Cases 4, 5, and 6 of DynamicTypeCheck: LHSclass is a resolved
846 // class or interface
847 if (LHSclass.isInterface()) {
848 // A resolved interface (case 4)
849 int interfaceIndex = LHSclass.getDoesImplementIndex();
850 int interfaceMask = LHSclass.getDoesImplementBitMask();
851 RegisterOperand doesImpl =
852 InsertUnary(continueAt, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
853
854 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
855 RegisterOperand doesImplLength =
856 InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
857 Instruction lengthCheck =
858 IfCmp.create(INT_IFCMP,
859 oldGuard,
860 doesImplLength,
861 IC(interfaceIndex),
862 ConditionOperand.LESS_EQUAL(),
863 falseBlock.makeJumpTarget(),
864 BranchProfileOperand.unlikely());
865 if (oldGuard != null) {
866 oldGuard = oldGuard.copyD2D();
867 }
868 continueAt.insertBefore(lengthCheck);
869 BasicBlock oldBlock = continueAt.getBasicBlock();
870 oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
871 oldBlock.insertOut(falseBlock); // required due to splitNode!
872 }
873 RegisterOperand entry =
874 InsertLoadOffset(continueAt,
875 ir,
876 INT_LOAD,
877 TypeReference.Int,
878 doesImpl,
879 Offset.fromIntZeroExtend(interfaceIndex << 2),
880 new LocationOperand(TypeReference.Int),
881 TG());
882 RegisterOperand bit =
883 insertBinary(continueAt, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
884 continueAt.insertBefore(IfCmp.create(INT_IFCMP,
885 oldGuard,
886 bit,
887 IC(0),
888 ConditionOperand.EQUAL(),
889 falseBlock.makeJumpTarget(),
890 falseProb));
891 return continueAt;
892 } else {
893 // A resolved class (cases 5 and 6 in DynamicTypeCheck)
894 if (LHSclass.isFinal()) {
895 // For a final class, we can do a PTR compare of
896 // rhsTIB and the TIB of the class
897 Operand classTIB = getTIB(continueAt, ir, LHSclass);
898 continueAt.insertBefore(IfCmp.create(REF_IFCMP,
899 oldGuard,
900 RHStib,
901 classTIB,
902 ConditionOperand.NOT_EQUAL(),
903 falseBlock.makeJumpTarget(),
904 falseProb));
905 return continueAt;
906 } else {
907 // Do the full blown case 5 or 6 typecheck.
908 int LHSDepth = LHSclass.getTypeDepth();
909 int LHSId = LHSclass.getId();
910 RegisterOperand superclassIds =
911 InsertUnary(continueAt, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
912 if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
913 RegisterOperand superclassIdsLength =
914 InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
915 Instruction lengthCheck =
916 IfCmp.create(INT_IFCMP,
917 oldGuard,
918 superclassIdsLength,
919 IC(LHSDepth),
920 ConditionOperand.LESS(),
921 falseBlock.makeJumpTarget(),
922 BranchProfileOperand.unlikely());
923 if (oldGuard != null) {
924 oldGuard = oldGuard.copyD2D();
925 }
926 continueAt.insertBefore(lengthCheck);
927 BasicBlock oldBlock = continueAt.getBasicBlock();
928 oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
929 oldBlock.insertOut(falseBlock); // required due to splitNode!
930 }
931 RegisterOperand refCandidate =
932 InsertLoadOffset(continueAt,
933 ir,
934 USHORT_LOAD,
935 TypeReference.Short,
936 superclassIds,
937 Offset.fromIntZeroExtend(LHSDepth << 1),
938 new LocationOperand(TypeReference.Short),
939 TG());
940 continueAt.insertBefore(IfCmp.create(INT_IFCMP,
941 oldGuard,
942 refCandidate,
943 IC(LHSId),
944 ConditionOperand.NOT_EQUAL(),
945 falseBlock.makeJumpTarget(),
946 falseProb));
947 return continueAt;
948 }
949 }
950 } else {
951 // A non-resolved class or interface. Case 3 of DynamicTypeCheck
952 // Branch on the result of a call to
953 // RuntimeEntrypoints.instance
954 RegisterOperand result = ir.regpool.makeTempInt();
955 RVMMethod target = Entrypoints.instanceOfMethod;
956 Instruction call =
957 Call.create2(CALL,
958 result,
959 AC(target.getOffset()),
960 MethodOperand.STATIC(target),
961 RHSobj,
962 IC(LHStype.getId()));
963 call.copyPosition(continueAt);
964 continueAt.insertBefore(call);
965 call = callHelper(call, ir);
966 continueAt.insertBefore(IfCmp.create(INT_IFCMP,
967 oldGuard,
968 result.copyD2U(),
969 IC(0),
970 ConditionOperand.EQUAL(),
971 falseBlock.makeJumpTarget(),
972 falseProb));
973 return continueAt;
974 }
975 }
976
977 if (LHStype.isArrayType()) {
978 // Case 2 of DynamicTypeCheck: LHS is an array.
979 RVMArray LHSArray = (RVMArray) LHStype.peekType();
980 if (LHSArray != null) {
981 Operand classTIB = getTIB(continueAt, ir, LHSArray);
982 RVMType innermostElementType = LHSArray.getInnermostElementType();
983 if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() ||
984 (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
985 // [^k of primitive or [^k of final class. Just like final classes,
986 // a PTR compare of rhsTIB and the TIB of the class gives the answer.
987 continueAt.insertBefore(IfCmp.create(REF_IFCMP,
988 oldGuard,
989 RHStib,
990 classTIB,
991 ConditionOperand.NOT_EQUAL(),
992 falseBlock.makeJumpTarget(),
993 falseProb));
994 return continueAt;
995 }
996 // TODO: branch probability calculation is somewhat bogus for this case.
997 Instruction shortcircuit =
998 IfCmp.create(REF_IFCMP,
999 oldGuard,
1000 RHStib,
1001 classTIB,
1002 ConditionOperand.EQUAL(),
1003 trueBlock.makeJumpTarget(),
1004 new BranchProfileOperand());
1005 if (oldGuard != null) {
1006 oldGuard = oldGuard.copyD2D();
1007 }
1008 continueAt.insertBefore(shortcircuit);
1009 BasicBlock myBlock = shortcircuit.getBasicBlock();
1010 BasicBlock mainBlock = myBlock.splitNodeWithLinksAt(shortcircuit, ir);
1011 myBlock.insertOut(trueBlock); // must come after the splitNodeAt
1012 RegisterOperand rhsType =
1013 InsertUnary(continueAt, ir, GET_TYPE_FROM_TIB, TypeReference.Type, RHStib.copy());
1014 if (innermostElementType.isJavaLangObjectType()) {
1015 IntConstantOperand lhsDimension = IC(LHStype.getDimensionality());
1016 RegisterOperand rhsDimension = getField(continueAt, ir, rhsType, Entrypoints.dimensionField);
1017 Instruction dimTest =
1018 IfCmp2.create(INT_IFCMP2,
1019 oldGuard,
1020 rhsDimension,
1021 lhsDimension,
1022 ConditionOperand.GREATER(),
1023 trueBlock.makeJumpTarget(),
1024 ((BranchProfileOperand) falseProb.copy()).flip(),
1025 ConditionOperand.LESS(),
1026 falseBlock.makeJumpTarget(),
1027 (BranchProfileOperand) falseProb.copy());
1028 if (oldGuard != null) {
1029 oldGuard = oldGuard.copyD2D();
1030 }
1031 continueAt.insertBefore(dimTest);
1032 //BasicBlock testBlock =
1033 mainBlock.splitNodeWithLinksAt(dimTest, ir);
1034 mainBlock.insertOut(trueBlock);
1035 mainBlock.insertOut(falseBlock);
1036 RegisterOperand rhsInnermostElementTypeDimension =
1037 getField(continueAt, ir, rhsType.copyU2U(), Entrypoints.innermostElementTypeDimensionField);
1038 continueAt.insertBefore(IfCmp.create(INT_IFCMP,
1039 oldGuard,
1040 rhsInnermostElementTypeDimension,
1041 IC(0),
1042 ConditionOperand.NOT_EQUAL(),
1043 falseBlock.makeJumpTarget(),
1044 falseProb));
1045 return continueAt;
1046 }
1047 }
1048
1049 // Not a case we want to handle inline
1050 RVMMethod target = Entrypoints.instanceOfMethod;
1051 RegisterOperand callResult = ir.regpool.makeTempInt();
1052 Instruction call =
1053 Call.create2(CALL,
1054 callResult,
1055 AC(target.getOffset()),
1056 MethodOperand.STATIC(target),
1057 RHSobj,
1058 IC(LHStype.getId()));
1059 call.copyPosition(continueAt);
1060 continueAt.insertBefore(call);
1061 call = callHelper(call, ir);
1062 continueAt.insertBefore(IfCmp.create(INT_IFCMP,
1063 oldGuard,
1064 callResult.copyD2U(),
1065 IC(0),
1066 ConditionOperand.EQUAL(),
1067 falseBlock.makeJumpTarget(),
1068 falseProb));
1069 return continueAt;
1070 }
1071 OptimizingCompilerException.UNREACHABLE();
1072 return null;
1073 }
1074
1075 // helper routine.
1076 // s is a conditional branch; Make it the last instruction in its block
1077 // if it isn't already and return the fallthrough block.
1078 private static BasicBlock fallThroughBB(Instruction s, IR ir) {
1079 Instruction next = s.nextInstructionInCodeOrder();
1080 if (next.operator() == BBEND) {
1081 return next.getBasicBlock().nextBasicBlockInCodeOrder();
1082 } else if (next.operator() == GOTO) {
1083 BasicBlock target = next.getBranchTarget();
1084 next.remove();
1085 return target;
1086 } else {
1087 BasicBlock myBlock = s.getBasicBlock();
1088 BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
1089 myBlock.insertOut(succBlock);
1090 ir.cfg.linkInCodeOrder(myBlock, succBlock);
1091 return succBlock;
1092 }
1093 }
1094
1095 private static BasicBlock advanceBlock(int bcIndex, BasicBlock curBlock, IR ir) {
1096 BasicBlock newBlock = curBlock.createSubBlock(bcIndex, ir);
1097 curBlock.insertOut(newBlock);
1098 ir.cfg.linkInCodeOrder(curBlock, newBlock);
1099 return newBlock;
1100 }
1101
1102 }