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.SizeConstants.LOG_BYTES_IN_ADDRESS;
016 import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_INT;
017 import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
018 import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
019 import static org.jikesrvm.compilers.opt.ir.Operators.BOUNDS_CHECK_opcode;
020 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode;
021 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
022 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD;
023 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE;
024 import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
025 import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
026 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_NOTNULL_opcode;
027 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_UNRESOLVED_opcode;
028 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_opcode;
029 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode;
030 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
031 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD;
032 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE;
033 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode;
034 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
035 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD;
036 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE;
037 import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
038 import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
039 import static org.jikesrvm.compilers.opt.ir.Operators.GET_CLASS_TIB;
040 import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB;
041 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
042 import static org.jikesrvm.compilers.opt.ir.Operators.IG_CLASS_TEST_opcode;
043 import static org.jikesrvm.compilers.opt.ir.Operators.IG_METHOD_TEST_opcode;
044 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_NOTNULL_opcode;
045 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_UNRESOLVED_opcode;
046 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_opcode;
047 import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt;
048 import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
049 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
050 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode;
051 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
052 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
053 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
054 import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
055 import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
056 import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
057 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ZERO_CHECK_opcode;
058 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode;
059 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
060 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD;
061 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE;
062 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ZERO_CHECK_opcode;
063 import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH;
064 import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH_opcode;
065 import static org.jikesrvm.compilers.opt.ir.Operators.LOWTABLESWITCH;
066 import static org.jikesrvm.compilers.opt.ir.Operators.MUST_IMPLEMENT_INTERFACE_opcode;
067 import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode;
068 import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_opcode;
069 import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
070 import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
071 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
072 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
073 import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
074 import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD;
075 import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE;
076 import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE;
077 import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE_MEMBER_opcode;
078 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode;
079 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
080 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD;
081 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE;
082 import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
083 import static org.jikesrvm.compilers.opt.ir.Operators.TABLESWITCH_opcode;
084 import static org.jikesrvm.compilers.opt.ir.Operators.TRAP_IF;
085 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode;
086 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD;
087 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode;
088 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
089 import static org.jikesrvm.objectmodel.TIBLayoutConstants.NEEDS_DYNAMIC_LINK;
090 import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_INTERFACE_DISPATCH_TABLE_INDEX;
091
092 import org.jikesrvm.VM;
093 import org.jikesrvm.adaptive.AosEntrypoints;
094 import org.jikesrvm.classloader.RVMClass;
095 import org.jikesrvm.classloader.RVMField;
096 import org.jikesrvm.classloader.InterfaceInvocation;
097 import org.jikesrvm.classloader.InterfaceMethodSignature;
098 import org.jikesrvm.classloader.RVMMethod;
099 import org.jikesrvm.classloader.RVMType;
100 import org.jikesrvm.classloader.TypeReference;
101 import org.jikesrvm.compilers.opt.OptOptions;
102 import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
103 import org.jikesrvm.compilers.opt.ir.ALoad;
104 import org.jikesrvm.compilers.opt.ir.AStore;
105 import org.jikesrvm.compilers.opt.ir.BasicBlock;
106 import org.jikesrvm.compilers.opt.ir.Binary;
107 import org.jikesrvm.compilers.opt.ir.BoundsCheck;
108 import org.jikesrvm.compilers.opt.ir.CacheOp;
109 import org.jikesrvm.compilers.opt.ir.Call;
110 import org.jikesrvm.compilers.opt.ir.GetField;
111 import org.jikesrvm.compilers.opt.ir.GetStatic;
112 import org.jikesrvm.compilers.opt.ir.Goto;
113 import org.jikesrvm.compilers.opt.ir.GuardedUnary;
114 import org.jikesrvm.compilers.opt.ir.IR;
115 import org.jikesrvm.compilers.opt.ir.IRTools;
116 import org.jikesrvm.compilers.opt.ir.IfCmp;
117 import org.jikesrvm.compilers.opt.ir.IfCmp2;
118 import org.jikesrvm.compilers.opt.ir.InlineGuard;
119 import org.jikesrvm.compilers.opt.ir.Instruction;
120 import org.jikesrvm.compilers.opt.ir.Load;
121 import org.jikesrvm.compilers.opt.ir.LookupSwitch;
122 import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
123 import org.jikesrvm.compilers.opt.ir.Operator;
124 import org.jikesrvm.compilers.opt.ir.PutField;
125 import org.jikesrvm.compilers.opt.ir.PutStatic;
126 import org.jikesrvm.compilers.opt.ir.Store;
127 import org.jikesrvm.compilers.opt.ir.TableSwitch;
128 import org.jikesrvm.compilers.opt.ir.TrapIf;
129 import org.jikesrvm.compilers.opt.ir.Unary;
130 import org.jikesrvm.compilers.opt.ir.ZeroCheck;
131 import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
132 import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
133 import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
134 import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
135 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
136 import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
137 import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
138 import org.jikesrvm.compilers.opt.ir.operand.Operand;
139 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
140 import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
141 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
142 import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
143 import org.jikesrvm.compilers.opt.specialization.SpecializedMethod;
144 import org.jikesrvm.mm.mminterface.MemoryManagerConstants;
145 import org.jikesrvm.runtime.Entrypoints;
146 import org.jikesrvm.runtime.Magic;
147 import org.vmmagic.unboxed.Address;
148 import org.vmmagic.unboxed.Offset;
149
150 /**
151 * Converts all remaining instructions with HIR-only operators into
152 * an equivalent sequence of LIR operators.
153 */
154 public abstract class ConvertToLowLevelIR extends IRTools {
155
156 /**
157 * We have slightly different ideas of what the LIR should look like
158 * for IA32 and PowerPC. The main difference is that for IA32
159 * instead of bending over backwards in BURS to rediscover array
160 * loads, (where we can use base + index*scale addressing modes),
161 * we'll leave array loads in the LIR.
162 */
163 public static final boolean LOWER_ARRAY_ACCESS = VM.BuildForPowerPC;
164
165 /**
166 * Converts the given HIR to LIR.
167 *
168 * @param ir IR to convert
169 */
170 static void convert(IR ir, OptOptions options) {
171 boolean didArrayStoreCheck = false;
172 for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
173
174 switch (s.getOpcode()) {
175 case GETSTATIC_opcode: {
176 LocationOperand loc = GetStatic.getClearLocation(s);
177 RegisterOperand result = GetStatic.getClearResult(s);
178 Operand address = ir.regpool.makeJTOCOp(ir, s);
179 Operand offset = GetStatic.getClearOffset(s);
180 Load.mutate(s, IRTools.getLoadOp(loc.getFieldRef(), true), result, address, offset, loc);
181 }
182 break;
183
184 case PUTSTATIC_opcode: {
185 LocationOperand loc = PutStatic.getClearLocation(s);
186 Operand value = PutStatic.getClearValue(s);
187 Operand address = ir.regpool.makeJTOCOp(ir, s);
188 Operand offset = PutStatic.getClearOffset(s);
189 Store.mutate(s, IRTools.getStoreOp(loc.getFieldRef(), true), value, address, offset, loc);
190 }
191 break;
192
193 case PUTFIELD_opcode: {
194 LocationOperand loc = PutField.getClearLocation(s);
195 Operand value = PutField.getClearValue(s);
196 Operand address = PutField.getClearRef(s);
197 Operand offset = PutField.getClearOffset(s);
198 Store.mutate(s,
199 IRTools.getStoreOp(loc.getFieldRef(), false),
200 value,
201 address,
202 offset,
203 loc,
204 PutField.getClearGuard(s));
205 }
206 break;
207
208 case GETFIELD_opcode: {
209 LocationOperand loc = GetField.getClearLocation(s);
210 RegisterOperand result = GetField.getClearResult(s);
211 Operand address = GetField.getClearRef(s);
212 Operand offset = GetField.getClearOffset(s);
213 Load.mutate(s,
214 IRTools.getLoadOp(loc.getFieldRef(), false),
215 result,
216 address,
217 offset,
218 loc,
219 GetField.getClearGuard(s));
220 }
221 break;
222
223 case INT_ALOAD_opcode:
224 doArrayLoad(s, ir, INT_LOAD, 2);
225 break;
226
227 case LONG_ALOAD_opcode:
228 doArrayLoad(s, ir, LONG_LOAD, 3);
229 break;
230
231 case FLOAT_ALOAD_opcode:
232 doArrayLoad(s, ir, FLOAT_LOAD, 2);
233 break;
234
235 case DOUBLE_ALOAD_opcode:
236 doArrayLoad(s, ir, DOUBLE_LOAD, 3);
237 break;
238
239 case REF_ALOAD_opcode:
240 doArrayLoad(s, ir, REF_LOAD, LOG_BYTES_IN_ADDRESS);
241 break;
242
243 case BYTE_ALOAD_opcode:
244 doArrayLoad(s, ir, BYTE_LOAD, 0);
245 break;
246
247 case UBYTE_ALOAD_opcode:
248 doArrayLoad(s, ir, UBYTE_LOAD, 0);
249 break;
250
251 case USHORT_ALOAD_opcode:
252 doArrayLoad(s, ir, USHORT_LOAD, 1);
253 break;
254
255 case SHORT_ALOAD_opcode:
256 doArrayLoad(s, ir, SHORT_LOAD, 1);
257 break;
258
259 case INT_ASTORE_opcode:
260 doArrayStore(s, ir, INT_STORE, 2);
261 break;
262
263 case LONG_ASTORE_opcode:
264 doArrayStore(s, ir, LONG_STORE, 3);
265 break;
266
267 case FLOAT_ASTORE_opcode:
268 doArrayStore(s, ir, FLOAT_STORE, 2);
269 break;
270
271 case DOUBLE_ASTORE_opcode:
272 doArrayStore(s, ir, DOUBLE_STORE, 3);
273 break;
274
275 case REF_ASTORE_opcode:
276 doArrayStore(s, ir, REF_STORE, LOG_BYTES_IN_ADDRESS);
277 break;
278
279 case BYTE_ASTORE_opcode:
280 doArrayStore(s, ir, BYTE_STORE, 0);
281 break;
282
283 case SHORT_ASTORE_opcode:
284 doArrayStore(s, ir, SHORT_STORE, 1);
285 break;
286
287 case CALL_opcode:
288 s = callHelper(s, ir);
289 break;
290
291 case SYSCALL_opcode:
292 // If the SYSCALL is using a symbolic address, convert that to
293 // a sequence of loads off the BootRecord to find the appropriate field.
294 if (Call.getMethod(s) != null) {
295 expandSysCallTarget(s, ir);
296 }
297 break;
298
299 case TABLESWITCH_opcode:
300 s = tableswitch(s, ir);
301 break;
302
303 case LOOKUPSWITCH_opcode:
304 s = lookup(s, ir);
305 break;
306
307 case OBJARRAY_STORE_CHECK_opcode:
308 s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, true);
309 didArrayStoreCheck = true;
310 break;
311
312 case OBJARRAY_STORE_CHECK_NOTNULL_opcode:
313 s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, false);
314 didArrayStoreCheck = true;
315 break;
316
317 case CHECKCAST_opcode:
318 case CHECKCAST_UNRESOLVED_opcode:
319 s = DynamicTypeCheckExpansion.checkcast(s, ir);
320 break;
321
322 case CHECKCAST_NOTNULL_opcode:
323 s = DynamicTypeCheckExpansion.checkcastNotNull(s, ir);
324 break;
325
326 case MUST_IMPLEMENT_INTERFACE_opcode:
327 s = DynamicTypeCheckExpansion.mustImplementInterface(s, ir);
328 break;
329
330 case IG_CLASS_TEST_opcode:
331 IfCmp.mutate(s,
332 REF_IFCMP,
333 ir.regpool.makeTempValidation(),
334 getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s)),
335 getTIB(s, ir, InlineGuard.getGoal(s).asType()),
336 ConditionOperand.NOT_EQUAL(),
337 InlineGuard.getClearTarget(s),
338 InlineGuard.getClearBranchProfile(s));
339 break;
340
341 case IG_METHOD_TEST_opcode: {
342 MethodOperand methOp = InlineGuard.getClearGoal(s).asMethod();
343 Operand t1 = getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s));
344 Operand t2 = getTIB(s, ir, methOp.getTarget().getDeclaringClass());
345 IfCmp.mutate(s,
346 REF_IFCMP,
347 ir.regpool.makeTempValidation(),
348 getInstanceMethod(s, ir, t1, methOp.getTarget()),
349 getInstanceMethod(s, ir, t2, methOp.getTarget()),
350 ConditionOperand.NOT_EQUAL(),
351 InlineGuard.getClearTarget(s),
352 InlineGuard.getClearBranchProfile(s));
353 break;
354 }
355
356 case INSTANCEOF_opcode:
357 case INSTANCEOF_UNRESOLVED_opcode:
358 s = DynamicTypeCheckExpansion.instanceOf(s, ir);
359 break;
360
361 case INSTANCEOF_NOTNULL_opcode:
362 s = DynamicTypeCheckExpansion.instanceOfNotNull(s, ir);
363 break;
364
365 case INT_ZERO_CHECK_opcode: {
366 TrapIf.mutate(s,
367 TRAP_IF,
368 ZeroCheck.getClearGuardResult(s),
369 ZeroCheck.getClearValue(s),
370 IC(0),
371 ConditionOperand.EQUAL(),
372 TrapCodeOperand.DivByZero());
373 }
374 break;
375
376 case LONG_ZERO_CHECK_opcode: {
377 TrapIf.mutate(s,
378 TRAP_IF,
379 ZeroCheck.getClearGuardResult(s),
380 ZeroCheck.getClearValue(s),
381 LC(0),
382 ConditionOperand.EQUAL(),
383 TrapCodeOperand.DivByZero());
384 }
385 break;
386
387 case BOUNDS_CHECK_opcode: {
388 // get array_length from array_ref
389 RegisterOperand array_length =
390 InsertGuardedUnary(s,
391 ir,
392 ARRAYLENGTH,
393 TypeReference.Int,
394 BoundsCheck.getClearRef(s),
395 BoundsCheck.getClearGuard(s));
396 // In UN-signed comparison, a negative index will look like a very
397 // large positive number, greater than array length.
398 // Thus length LLT index is false iff 0 <= index <= length
399 TrapIf.mutate(s,
400 TRAP_IF,
401 BoundsCheck.getClearGuardResult(s),
402 array_length.copyD2U(),
403 BoundsCheck.getClearIndex(s),
404 ConditionOperand.LOWER_EQUAL(),
405 TrapCodeOperand.ArrayBounds());
406 }
407 break;
408
409 case RESOLVE_MEMBER_opcode:
410 s = resolveMember(s, ir);
411 break;
412
413 default:
414 break;
415 }
416 }
417 // Eliminate possible redundant trap block from array store checks
418 if (didArrayStoreCheck) {
419 branchOpts.perform(ir, true);
420 }
421 }
422
423 private static BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true);
424
425 /**
426 * Expand a tableswitch.
427 * @param s the instruction to expand
428 * @param ir the containing IR
429 * @return the last Instruction in the generated LIR sequence.
430 */
431 static Instruction tableswitch(Instruction s, IR ir) {
432
433 Instruction s2;
434 int lowLimit = TableSwitch.getLow(s).value;
435 int highLimit = TableSwitch.getHigh(s).value;
436 int number = highLimit - lowLimit + 1;
437 if (VM.VerifyAssertions) {
438 VM._assert(number > 0); // also checks that there are < 2^31 targets
439 }
440 Operand val = TableSwitch.getClearValue(s);
441 BranchOperand defaultLabel = TableSwitch.getClearDefault(s);
442 if (number < ir.options.CONTROL_TABLESWITCH_CUTOFF) { // convert into a lookupswitch
443 Instruction l =
444 LookupSwitch.create(LOOKUPSWITCH,
445 val,
446 null,
447 null,
448 defaultLabel,
449 TableSwitch.getClearDefaultBranchProfile(s),
450 number * 3);
451 for (int i = 0; i < number; i++) {
452 LookupSwitch.setMatch(l, i, IC(lowLimit + i));
453 LookupSwitch.setTarget(l, i, TableSwitch.getClearTarget(s, i));
454 LookupSwitch.setBranchProfile(l, i, TableSwitch.getClearBranchProfile(s, i));
455 }
456 s.insertAfter(CPOS(s, l));
457 return s.remove();
458 }
459 RegisterOperand reg = val.asRegister();
460 BasicBlock BB1 = s.getBasicBlock();
461 BasicBlock BB2 = BB1.splitNodeAt(s, ir);
462 BasicBlock defaultBB = defaultLabel.target.getBasicBlock();
463
464 /******* First basic block */
465 RegisterOperand t;
466 if (lowLimit != 0) {
467 t = insertBinary(s, ir, INT_ADD, TypeReference.Int, reg, IC(-lowLimit));
468 } else {
469 t = reg.copyU2U();
470 }
471 BranchProfileOperand defaultProb = TableSwitch.getClearDefaultBranchProfile(s);
472 s.replace(CPOS(s, IfCmp.create(INT_IFCMP,
473 ir.regpool.makeTempValidation(),
474 t,
475 IC(highLimit - lowLimit),
476 ConditionOperand.HIGHER(),
477 defaultLabel,
478 defaultProb)));
479 // Reweight branches to account for the default branch going. If
480 // the default probability was ALWAYS then when we recompute the
481 // weight to be a proportion of the total number of branches.
482 final boolean defaultIsAlways = defaultProb.takenProbability >= 1f;
483 final float weight = defaultIsAlways ? 1f / number : 1f / (1f - defaultProb.takenProbability);
484
485 /********** second Basic Block ******/
486 s2 = CPOS(s, LowTableSwitch.create(LOWTABLESWITCH, t.copyRO(), number * 2));
487 boolean containsDefault = false;
488 for (int i = 0; i < number; i++) {
489 BranchOperand b = TableSwitch.getClearTarget(s, i);
490 LowTableSwitch.setTarget(s2, i, b);
491 BranchProfileOperand bp = TableSwitch.getClearBranchProfile(s, i);
492 if (defaultIsAlways) {
493 bp.takenProbability = weight;
494 } else {
495 bp.takenProbability *= weight;
496 }
497 LowTableSwitch.setBranchProfile(s2, i, bp);
498 if (b.target == defaultLabel.target) {
499 containsDefault = true;
500 }
501 }
502 // Fixup the CFG and code order.
503 BB1.insertOut(BB2);
504 BB1.insertOut(defaultBB);
505 ir.cfg.linkInCodeOrder(BB1, BB2);
506 if (!containsDefault) {
507 BB2.deleteOut(defaultBB);
508 }
509 // Simplify a fringe case...
510 // if all targets of the LOWTABLESWITCH are the same,
511 // then just use a GOTO instead of the LOWTABLESWITCH.
512 // This actually happens (very occasionally), and is easy to test for.
513 if (BB2.getNumberOfNormalOut() == 1) {
514 BB2.appendInstruction(CPOS(s, Goto.create(GOTO, LowTableSwitch.getTarget(s2, 0))));
515 } else {
516 BB2.appendInstruction(s2);
517 }
518 // continue at next BB
519 s = BB2.lastInstruction();
520
521 return s;
522 }
523
524 /**
525 * Expand a lookupswitch.
526 * @param switchInstr The instruction to expand
527 * @param ir The containing IR
528 * @return the next {@link Instruction} after the generated LIR sequence.
529 */
530 static Instruction lookup(Instruction switchInstr, IR ir) {
531 Instruction bbend = switchInstr.nextInstructionInCodeOrder();
532 BasicBlock thisBB = bbend.getBasicBlock();
533 BasicBlock nextBB = thisBB.nextBasicBlockInCodeOrder();
534 // Blow away the old Normal ControlFlowGraph edges to prepare for new links
535 thisBB.deleteNormalOut();
536 switchInstr.remove();
537 BranchOperand defTarget = LookupSwitch.getClearDefault(switchInstr);
538 BasicBlock defaultBB = defTarget.target.getBasicBlock();
539 int high = LookupSwitch.getNumberOfTargets(switchInstr) - 1;
540 if (high < 0) {
541 // no cases in switch; just jump to defaultBB
542 thisBB.appendInstruction(Goto.create(GOTO, defTarget));
543 thisBB.insertOut(defaultBB);
544 } else {
545 Operand match = LookupSwitch.getValue(switchInstr);
546 if (match.isConstant()) {
547 // switch on a constant
548 int value = match.asIntConstant().value;
549 int numMatches = LookupSwitch.getNumberOfMatches(switchInstr);
550 BranchOperand target = LookupSwitch.getDefault(switchInstr);
551 for (int i = 0; i < numMatches; i++) {
552 if (value == LookupSwitch.getMatch(switchInstr, i).value) {
553 target = LookupSwitch.getTarget(switchInstr, i);
554 break;
555 }
556 }
557 thisBB.appendInstruction(Goto.create(GOTO, target));
558 thisBB.insertOut(target.target.getBasicBlock());
559 } else {
560 RegisterOperand reg = match.asRegister();
561
562 // If you're not already at the end of the code order
563 if (nextBB != null) {
564 ir.cfg.breakCodeOrder(thisBB, nextBB);
565 }
566 // generate the binary search tree into thisBB
567 BasicBlock lastNewBB =
568 _lookupswitchHelper(switchInstr, reg, defaultBB, ir, thisBB, 0, high, Integer.MIN_VALUE, Integer.MAX_VALUE);
569 if (nextBB != null) {
570 ir.cfg.linkInCodeOrder(lastNewBB, nextBB);
571 }
572 }
573 }
574
575 // skip all the instrs just inserted by _lookupswitchHelper
576 if (nextBB != null) {
577 return nextBB.firstInstruction();
578 } else {
579 return thisBB.lastInstruction();
580 }
581 }
582
583 /**
584 * Helper function to generate the binary search tree for
585 * a lookupswitch bytecode
586 *
587 * @param switchInstr the lookupswitch instruction
588 * @param defaultBB the basic block of the default case
589 * @param ir the ir object
590 * @param curBlock the basic block to insert instructions into
591 * @param reg the RegisterOperand that contains the valued being switched on
592 * @param low the low index of cases (operands of switchInstr)
593 * @param high the high index of cases (operands of switchInstr)
594 * @param min
595 * @param max
596 * @return the last basic block created
597 */
598 private static BasicBlock _lookupswitchHelper(Instruction switchInstr, RegisterOperand reg,
599 BasicBlock defaultBB, IR ir, BasicBlock curBlock,
600 int low, int high, int min, int max) {
601 if (VM.VerifyAssertions) {
602 VM._assert(low <= high, "broken control logic in _lookupswitchHelper");
603 }
604
605 int middle = (low + high) >> 1; // find middle
606
607 // The following are used below to store the computed branch
608 // probabilities for the branches that are created to implement
609 // the binary search. Used only if basic block frequencies available
610 float lessProb = 0.0f;
611 float greaterProb = 0.0f;
612 float equalProb = 0.0f;
613 float sum = 0.0f;
614
615 // Sum the probabilities for all targets < middle
616 for (int i = low; i < middle; i++) {
617 lessProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
618 }
619
620 // Sum the probabilities for all targets > middle
621 for (int i = middle + 1; i <= high; i++) {
622 greaterProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
623 }
624 equalProb = LookupSwitch.getBranchProfile(switchInstr, middle).takenProbability;
625
626 // The default case is a bit of a kludge. We know the total
627 // probability of executing the default case, but we have no
628 // idea which paths are taken to get there. For now, we'll
629 // assume that all paths that went to default were because the
630 // value was less than the smallest switch value. This ensures
631 // that all basic block appearing in the switch will have the
632 // correct weights (but the blocks in the binary switch
633 // generated may not).
634 if (low == 0) {
635 lessProb += LookupSwitch.getDefaultBranchProfile(switchInstr).takenProbability;
636 }
637
638 // Now normalize them so they are relative to the sum of the
639 // branches being considered in this piece of the subtree
640 sum = lessProb + equalProb + greaterProb;
641 if (sum > 0) { // check for divide by zero
642 lessProb /= sum;
643 equalProb /= sum;
644 greaterProb /= sum;
645 }
646
647 IntConstantOperand val = LookupSwitch.getClearMatch(switchInstr, middle);
648 int value = val.value;
649 BasicBlock greaterBlock = middle == high ? defaultBB : curBlock.createSubBlock(0, ir);
650 BasicBlock lesserBlock = low == middle ? defaultBB : curBlock.createSubBlock(0, ir);
651 // Generate this level of tests
652 BranchOperand branch = LookupSwitch.getClearTarget(switchInstr, middle);
653 BasicBlock branchBB = branch.target.getBasicBlock();
654 curBlock.insertOut(branchBB);
655 if (low != high) {
656 if (value == min) {
657 curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
658 ir.regpool.makeTempValidation(),
659 reg.copy(),
660 val,
661 ConditionOperand.EQUAL(),
662 branchBB.makeJumpTarget(),
663 new BranchProfileOperand(equalProb)));
664 } else {
665
666 // To compute the probability of the second compare, the first
667 // probability must be removed since the second branch is
668 // considered only if the first fails.
669 float secondIfProb = 0.0f;
670 sum = equalProb + greaterProb;
671 if (sum > 0) {
672 // if divide by zero, leave as is
673 secondIfProb = equalProb / sum;
674 }
675
676 curBlock.appendInstruction(IfCmp2.create(INT_IFCMP2,
677 ir.regpool.makeTempValidation(),
678 reg.copy(),
679 val,
680 ConditionOperand.LESS(),
681 lesserBlock.makeJumpTarget(),
682 new BranchProfileOperand(lessProb),
683 ConditionOperand.EQUAL(),
684 branchBB.makeJumpTarget(),
685 new BranchProfileOperand(secondIfProb)));
686 curBlock.insertOut(lesserBlock);
687 }
688 } else { // Base case: middle was the only case left to consider
689 if (min == max) {
690 curBlock.appendInstruction(Goto.create(GOTO, branch));
691 curBlock.insertOut(branchBB);
692 } else {
693 curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
694 ir.regpool.makeTempValidation(),
695 reg.copy(),
696 val,
697 ConditionOperand.EQUAL(),
698 branchBB.makeJumpTarget(),
699 new BranchProfileOperand(equalProb)));
700 BasicBlock newBlock = curBlock.createSubBlock(0, ir);
701 curBlock.insertOut(newBlock);
702 ir.cfg.linkInCodeOrder(curBlock, newBlock);
703 curBlock = newBlock;
704 curBlock.appendInstruction(defaultBB.makeGOTO());
705 curBlock.insertOut(defaultBB);
706 }
707 }
708 // Generate sublevels as needed and splice together instr & bblist
709 if (middle < high) {
710 curBlock.insertOut(greaterBlock);
711 ir.cfg.linkInCodeOrder(curBlock, greaterBlock);
712 curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, greaterBlock, middle + 1, high, value + 1, max);
713 }
714 if (low < middle) {
715 ir.cfg.linkInCodeOrder(curBlock, lesserBlock);
716 curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, lesserBlock, low, middle - 1, min, value - 1);
717 }
718 return curBlock;
719 }
720
721 /**
722 * Expand an array load.
723 * @param s the instruction to expand
724 * @param ir the containing IR
725 * @param op the load operator to use
726 * @param logwidth the log base 2 of the element type's size
727 */
728 public static void doArrayLoad(Instruction s, IR ir, Operator op, int logwidth) {
729 if (LOWER_ARRAY_ACCESS) {
730 RegisterOperand result = ALoad.getClearResult(s);
731 Operand array = ALoad.getClearArray(s);
732 Operand index = ALoad.getClearIndex(s);
733 Operand offset;
734 LocationOperand loc = ALoad.getClearLocation(s);
735 if (index instanceof IntConstantOperand) { // constant propagation
736 offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
737 } else {
738 if (logwidth != 0) {
739 offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
740 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
741 } else {
742 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
743 }
744 }
745 Load.mutate(s, op, result, array, offset, loc, ALoad.getClearGuard(s));
746 }
747 }
748
749 /**
750 * Expand an array store.
751 * @param s the instruction to expand
752 * @param ir the containing IR
753 * @param op the store operator to use
754 * @param logwidth the log base 2 of the element type's size
755 */
756 public static void doArrayStore(Instruction s, IR ir, Operator op, int logwidth) {
757 if (LOWER_ARRAY_ACCESS) {
758 Operand value = AStore.getClearValue(s);
759 Operand array = AStore.getClearArray(s);
760 Operand index = AStore.getClearIndex(s);
761 Operand offset;
762 LocationOperand loc = AStore.getClearLocation(s);
763 if (index instanceof IntConstantOperand) {// constant propagation
764 offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
765 } else {
766 if (logwidth != 0) {
767 offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
768 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
769 } else {
770 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
771 }
772 }
773 Store.mutate(s, op, value, array, offset, loc, AStore.getClearGuard(s));
774 }
775 }
776
777 /**
778 * Helper method for call expansion.
779 * @param v the call instruction
780 * @param ir the containing IR
781 * @return the last expanded instruction
782 */
783 static Instruction callHelper(Instruction v, IR ir) {
784 if (!Call.hasMethod(v)) {
785 if (VM.VerifyAssertions) VM._assert(Call.getAddress(v) instanceof RegisterOperand);
786 return v; // nothing to do....very low level call to address already in the register.
787 }
788
789 MethodOperand methOp = Call.getMethod(v);
790
791 // Handle recursive invocations.
792 if (methOp.hasPreciseTarget() && methOp.getTarget() == ir.method) {
793 Call.setAddress(v, new BranchOperand(ir.firstInstructionInCodeOrder()));
794 return v;
795 }
796
797 /* RRB 100500 */
798 // generate direct call to specialized method if the method operand
799 // has been marked as a specialized call.
800 if (VM.runningVM) {
801 SpecializedMethod spMethod = methOp.spMethod;
802 if (spMethod != null) {
803 int smid = spMethod.getSpecializedMethodIndex();
804 Call.setAddress(v, getSpecialMethod(v, ir, smid));
805 return v;
806 }
807 }
808
809 // Used mainly (only?) by OSR
810 if (methOp.hasDesignatedTarget()) {
811 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, methOp.jtocOffset));
812 return v;
813 }
814
815 if (methOp.isStatic()) {
816 if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
817 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
818 } else if (methOp.isVirtual()) {
819 if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
820 if (ir.options.H2L_CALL_VIA_JTOC && methOp.hasPreciseTarget()) {
821 // Call to precise type can go via JTOC
822 RVMMethod target = methOp.getTarget();
823 Call.setAddress(v,
824 InsertLoadOffsetJTOC(v,
825 ir,
826 REF_LOAD,
827 TypeReference.CodeArray,
828 target.findOrCreateJtocOffset()));
829 } else {
830 Operand tib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
831 Call.setAddress(v,
832 InsertLoadOffset(v,
833 ir,
834 REF_LOAD,
835 TypeReference.CodeArray,
836 tib,
837 Call.getClearAddress(v),
838 null,
839 TG()));
840 }
841 } else if (methOp.isSpecial()) {
842 RVMMethod target = methOp.getTarget();
843 if (target == null || target.isObjectInitializer() || target.isStatic()) {
844 // target == null => we are calling an unresolved <init> method.
845 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
846 } else {
847 if (ir.options.H2L_CALL_VIA_JTOC) {
848 Call.setAddress(v,
849 InsertLoadOffsetJTOC(v,
850 ir,
851 REF_LOAD,
852 TypeReference.CodeArray,
853 target.findOrCreateJtocOffset()));
854 } else {
855 // invoking a virtual method; do it via TIB of target's declaring class.
856 Operand tib = getTIB(v, ir, target.getDeclaringClass());
857 Call.setAddress(v,
858 InsertLoadOffset(v,
859 ir,
860 REF_LOAD,
861 TypeReference.CodeArray,
862 tib,
863 Call.getClearAddress(v),
864 null,
865 TG()));
866 }
867 }
868 } else {
869 if (VM.VerifyAssertions) VM._assert(methOp.isInterface());
870 if (VM.VerifyAssertions) VM._assert(!Call.hasAddress(v));
871 if (VM.BuildForIMTInterfaceInvocation) {
872 // SEE ALSO: FinalMIRExpansion (for hidden parameter)
873 Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
874 InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methOp.getMemberRef());
875 Offset offset = sig.getIMTOffset();
876 RegisterOperand address = null;
877 RegisterOperand IMT =
878 InsertLoadOffset(v,
879 ir,
880 REF_LOAD,
881 TypeReference.IMT,
882 RHStib.copy(),
883 Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS));
884 address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, IMT.copyD2U(), offset);
885
886 Call.setAddress(v, address);
887 } else {
888 int itableIndex = -1;
889 if (VM.BuildForITableInterfaceInvocation && methOp.hasTarget()) {
890 RVMClass I = methOp.getTarget().getDeclaringClass();
891 // search ITable variant
892 itableIndex =
893 InterfaceInvocation.getITableIndex(I,
894 methOp.getMemberRef().getName(),
895 methOp.getMemberRef().getDescriptor());
896 }
897 if (itableIndex == -1) {
898 // itable index is not known at compile-time.
899 // call "invokeinterface" to resolve the object and method id
900 // into a method address
901 RegisterOperand realAddrReg = ir.regpool.makeTemp(TypeReference.CodeArray);
902 RVMMethod target = Entrypoints.invokeInterfaceMethod;
903 Instruction vp =
904 Call.create2(CALL,
905 realAddrReg,
906 AC(target.getOffset()),
907 MethodOperand.STATIC(target),
908 Call.getParam(v, 0).asRegister().copyU2U(),
909 IC(methOp.getMemberRef().getId()));
910 vp.position = v.position;
911 vp.bcIndex = RUNTIME_SERVICES_BCI;
912 v.insertBefore(vp);
913 callHelper(vp, ir);
914 Call.setAddress(v, realAddrReg.copyD2U());
915 return v;
916 } else {
917 // itable index is known at compile-time.
918 // call "findITable" to resolve object + interface id into
919 // itable address
920 RegisterOperand iTable = ir.regpool.makeTemp(TypeReference.ITable);
921 Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
922 RVMMethod target = Entrypoints.findItableMethod;
923 Instruction fi =
924 Call.create2(CALL,
925 iTable,
926 AC(target.getOffset()),
927 MethodOperand.STATIC(target),
928 RHStib,
929 IC(methOp.getTarget().getDeclaringClass().getInterfaceId()));
930 fi.position = v.position;
931 fi.bcIndex = RUNTIME_SERVICES_BCI;
932 v.insertBefore(fi);
933 callHelper(fi, ir);
934 RegisterOperand address =
935 InsertLoadOffset(v,
936 ir,
937 REF_LOAD,
938 TypeReference.CodeArray,
939 iTable.copyD2U(),
940 Offset.fromIntZeroExtend(itableIndex << LOG_BYTES_IN_ADDRESS));
941 Call.setAddress(v, address);
942 return v;
943 }
944 }
945 }
946 return v;
947 }
948
949 /**
950 * Generate the code to resolve a member (field/method) reference.
951 * @param s the RESOLVE_MEMBER instruction to expand
952 * @param ir the containing ir object
953 * @return the last expanded instruction
954 */
955 private static Instruction resolveMember(Instruction s, IR ir) {
956 Operand memberOp = Unary.getClearVal(s);
957 RegisterOperand offset = Unary.getClearResult(s);
958 int dictId;
959 if (memberOp instanceof LocationOperand) {
960 dictId = ((LocationOperand) memberOp).getFieldRef().getId();
961 } else {
962 dictId = ((MethodOperand) memberOp).getMemberRef().getId();
963 }
964
965 BranchProfileOperand bp = BranchProfileOperand.never();
966 BasicBlock predBB = s.getBasicBlock();
967 BasicBlock succBB = predBB.splitNodeAt(s.prevInstructionInCodeOrder(), ir);
968 BasicBlock testBB = predBB.createSubBlock(s.bcIndex, ir, 1f - bp.takenProbability);
969 BasicBlock resolveBB = predBB.createSubBlock(s.bcIndex, ir, bp.takenProbability);
970 s.remove();
971
972 // Get the offset from the appropriate RVMClassLoader array
973 // and check to see if it is valid
974 RegisterOperand offsetTable = getStatic(testBB.lastInstruction(), ir, Entrypoints.memberOffsetsField);
975 testBB.appendInstruction(Load.create(INT_LOAD,
976 offset.copyRO(),
977 offsetTable,
978 AC(Offset.fromIntZeroExtend(dictId << LOG_BYTES_IN_INT)),
979 new LocationOperand(TypeReference.Int),
980 TG()));
981 testBB.appendInstruction(Unary.create(INT_2ADDRSigExt, offset, offset.copy()));
982 testBB.appendInstruction(IfCmp.create(REF_IFCMP,
983 ir.regpool.makeTempValidation(),
984 offset.copy(),
985 AC(Address.fromIntSignExtend(NEEDS_DYNAMIC_LINK)),
986 ConditionOperand.EQUAL(),
987 resolveBB.makeJumpTarget(),
988 bp));
989
990 // Handle the offset being invalid
991 resolveBB.appendInstruction(CacheOp.mutate(s, RESOLVE, memberOp));
992 resolveBB.appendInstruction(testBB.makeGOTO());
993
994 // Put together the CFG links & code order
995 predBB.insertOut(testBB);
996 ir.cfg.linkInCodeOrder(predBB, testBB);
997 testBB.insertOut(succBB);
998 testBB.insertOut(resolveBB);
999 ir.cfg.linkInCodeOrder(testBB, succBB);
1000 resolveBB.insertOut(testBB); // backedge
1001 ir.cfg.addLastInCodeOrder(resolveBB); // stick resolution code in outer space.
1002 return testBB.lastInstruction();
1003 }
1004
1005 /**
1006 * Insert a binary instruction before s in the instruction stream.
1007 * @param s the instruction to insert before
1008 * @param ir the containing IR
1009 * @param operator the operator to insert
1010 * @param type the type of the result
1011 * @param o1 the first operand
1012 * @param o2 the second operand
1013 * @return the result operand of the inserted instruction
1014 */
1015 public static RegisterOperand insertBinary(Instruction s, IR ir, Operator operator,
1016 TypeReference type, Operand o1, Operand o2) {
1017 RegisterOperand t = ir.regpool.makeTemp(type);
1018 s.insertBefore(CPOS(s, Binary.create(operator, t, o1, o2)));
1019 return t.copyD2U();
1020 }
1021
1022 /**
1023 * Insert a unary instruction before s in the instruction stream.
1024 * @param s the instruction to insert before
1025 * @param ir the containing IR
1026 * @param operator the operator to insert
1027 * @param type the type of the result
1028 * @param o1 the operand
1029 * @return the result operand of the inserted instruction
1030 */
1031 static RegisterOperand InsertUnary(Instruction s, IR ir, Operator operator, TypeReference type,
1032 Operand o1) {
1033 RegisterOperand t = ir.regpool.makeTemp(type);
1034 s.insertBefore(CPOS(s, Unary.create(operator, t, o1)));
1035 return t.copyD2U();
1036 }
1037
1038 /**
1039 * Insert a guarded unary instruction before s in the instruction stream.
1040 * @param s the instruction to insert before
1041 * @param ir the containing IR
1042 * @param operator the operator to insert
1043 * @param type the type of the result
1044 * @param o1 the operand
1045 * @param guard the guard operand
1046 * @return the result operand of the inserted instruction
1047 */
1048 static RegisterOperand InsertGuardedUnary(Instruction s, IR ir, Operator operator,
1049 TypeReference type, Operand o1, Operand guard) {
1050 RegisterOperand t = ir.regpool.makeTemp(type);
1051 s.insertBefore(GuardedUnary.create(operator, t, o1, guard));
1052 return t.copyD2U();
1053 }
1054
1055 /**
1056 * Insert a load off the JTOC before s in the instruction stream.
1057 * @param s the instruction to insert before
1058 * @param ir the containing IR
1059 * @param operator the operator to insert
1060 * @param type the type of the result
1061 * @param offset the offset to load at
1062 * @return the result operand of the inserted instruction
1063 */
1064 static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1065 TypeReference type, Offset offset) {
1066 return InsertLoadOffset(s,
1067 ir,
1068 operator,
1069 type,
1070 ir.regpool.makeJTOCOp(ir, s),
1071 AC(offset),
1072 new LocationOperand(offset),
1073 null);
1074 }
1075
1076 /**
1077 * Insert a load off the JTOC before s in the instruction stream.
1078 * @param s the instruction to insert before
1079 * @param ir the containing IR
1080 * @param operator the operator to insert
1081 * @param type the type of the result
1082 * @param offset the offset to load at
1083 * @return the result operand of the inserted instruction
1084 */
1085 static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1086 TypeReference type, Operand offset) {
1087 return InsertLoadOffset(s, ir, operator, type, ir.regpool.makeJTOCOp(ir, s), offset, null, null);
1088 }
1089
1090 /**
1091 * Insert a load off before s in the instruction stream.
1092 * @param s the instruction to insert before
1093 * @param ir the containing IR
1094 * @param operator the operator to insert
1095 * @param type the type of the result
1096 * @param reg2 the base to load from
1097 * @param offset the offset to load at
1098 * @return the result operand of the inserted instruction
1099 */
1100 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1101 TypeReference type, Operand reg2, Offset offset) {
1102 return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, null);
1103 }
1104
1105 /**
1106 * Insert a load off before s in the instruction stream.
1107 * @param s the instruction to insert before
1108 * @param ir the containing IR
1109 * @param operator the operator to insert
1110 * @param type the type of the result
1111 * @param reg2 the base to load from
1112 * @param offset the offset to load at
1113 * @param guard the guard operand
1114 * @return the result operand of the inserted instruction
1115 */
1116 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1117 TypeReference type, Operand reg2, Offset offset,
1118 Operand guard) {
1119 return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, guard);
1120 }
1121
1122 /**
1123 * Insert a load off before s in the instruction stream.
1124 * @param s the instruction to insert before
1125 * @param ir the containing IR
1126 * @param operator the operator to insert
1127 * @param type the type of the result
1128 * @param reg2 the base to load from
1129 * @param offset the offset to load at
1130 * @param loc the location operand
1131 * @param guard the guard operand
1132 * @return the result operand of the inserted instruction
1133 */
1134 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1135 TypeReference type, Operand reg2, Offset offset,
1136 LocationOperand loc, Operand guard) {
1137 return InsertLoadOffset(s, ir, operator, type, reg2, AC(offset), loc, guard);
1138 }
1139
1140 /**
1141 * Insert a load off before s in the instruction stream.
1142 * @param s the instruction to insert before
1143 * @param ir the containing IR
1144 * @param operator the operator to insert
1145 * @param type the type of the result
1146 * @param reg2 the base to load from
1147 * @param offset the offset to load at
1148 * @param loc the location operand
1149 * @param guard the guard operand
1150 * @return the result operand of the inserted instruction
1151 */
1152 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1153 TypeReference type, Operand reg2, Operand offset,
1154 LocationOperand loc, Operand guard) {
1155 RegisterOperand regTarget = ir.regpool.makeTemp(type);
1156 Instruction s2 = Load.create(operator, regTarget, reg2, offset, loc, guard);
1157 s.insertBefore(s2);
1158 return regTarget.copyD2U();
1159 }
1160
1161 /** get the tib from the object pointer to by obj */
1162 static Operand getTIB(Instruction s, IR ir, Operand obj, Operand guard) {
1163 if (obj.isObjectConstant()) {
1164 // NB Constant types must already be resolved
1165 try {
1166 RVMType type = obj.getType().resolve();
1167 return new TIBConstantOperand(type);
1168 } catch (NoClassDefFoundError e) {
1169 if (VM.runningVM) throw e;
1170 // Class not found during bootstrap due to chasing a class
1171 // only valid in the bootstrap JVM
1172 }
1173 }
1174 RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1175 Instruction s2 = GuardedUnary.create(GET_OBJ_TIB, res, obj, guard);
1176 s.insertBefore(s2);
1177 return res.copyD2U();
1178 }
1179
1180 /** get the class tib for type */
1181 static Operand getTIB(Instruction s, IR ir, RVMType type) {
1182 return new TIBConstantOperand(type);
1183 //return getTIB(s, ir, new TypeOperand(type));
1184 }
1185
1186 /** get the class tib for type */
1187 static Operand getTIB(Instruction s, IR ir, TypeOperand type) {
1188 RVMType t = type.getVMType();
1189 if (VM.BuildForIA32 && !MemoryManagerConstants.MOVES_TIBS && VM.runningVM && t != null && t.isResolved()) {
1190 Address addr = Magic.objectAsAddress(t.getTypeInformationBlock());
1191 return new AddressConstantOperand(addr);
1192 } else if (!t.isResolved()) {
1193 RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1194 s.insertBefore(Unary.create(GET_CLASS_TIB, res, type));
1195 return res.copyD2U();
1196 } else {
1197 return new TIBConstantOperand(t);
1198 }
1199 }
1200
1201 /**
1202 * Get an instance method from a TIB
1203 */
1204 static RegisterOperand getInstanceMethod(Instruction s, IR ir, Operand tib, RVMMethod method) {
1205 return InsertLoadOffset(s, ir, REF_LOAD, TypeReference.CodeArray, tib, method.getOffset());
1206 }
1207
1208 /**
1209 * Load an instance field.
1210 * @param s
1211 * @param ir
1212 * @param obj
1213 * @param field
1214 */
1215 public static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field) {
1216 return getField(s, ir, obj, field, null);
1217 }
1218
1219 /**
1220 * Load an instance field.
1221 * @param s
1222 * @param ir
1223 * @param obj
1224 * @param field
1225 * @param guard
1226 */
1227 static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field,
1228 Operand guard) {
1229 return InsertLoadOffset(s,
1230 ir,
1231 IRTools.getLoadOp(field.getType(), field.isStatic()),
1232 field.getType(),
1233 obj,
1234 field.getOffset(),
1235 new LocationOperand(field),
1236 guard);
1237 }
1238
1239 /* RRB 100500 */
1240 /**
1241 * support for direct call to specialized method.
1242 */
1243 static RegisterOperand getSpecialMethod(Instruction s, IR ir, int smid) {
1244 // First, get the pointer to the JTOC offset pointing to the
1245 // specialized Method table
1246 RegisterOperand reg =
1247 InsertLoadOffsetJTOC(s,
1248 ir,
1249 REF_LOAD,
1250 TypeReference.JavaLangObjectArray,
1251 AosEntrypoints.specializedMethodsField.getOffset());
1252 RegisterOperand instr =
1253 InsertLoadOffset(s,
1254 ir,
1255 REF_LOAD,
1256 TypeReference.CodeArray,
1257 reg,
1258 Offset.fromIntZeroExtend(smid << LOG_BYTES_IN_INT));
1259 return instr;
1260 }
1261
1262 /**
1263 * Expand symbolic SysCall target into a chain of loads from the bootrecord to
1264 * the desired target address.
1265 */
1266 public static void expandSysCallTarget(Instruction s, IR ir) {
1267 MethodOperand sysM = Call.getMethod(s);
1268 if (sysM.getMemberRef().isFieldReference()) {
1269 RegisterOperand t1 = getStatic(s, ir, Entrypoints.the_boot_recordField);
1270 RVMField target = sysM.getMemberRef().asFieldReference().resolve();
1271 Operand ip = getField(s, ir, t1, target);
1272 Call.setAddress(s, ip);
1273 }
1274 }
1275
1276 /**
1277 * Load a static field.
1278 * @param s
1279 * @param ir
1280 * @param field
1281 */
1282 public static RegisterOperand getStatic(Instruction s, IR ir, RVMField field) {
1283 return InsertLoadOffsetJTOC(s,
1284 ir,
1285 IRTools.getLoadOp(field.getType(), field.isStatic()),
1286 field.getType(),
1287 field.getOffset());
1288 }
1289 }