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.bc2ir;
014
015import static org.jikesrvm.compilers.opt.ir.IRTools.AC;
016import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2INT;
017import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2LONG;
018import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
019import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_ADDR;
020import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_INT;
021import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_LONG;
022import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR;
023import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD;
024import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE;
025import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
026import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_AS_LONG_BITS;
027import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD;
028import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_SQRT;
029import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE;
030import static org.jikesrvm.compilers.opt.ir.Operators.FENCE;
031import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_AS_INT_BITS;
032import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD;
033import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_SQRT;
034import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE;
035import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB;
036import static org.jikesrvm.compilers.opt.ir.Operators.GET_TIME_BASE;
037import static org.jikesrvm.compilers.opt.ir.Operators.GET_TYPE_FROM_TIB;
038import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt;
039import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
040import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
041import static org.jikesrvm.compilers.opt.ir.Operators.INT_BITS_AS_FLOAT;
042import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
043import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
044import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
045import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2ADDR;
046import static org.jikesrvm.compilers.opt.ir.Operators.LONG_BITS_AS_DOUBLE;
047import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD;
048import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE;
049import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_ADDR;
050import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_INT;
051import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_LONG;
052import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING;
053import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD;
054import static org.jikesrvm.compilers.opt.ir.Operators.REF_AND;
055import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD;
056import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
057import static org.jikesrvm.compilers.opt.ir.Operators.REF_NOT;
058import static org.jikesrvm.compilers.opt.ir.Operators.REF_OR;
059import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHL;
060import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHR;
061import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE;
062import static org.jikesrvm.compilers.opt.ir.Operators.REF_SUB;
063import static org.jikesrvm.compilers.opt.ir.Operators.REF_USHR;
064import static org.jikesrvm.compilers.opt.ir.Operators.REF_XOR;
065import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD;
066import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE;
067import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL;
068import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD;
069import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
070import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR;
071import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_FIRST_SPECIALIZED_METHOD_INDEX;
072import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
073import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS;
074
075import org.jikesrvm.VM;
076import org.jikesrvm.classloader.Atom;
077import org.jikesrvm.classloader.MemberReference;
078import org.jikesrvm.classloader.MethodReference;
079import org.jikesrvm.classloader.RVMField;
080import org.jikesrvm.classloader.TypeReference;
081import org.jikesrvm.compilers.opt.MagicNotImplementedException;
082import org.jikesrvm.compilers.opt.OptimizingCompilerException;
083import org.jikesrvm.compilers.opt.Simplifier;
084import org.jikesrvm.compilers.opt.ir.Attempt;
085import org.jikesrvm.compilers.opt.ir.Binary;
086import org.jikesrvm.compilers.opt.ir.BooleanCmp;
087import org.jikesrvm.compilers.opt.ir.Call;
088import org.jikesrvm.compilers.opt.ir.Empty;
089import org.jikesrvm.compilers.opt.ir.GuardedUnary;
090import org.jikesrvm.compilers.opt.ir.Instruction;
091import org.jikesrvm.compilers.opt.ir.Load;
092import org.jikesrvm.compilers.opt.ir.Move;
093import org.jikesrvm.compilers.opt.ir.Nullary;
094import org.jikesrvm.compilers.opt.ir.Operator;
095import org.jikesrvm.compilers.opt.ir.Prepare;
096import org.jikesrvm.compilers.opt.ir.Store;
097import org.jikesrvm.compilers.opt.ir.Unary;
098import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
099import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
100import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
101import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
102import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
103import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand;
104import org.jikesrvm.compilers.opt.ir.operand.Operand;
105import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
106import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
107import org.jikesrvm.runtime.ArchEntrypoints;
108import org.jikesrvm.runtime.MagicNames;
109import org.vmmagic.pragma.Interruptible;
110import org.vmmagic.unboxed.Address;
111import org.vmmagic.unboxed.Offset;
112
113/**
114 * This class implements the non-machine-specific magics for the opt compiler.
115 * By non-machine-specific we mean that the IR generated to implement the magic
116 * is independent of the target-architecture.
117 * It does not mean that the eventual MIR that implements the magic
118 * won't differ from architecture to architecture.
119 */
120public class GenerateMagic {
121
122  /**
123   * "Semantic inlining" of methods of the Magic class.
124   * Based on the methodName, generate a sequence of opt instructions
125   * that implement the magic, updating the expression stack as necessary.
126   *
127   * @param bc2ir the bc2ir object that is generating the
128   *              ir containing this magic
129   * @param gc must be bc2ir.gc
130   * @param meth the RVMMethod that is the magic method
131   * @return {@code true} if and only if magic was generated
132   */
133  static boolean generateMagic(BC2IR bc2ir, GenerationContext gc, MethodReference meth)
134      throws MagicNotImplementedException {
135
136    if (gc.getMethod().hasNoInlinePragma()) gc.forceFrameAllocation();
137
138    Atom methodName = meth.getName();
139
140    boolean address = (meth.getType() == TypeReference.Address);
141
142    // Address magic
143    TypeReference[] types = meth.getParameterTypes();
144    TypeReference returnType = meth.getReturnType();
145
146    if (address && isLoad(methodName)) {
147      // LOAD
148      Operand offset = (types.length == 0) ? AC(Address.zero()) : bc2ir.popAddress();
149      Operand base = bc2ir.popAddress();
150      RegisterOperand result = gc.getTemps().makeTemp(returnType);
151      bc2ir.appendInstruction(Load.create(getOperator(returnType, LOAD_OP), result, base, offset, null));
152      bc2ir.push(result.copyD2U(), returnType);
153
154    } else if (address && isPrepare(methodName)) {
155      // PREPARE
156      Operand offset = (types.length == 0) ? AC(Address.zero()) : bc2ir.popAddress();
157      Operand base = bc2ir.popAddress();
158      RegisterOperand result = gc.getTemps().makeTemp(returnType);
159      bc2ir.appendInstruction(Prepare.create(getOperator(returnType, PREPARE_OP), result, base, offset, null));
160      bc2ir.push(result.copyD2U(), returnType);
161
162    } else if (address && methodName == MagicNames.attempt) {
163      // ATTEMPT
164      TypeReference attemptType = types[0];
165
166      Operand offset = (types.length == 2) ? AC(Address.zero()) : bc2ir.popAddress();
167
168      Operand newVal = bc2ir.pop();
169      Operand oldVal = bc2ir.pop();
170      Operand base = bc2ir.popAddress();
171      RegisterOperand test = gc.getTemps().makeTempInt();
172      bc2ir.appendInstruction(Attempt.create(getOperator(attemptType, ATTEMPT_OP),
173                                             test,
174                                             base,
175                                             offset,
176                                             oldVal,
177                                             newVal,
178                                             null));
179      bc2ir.push(test.copyD2U(), returnType);
180
181    } else if (address && methodName == MagicNames.store) {
182      // STORE
183      TypeReference storeType = types[0];
184
185      Operand offset = (types.length == 1) ? AC(Address.zero()) : bc2ir.popAddress();
186
187      Operand val = bc2ir.pop(storeType);
188      Operand base = bc2ir.popAddress();
189      bc2ir.appendInstruction(Store.create(getOperator(storeType, STORE_OP), val, base, offset, null));
190
191    } else if (methodName == MagicNames.getThreadRegister) {
192      RegisterOperand rop = gc.getTemps().makeTROp();
193      bc2ir.markGuardlessNonNull(rop);
194      bc2ir.push(rop);
195    } else if (methodName == MagicNames.setThreadRegister) {
196      Operand val = bc2ir.popRef();
197      if (val instanceof RegisterOperand) {
198        bc2ir.appendInstruction(Move.create(REF_MOVE, gc.getTemps().makeTROp(), val));
199      } else {
200        String msg = " Unexpected operand Magic.setThreadRegister";
201        throw MagicNotImplementedException.UNEXPECTED(msg);
202      }
203    } else if (methodName == MagicNames.addressArrayCreate) {
204      Instruction s = bc2ir.generateAnewarray(null, meth.getType().getArrayElementType());
205      bc2ir.appendInstruction(s);
206    } else if (methodName == MagicNames.addressArrayLength) {
207      Operand op1 = bc2ir.pop();
208      bc2ir.clearCurrentGuard();
209      if (bc2ir.do_NullCheck(op1)) {
210        return true;
211      }
212      RegisterOperand t = gc.getTemps().makeTempInt();
213      Instruction s = GuardedUnary.create(ARRAYLENGTH, t, op1, bc2ir.getCurrentGuard());
214      bc2ir.push(t.copyD2U());
215      bc2ir.appendInstruction(s);
216    } else if (methodName == MagicNames.addressArrayGet) {
217      TypeReference elementType = meth.getReturnType();
218      Operand index = bc2ir.popInt();
219      Operand ref = bc2ir.popRef();
220      RegisterOperand offsetI = gc.getTemps().makeTempInt();
221      RegisterOperand offset = gc.getTemps().makeTempOffset();
222      RegisterOperand result;
223      if (meth.getType().isCodeArrayType()) {
224        if (VM.BuildForIA32) {
225          result = gc.getTemps().makeTemp(TypeReference.Byte);
226          bc2ir.appendInstruction(Load.create(BYTE_LOAD,
227                                              result,
228                                              ref,
229                                              index,
230                                              new LocationOperand(elementType),
231                                              new TrueGuardOperand()));
232        } else if (VM.BuildForPowerPC) {
233          result = gc.getTemps().makeTemp(TypeReference.Int);
234          bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_INT)));
235          bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
236          bc2ir.appendInstruction(Load.create(INT_LOAD,
237                                              result,
238                                              ref,
239                                              offset.copy(),
240                                              new LocationOperand(elementType),
241                                              new TrueGuardOperand()));
242        }
243      } else {
244        result = gc.getTemps().makeTemp(elementType);
245        bc2ir.appendInstruction(Binary.create(INT_SHL,
246                                              offsetI,
247                                              index,
248                                              new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
249        bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
250        bc2ir.appendInstruction(Load.create(REF_LOAD,
251                                            result,
252                                            ref,
253                                            offset.copy(),
254                                            new LocationOperand(elementType),
255                                            new TrueGuardOperand()));
256      }
257      bc2ir.push(result.copyD2U());
258    } else if (methodName == MagicNames.addressArraySet) {
259      TypeReference elementType = meth.getParameterTypes()[1];
260      Operand val = bc2ir.pop();
261      Operand index = bc2ir.popInt();
262      Operand ref = bc2ir.popRef();
263      RegisterOperand offsetI = gc.getTemps().makeTempInt();
264      RegisterOperand offset = gc.getTemps().makeTempOffset();
265      if (meth.getType().isCodeArrayType()) {
266        if (VM.BuildForIA32) {
267          bc2ir.appendInstruction(Store.create(BYTE_STORE,
268                                               val,
269                                               ref,
270                                               index,
271                                               new LocationOperand(elementType),
272                                               new TrueGuardOperand()));
273        } else if (VM.BuildForPowerPC) {
274          bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_INT)));
275          bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
276          bc2ir.appendInstruction(Store.create(INT_STORE,
277                                               val,
278                                               ref,
279                                               offset.copy(),
280                                               new LocationOperand(elementType),
281                                               new TrueGuardOperand()));
282        }
283      } else {
284        bc2ir.appendInstruction(Binary.create(INT_SHL,
285                                              offsetI,
286                                              index,
287                                              new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
288        bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
289        bc2ir.appendInstruction(Store.create(REF_STORE,
290                                             val,
291                                             ref,
292                                             offset.copy(),
293                                             new LocationOperand(elementType),
294                                             new TrueGuardOperand()));
295      }
296    } else if (methodName == MagicNames.getIntAtOffset) {
297      Operand offset = bc2ir.popAddress();
298      Operand object = bc2ir.popRef();
299      RegisterOperand val = gc.getTemps().makeTempInt();
300      bc2ir.appendInstruction(Load.create(INT_LOAD, val, object, offset, null));
301      bc2ir.push(val.copyD2U());
302    } else if (methodName == MagicNames.setIntAtOffset) {
303      LocationOperand loc = null;
304      if (meth.getParameterTypes().length == 4) {
305        loc = mapToMetadata(bc2ir.popInt());
306      }
307      Operand val = bc2ir.popInt();
308      Operand offset = bc2ir.popAddress();
309      Operand object = bc2ir.popRef();
310      bc2ir.appendInstruction(Store.create(INT_STORE, val, object, offset, loc));
311    } else if (methodName == MagicNames.getFloatAtOffset) {
312      Operand offset = bc2ir.popAddress();
313      Operand object = bc2ir.popRef();
314      RegisterOperand val = gc.getTemps().makeTempFloat();
315      bc2ir.appendInstruction(Load.create(FLOAT_LOAD, val, object, offset, null));
316      bc2ir.push(val.copyD2U());
317    } else if (methodName == MagicNames.setFloatAtOffset) {
318      LocationOperand loc = null;
319      if (meth.getParameterTypes().length == 4) {
320        loc = mapToMetadata(bc2ir.popInt());
321      }
322      Operand val = bc2ir.popFloat();
323      Operand offset = bc2ir.popAddress();
324      Operand object = bc2ir.popRef();
325      bc2ir.appendInstruction(Store.create(FLOAT_STORE, val, object, offset, loc));
326    } else if (methodName == MagicNames.getWordAtOffset) {
327      LocationOperand loc = null;
328      if (meth.getParameterTypes().length == 3) {
329        loc = mapToMetadata(bc2ir.popInt());
330      }
331      Operand offset = bc2ir.popAddress();
332      Operand object = bc2ir.popRef();
333      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
334      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
335      bc2ir.push(val.copyD2U());
336    } else if (methodName == MagicNames.getAddressAtOffset) {
337      LocationOperand loc = null;
338      if (meth.getParameterTypes().length == 3) {
339        loc = mapToMetadata(bc2ir.popInt());
340      }
341      Operand offset = bc2ir.popAddress();
342      Operand object = bc2ir.popRef();
343      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
344      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
345      bc2ir.push(val.copyD2U());
346    } else if (methodName == MagicNames.getExtentAtOffset) {
347      LocationOperand loc = null;
348      if (meth.getParameterTypes().length == 3) {
349        loc = mapToMetadata(bc2ir.popInt());
350      }
351      Operand offset = bc2ir.popAddress();
352      Operand object = bc2ir.popRef();
353      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Extent);
354      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
355      bc2ir.push(val.copyD2U());
356    } else if (methodName == MagicNames.getOffsetAtOffset) {
357      LocationOperand loc = null;
358      if (meth.getParameterTypes().length == 3) {
359        loc = mapToMetadata(bc2ir.popInt());
360      }
361      Operand offset = bc2ir.popAddress();
362      Operand object = bc2ir.popRef();
363      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Offset);
364      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
365      bc2ir.push(val.copyD2U());
366    } else if (methodName == MagicNames.setWordAtOffset ||
367        methodName == MagicNames.setAddressAtOffset ||
368        methodName == MagicNames.setOffsetAtOffset ||
369        methodName == MagicNames.setExtentAtOffset) {
370      LocationOperand loc = null;
371      if (meth.getParameterTypes().length == 4) {
372        loc = mapToMetadata(bc2ir.popInt());
373      }
374      Operand val = bc2ir.popRef();
375      Operand offset = bc2ir.popAddress();
376      Operand object = bc2ir.popRef();
377      bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, loc));
378    } else if (methodName == MagicNames.getLongAtOffset) {
379      Operand offset = bc2ir.popAddress();
380      Operand object = bc2ir.popRef();
381      RegisterOperand val = gc.getTemps().makeTempLong();
382      bc2ir.appendInstruction(Load.create(LONG_LOAD, val, object, offset, null));
383      bc2ir.pushDual(val.copyD2U());
384    } else if (methodName == MagicNames.setLongAtOffset) {
385      LocationOperand loc = null;
386      if (meth.getParameterTypes().length == 4) {
387        loc = mapToMetadata(bc2ir.popInt());
388      }
389      Operand val = bc2ir.popLong();
390      Operand offset = bc2ir.popAddress();
391      Operand object = bc2ir.popRef();
392      bc2ir.appendInstruction(Store.create(LONG_STORE, val, object, offset, loc));
393    } else if (methodName == MagicNames.getDoubleAtOffset) {
394      Operand offset = bc2ir.popAddress();
395      Operand object = bc2ir.popRef();
396      RegisterOperand val = gc.getTemps().makeTempDouble();
397      bc2ir.appendInstruction(Load.create(DOUBLE_LOAD, val, object, offset, null));
398      bc2ir.pushDual(val.copyD2U());
399    } else if (methodName == MagicNames.setDoubleAtOffset) {
400      LocationOperand loc = null;
401      if (meth.getParameterTypes().length == 4) {
402        loc = mapToMetadata(bc2ir.popInt());
403      }
404      Operand val = bc2ir.popDouble();
405      Operand offset = bc2ir.popAddress();
406      Operand object = bc2ir.popRef();
407      bc2ir.appendInstruction(Store.create(DOUBLE_STORE, val, object, offset, loc));
408    } else if (methodName == MagicNames.getObjectAtOffset) {
409      LocationOperand loc = null;
410      if (meth.getParameterTypes().length == 3) {
411        loc = mapToMetadata(bc2ir.popInt());
412      }
413      Operand offset = bc2ir.popAddress();
414      Operand object = bc2ir.popRef();
415      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
416      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
417      bc2ir.push(val.copyD2U());
418    } else if (methodName == MagicNames.getTIBAtOffset) {
419      Operand offset = bc2ir.popAddress();
420      Operand object = bc2ir.popRef();
421      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.TIB);
422      bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, null));
423      bc2ir.push(val.copyD2U());
424    } else if (methodName == MagicNames.setObjectAtOffset) {
425      LocationOperand loc = null;
426      if (meth.getParameterTypes().length == 4) {
427        loc = mapToMetadata(bc2ir.popInt());
428      }
429      Operand val = bc2ir.popRef();
430      Operand offset = bc2ir.popAddress();
431      Operand object = bc2ir.popRef();
432      bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, loc));
433    } else if (methodName == MagicNames.getByteAtOffset) {
434      Operand offset = bc2ir.popAddress();
435      Operand object = bc2ir.popRef();
436      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Byte);
437      bc2ir.appendInstruction(Load.create(BYTE_LOAD, val, object, offset, null));
438      bc2ir.push(val.copyD2U());
439    } else if (methodName == MagicNames.getUnsignedByteAtOffset) {
440      Operand offset = bc2ir.popAddress();
441      Operand object = bc2ir.popRef();
442      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Byte);
443      bc2ir.appendInstruction(Load.create(UBYTE_LOAD, val, object, offset, null));
444      bc2ir.push(val.copyD2U());
445    } else if (methodName == MagicNames.setByteAtOffset || methodName == MagicNames.setBooleanAtOffset) {
446      LocationOperand loc = null;
447      if (meth.getParameterTypes().length == 4) {
448        loc = mapToMetadata(bc2ir.popInt());
449      }
450      Operand val = bc2ir.popInt();
451      Operand offset = bc2ir.popAddress();
452      Operand object = bc2ir.popRef();
453      bc2ir.appendInstruction(Store.create(BYTE_STORE, val, object, offset, loc));
454    } else if (methodName == MagicNames.getShortAtOffset) {
455      Operand offset = bc2ir.popAddress();
456      Operand object = bc2ir.popRef();
457      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Char);
458      bc2ir.appendInstruction(Load.create(SHORT_LOAD, val, object, offset, null));
459      bc2ir.push(val.copyD2U());
460    } else if (methodName == MagicNames.getCharAtOffset) {
461      Operand offset = bc2ir.popAddress();
462      Operand object = bc2ir.popRef();
463      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Char);
464      bc2ir.appendInstruction(Load.create(USHORT_LOAD, val, object, offset, null));
465      bc2ir.push(val.copyD2U());
466    } else if (methodName == MagicNames.setCharAtOffset || methodName == MagicNames.setShortAtOffset) {
467      LocationOperand loc = null;
468      if (meth.getParameterTypes().length == 4) {
469        loc = mapToMetadata(bc2ir.popInt());
470      }
471      Operand val = bc2ir.popInt();
472      Operand offset = bc2ir.popAddress();
473      Operand object = bc2ir.popRef();
474      bc2ir.appendInstruction(Store.create(SHORT_STORE, val, object, offset, loc));
475    } else if (methodName == MagicNames.getMemoryInt) {
476      Operand memAddr = bc2ir.popAddress();
477      RegisterOperand val = gc.getTemps().makeTempInt();
478      bc2ir.appendInstruction(Load.create(INT_LOAD, val, memAddr, AC(Offset.zero()), null));
479      bc2ir.push(val.copyD2U());
480    } else if (methodName == MagicNames.getMemoryWord) {
481      Operand memAddr = bc2ir.popAddress();
482      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
483      bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, AC(Offset.zero()), null));
484      bc2ir.push(val.copyD2U());
485    } else if (methodName == MagicNames.getMemoryAddress) {
486      Operand memAddr = bc2ir.popAddress();
487      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
488      bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, AC(Offset.zero()), null));
489      bc2ir.push(val.copyD2U());
490    } else if (methodName == MagicNames.setMemoryInt) {
491      Operand val = bc2ir.popInt();
492      Operand memAddr = bc2ir.popAddress();
493      bc2ir.appendInstruction(Store.create(INT_STORE,
494                                           val,
495                                           memAddr,
496                                           AC(Offset.zero()),
497                                           null));
498    } else if (methodName == MagicNames.setMemoryWord) {
499      Operand val = bc2ir.popRef();
500      Operand memAddr = bc2ir.popAddress();
501      bc2ir.appendInstruction(Store.create(REF_STORE,
502                                           val,
503                                           memAddr,
504                                           AC(Offset.zero()),
505                                           null));
506    } else if (meth.isSysCall()) {
507      // All methods of SysCall have the following signature:
508      // callNAME(Address functionAddress, <var args to pass via native calling convention>)
509      // With 64 bit PowerPC ELF ABI, functionAddress points to the function descriptor
510      TypeReference[] args = meth.getParameterTypes();
511      Instruction call = Call.create(SYSCALL, null, null, null, null, args.length - 1);
512      for (int i = args.length - 1; i >= 1; i--) {
513        Call.setParam(call, i - 1, bc2ir.pop(args[i]));
514      }
515      Operand functionAddress = bc2ir.pop(args[0]);
516      Call.setAddress(call, functionAddress);
517      if (!returnType.isVoidType()) {
518        RegisterOperand op0 = gc.getTemps().makeTemp(returnType);
519        Call.setResult(call, op0);
520        bc2ir.push(op0.copyD2U(), returnType);
521      }
522      Call.setMethod(call, MethodOperand.STATIC(meth, meth.peekResolvedMethod()));
523      bc2ir.appendInstruction(call);
524    } else if (meth.isSpecializedInvoke()) {
525      // The callsite looks like              RETURN = INVOKE (ID, OBJECT, P0, P1 .. PN)
526      // And the actual method will look like RETURN = INVOKE     (OBJECT, P0, P1 .. PN)
527
528      // Create the call instruction
529      Instruction call = Call.create(CALL, null, null, null, null, types.length - 1);
530
531      // Plumb all of the normal parameters into the call
532      for (int i = types.length - 1; i >= 2; i--) {
533        Call.setParam(call, i - 1, bc2ir.pop(types[i]));
534      }
535      // The object being specialized
536      Operand objectOperand = bc2ir.pop(types[1]);
537      Call.setParam(call, 0, objectOperand);
538      Operand guard = BC2IR.copyGuardFromOperand(objectOperand);
539      if (guard == null) {
540        // it's magic, so assume that it's OK....
541        guard = new TrueGuardOperand();
542      }
543      Call.setGuard(call, guard);
544
545      // Load the tib of this object
546      RegisterOperand tibObject = gc.getTemps().makeTemp(TypeReference.TIB);
547      bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibObject, objectOperand.copy(), guard.copy()));
548
549      // The index of the specialized method
550      Operand methodId = bc2ir.popInt();
551
552      // Add the base offset for specialized methods and convert from index to address
553      RegisterOperand tibOffset = gc.getTemps().makeTemp(TypeReference.Int);
554      bc2ir.appendInstruction(Binary.create(INT_ADD, tibOffset, methodId, new IntConstantOperand(TIB_FIRST_SPECIALIZED_METHOD_INDEX)));
555      bc2ir.appendInstruction(Binary.create(INT_SHL, tibOffset.copyRO(), tibOffset.copyD2U(), new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
556
557      // Load the code address from the TIB
558      RegisterOperand codeAddress = gc.getTemps().makeTemp(TypeReference.Address);
559      bc2ir.appendInstruction(Load.create(REF_LOAD, codeAddress, tibObject.copyD2U(), tibOffset.copyD2U(), null));
560
561      Call.setAddress(call, codeAddress.copyD2U());
562      if (!returnType.isVoidType()) {
563        RegisterOperand op0 = gc.getTemps().makeTemp(returnType);
564        Call.setResult(call, op0);
565        bc2ir.push(op0.copyD2U(), returnType);
566      }
567      bc2ir.appendInstruction(call);
568    } else if (methodName == MagicNames.objectAsType) {
569      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Type);
570      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
571      bc2ir.push(reg.copyD2U());
572    } else if (methodName == MagicNames.objectAsThread) {
573      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Thread);
574      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
575      bc2ir.push(reg.copyD2U());
576    } else if (methodName == MagicNames.objectAsAddress) {
577      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Address);
578      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
579      bc2ir.push(reg.copyD2U());
580    } else if (methodName == MagicNames.addressAsObject) {
581      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
582      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
583      bc2ir.push(reg.copyD2U());
584    } else if (methodName == MagicNames.addressAsTIB) {
585      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.TIB);
586      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
587      bc2ir.push(reg.copyD2U());
588    } else if (methodName == MagicNames.addressAsByteArray) {
589      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.ByteArray);
590      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
591      bc2ir.push(reg.copyD2U());
592    } else if (methodName == MagicNames.objectAsShortArray) {
593      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.ShortArray);
594      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
595      bc2ir.push(reg.copyD2U());
596    } else if (methodName == MagicNames.objectAsIntArray) {
597      RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.IntArray);
598      bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
599      bc2ir.push(reg.copyD2U());
600    } else if (methodName == MagicNames.floatAsIntBits) {
601      Operand val = bc2ir.popFloat();
602      RegisterOperand op0 = gc.getTemps().makeTempInt();
603      bc2ir.appendInstruction(Unary.create(FLOAT_AS_INT_BITS, op0, val));
604      bc2ir.push(op0.copyD2U());
605    } else if (methodName == MagicNames.intBitsAsFloat) {
606      Operand val = bc2ir.popInt();
607      RegisterOperand op0 = gc.getTemps().makeTempFloat();
608      bc2ir.appendInstruction(Unary.create(INT_BITS_AS_FLOAT, op0, val));
609      bc2ir.push(op0.copyD2U());
610    } else if (methodName == MagicNames.doubleAsLongBits) {
611      Operand val = bc2ir.popDouble();
612      RegisterOperand op0 = gc.getTemps().makeTempLong();
613      bc2ir.appendInstruction(Unary.create(DOUBLE_AS_LONG_BITS, op0, val));
614      bc2ir.pushDual(op0.copyD2U());
615    } else if (methodName == MagicNames.longBitsAsDouble) {
616      Operand val = bc2ir.popLong();
617      RegisterOperand op0 = gc.getTemps().makeTempDouble();
618      bc2ir.appendInstruction(Unary.create(LONG_BITS_AS_DOUBLE, op0, val));
619      bc2ir.pushDual(op0.copyD2U());
620    } else if (methodName == MagicNames.sqrt) {
621      TypeReference[] args = meth.getParameterTypes();
622      if (args[0] == TypeReference.Float) {
623        Operand val = bc2ir.popFloat();
624        RegisterOperand op0 = gc.getTemps().makeTempFloat();
625        bc2ir.appendInstruction(Unary.create(FLOAT_SQRT, op0, val));
626        bc2ir.push(op0.copyD2U());
627      } else if (args[0] == TypeReference.Double) {
628        Operand val = bc2ir.popDouble();
629        RegisterOperand op0 = gc.getTemps().makeTempDouble();
630        bc2ir.appendInstruction(Unary.create(DOUBLE_SQRT, op0, val));
631        bc2ir.pushDual(op0.copyD2U());
632      } else {
633        if (VM.VerifyAssertions)
634          VM._assert(VM.NOT_REACHED,"SQRT only handles Double or Float operands");
635      }
636    } else if (methodName == MagicNames.getObjectType) {
637      Operand val = bc2ir.popRef();
638      if (val.isObjectConstant()) {
639        bc2ir.push(new ObjectConstantOperand(val.getType().peekType(), Offset.zero()));
640      } else {
641        Operand guard = BC2IR.copyGuardFromOperand(val);
642        if (guard == null) {
643          // it's magic, so assume that it's OK....
644          guard = new TrueGuardOperand();
645        }
646        RegisterOperand tibPtr = gc.getTemps().makeTemp(TypeReference.TIB);
647        bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibPtr, val, guard));
648        RegisterOperand op0;
649        TypeReference argType = val.getType();
650        if (argType.isArrayType()) {
651          op0 = gc.getTemps().makeTemp(TypeReference.RVMArray);
652        } else {
653          if (argType == TypeReference.JavaLangObject ||
654              argType == TypeReference.JavaLangCloneable ||
655              argType == TypeReference.JavaIoSerializable) {
656            // could be an array or a class, so make op0 be a RVMType
657            op0 = gc.getTemps().makeTemp(TypeReference.Type);
658          } else {
659            op0 = gc.getTemps().makeTemp(TypeReference.Class);
660          }
661        }
662        bc2ir.markGuardlessNonNull(op0);
663        bc2ir.appendInstruction(Unary.create(GET_TYPE_FROM_TIB, op0, tibPtr.copyD2U()));
664        bc2ir.push(op0.copyD2U());
665      }
666    } else if (methodName == MagicNames.getArrayLength) {
667      Operand val = bc2ir.popRef();
668      RegisterOperand op0 = gc.getTemps().makeTempInt();
669      bc2ir.appendInstruction(GuardedUnary.create(ARRAYLENGTH, op0, val, new TrueGuardOperand()));
670      bc2ir.push(op0.copyD2U());
671    } else if (methodName == MagicNames.invokeClassInitializer) {
672      Instruction s = Call.create0(CALL, null, bc2ir.popRef(), null);
673      bc2ir.appendInstruction(s);
674    } else if ((methodName == MagicNames.invokeMethodReturningObject) ||
675               (methodName == MagicNames.invokeMethodReturningVoid) ||
676               (methodName == MagicNames.invokeMethodReturningLong) ||
677               (methodName == MagicNames.invokeMethodReturningDouble) ||
678               (methodName == MagicNames.invokeMethodReturningFloat) ||
679               (methodName == MagicNames.invokeMethodReturningInt)) {
680      Operand spills = bc2ir.popRef();
681      Operand fprmeta = bc2ir.popRef();
682      Operand fprs = bc2ir.popRef();
683      Operand gprs = bc2ir.popRef();
684      Operand code = bc2ir.popRef();
685      RegisterOperand res = null;
686      if (methodName == MagicNames.invokeMethodReturningObject) {
687        res = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
688        bc2ir.push(res.copyD2U());
689      } else if (methodName == MagicNames.invokeMethodReturningLong) {
690        res = gc.getTemps().makeTemp(TypeReference.Long);
691        bc2ir.push(res.copyD2U(), TypeReference.Long);
692      } else if (methodName == MagicNames.invokeMethodReturningDouble) {
693        res = gc.getTemps().makeTempDouble();
694        bc2ir.push(res.copyD2U(), TypeReference.Double);
695      } else if (methodName == MagicNames.invokeMethodReturningFloat) {
696        res = gc.getTemps().makeTempFloat();
697        bc2ir.push(res.copyD2U(), TypeReference.Float);
698      } else if (methodName == MagicNames.invokeMethodReturningInt) {
699        res = gc.getTemps().makeTempInt();
700        bc2ir.push(res.copyD2U());
701      }
702      RVMField target = ArchEntrypoints.reflectiveMethodInvokerInstructionsField;
703      MethodOperand met = MethodOperand.STATIC(target);
704      Instruction s =
705          Call.create5(CALL, res, AC(target.getOffset()), met, code, gprs, fprs, fprmeta, spills);
706      bc2ir.appendInstruction(s);
707    } else if (methodName == MagicNames.saveThreadState) {
708      Operand p1 = bc2ir.popRef();
709      RVMField target = ArchEntrypoints.saveThreadStateInstructionsField;
710      MethodOperand mo = MethodOperand.STATIC(target);
711      bc2ir.appendInstruction(Call.create1(CALL, null, AC(target.getOffset()), mo, p1));
712    } else if (methodName == MagicNames.threadSwitch) {
713      Operand p2 = bc2ir.popRef();
714      Operand p1 = bc2ir.popRef();
715      RVMField target = ArchEntrypoints.threadSwitchInstructionsField;
716      MethodOperand mo = MethodOperand.STATIC(target);
717      bc2ir.appendInstruction(Call.create2(CALL, null, AC(target.getOffset()), mo, p1, p2));
718    } else if (methodName == MagicNames.restoreHardwareExceptionState) {
719      RVMField target = ArchEntrypoints.restoreHardwareExceptionStateInstructionsField;
720      MethodOperand mo = MethodOperand.STATIC(target);
721      bc2ir.appendInstruction(Call.create1(CALL,
722                                           null,
723                                           AC(target.getOffset()),
724                                           mo,
725                                           bc2ir.popRef()));
726    } else if (methodName == MagicNames.prepareInt) {
727      Operand offset = bc2ir.popAddress();
728      Operand base = bc2ir.popRef();
729      RegisterOperand val = gc.getTemps().makeTempInt();
730      bc2ir.appendInstruction(Prepare.create(PREPARE_INT, val, base, offset, null));
731      bc2ir.push(val.copyD2U());
732    } else if (methodName == MagicNames.prepareLong) {
733      Operand offset = bc2ir.popAddress();
734      Operand base = bc2ir.popRef();
735      RegisterOperand val = gc.getTemps().makeTempLong();
736      bc2ir.appendInstruction(Prepare.create(PREPARE_LONG, val, base, offset, null));
737      bc2ir.pushDual(val.copyD2U());
738    } else if (methodName == MagicNames.prepareObject) {
739      Operand offset = bc2ir.popAddress();
740      Operand base = bc2ir.popRef();
741      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
742      bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
743      bc2ir.push(val.copyD2U());
744    } else if (methodName == MagicNames.prepareAddress) {
745      Operand offset = bc2ir.popAddress();
746      Operand base = bc2ir.popRef();
747      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
748      bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
749      bc2ir.push(val.copyD2U());
750    } else if (methodName == MagicNames.prepareWord) {
751      Operand offset = bc2ir.popAddress();
752      Operand base = bc2ir.popRef();
753      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
754      bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
755      bc2ir.push(val.copyD2U());
756    } else if (methodName == MagicNames.attemptInt) {
757      Operand newVal = bc2ir.popInt();
758      Operand oldVal = bc2ir.popInt();
759      Operand offset = bc2ir.popAddress();
760      Operand base = bc2ir.popRef();
761      RegisterOperand test = gc.getTemps().makeTempBoolean();
762      bc2ir.appendInstruction(Attempt.create(ATTEMPT_INT, test, base, offset, oldVal, newVal, null));
763      bc2ir.push(test.copyD2U());
764    } else if (methodName == MagicNames.attemptLong) {
765      Operand newVal = bc2ir.popLong();
766      Operand oldVal = bc2ir.popLong();
767      Operand offset = bc2ir.popAddress();
768      Operand base = bc2ir.popRef();
769      RegisterOperand test = gc.getTemps().makeTempBoolean();
770      bc2ir.appendInstruction(Attempt.create(ATTEMPT_LONG, test, base, offset, oldVal, newVal, null));
771      bc2ir.push(test.copyD2U());
772    } else if (methodName == MagicNames.attemptObject) {
773      Operand newVal = bc2ir.popRef();
774      Operand oldVal = bc2ir.popRef();
775      Operand offset = bc2ir.popAddress();
776      Operand base = bc2ir.popRef();
777      RegisterOperand test = gc.getTemps().makeTempBoolean();
778      bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
779      bc2ir.push(test.copyD2U());
780    } else if (methodName == MagicNames.attemptAddress) {
781      Operand newVal = bc2ir.popAddress();
782      Operand oldVal = bc2ir.popAddress();
783      Operand offset = bc2ir.popAddress();
784      Operand base = bc2ir.popRef();
785      RegisterOperand test = gc.getTemps().makeTempBoolean();
786      bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
787      bc2ir.push(test.copyD2U());
788    } else if (methodName == MagicNames.attemptWord) {
789      Operand newVal = bc2ir.pop();
790      Operand oldVal = bc2ir.pop();
791      Operand offset = bc2ir.popAddress();
792      Operand base = bc2ir.popRef();
793      RegisterOperand test = gc.getTemps().makeTempBoolean();
794      bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
795      bc2ir.push(test.copyD2U());
796    } else if (methodName == MagicNames.fence) {
797      bc2ir.appendInstruction(Empty.create(FENCE));
798    } else if (methodName == MagicNames.combinedLoadBarrier) {
799      bc2ir.appendInstruction(Empty.create(READ_CEILING));
800    } else if (methodName == MagicNames.storeStoreBarrier) {
801      bc2ir.appendInstruction(Empty.create(WRITE_FLOOR));
802    } else if (generatePolymorphicMagic(bc2ir, gc, meth, methodName)) {
803      return true;
804    } else if (methodName == MagicNames.getTimeBase) {
805      RegisterOperand op0 = gc.getTemps().makeTempLong();
806      bc2ir.appendInstruction(Nullary.create(GET_TIME_BASE, op0));
807      bc2ir.pushDual(op0.copyD2U());
808    } else if (methodName == MagicNames.getInlineDepth) {
809      bc2ir.push(new IntConstantOperand(gc.getInlineSequence().getInlineDepth()));
810    } else if (methodName == MagicNames.isConstantParameter) {
811      Operand requestedOperand = bc2ir.pop();
812      if (!(requestedOperand instanceof IntConstantOperand)) {
813        throw new OptimizingCompilerException("Must supply constant to Magic.isConstantParameter");
814      }
815      int requested = ((IntConstantOperand)(requestedOperand)).value;
816      boolean isConstant = gc.getArguments()[requested].isConstant();
817      bc2ir.push(new IntConstantOperand(isConstant ? 1 : 0));
818    } else {
819      // Wasn't machine-independent, so try the machine-dependent magics next.
820      if (VM.BuildForIA32) {
821        return org.jikesrvm.compilers.opt.bc2ir.ia32.GenerateMachineSpecificMagic.generateMagic(bc2ir, gc, meth);
822      } else {
823        if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
824        return org.jikesrvm.compilers.opt.bc2ir.ppc.GenerateMachineSpecificMagic.generateMagic(bc2ir, gc, meth);
825      }
826    }
827    return true;
828  } // generateMagic
829
830  // Generate magic where the untype operational semantics is identified by name.
831  // The operands' types are determined from the method signature.
832  //
833  static boolean generatePolymorphicMagic(BC2IR bc2ir, GenerationContext gc, MethodReference meth,
834                                          Atom methodName) {
835    TypeReference resultType = meth.getReturnType();
836    Instruction s = null;
837    if (methodName == MagicNames.wordFromInt || methodName == MagicNames.wordFromIntSignExtend) {
838      s = bc2ir._unaryHelper(INT_2ADDRSigExt, bc2ir.popInt(), resultType);
839    } else if (methodName == MagicNames.wordFromIntZeroExtend) {
840      s = bc2ir._unaryHelper(INT_2ADDRZerExt, bc2ir.popInt(), resultType);
841    } else if (methodName == MagicNames.wordFromLong) {
842      s = bc2ir._unaryHelper(LONG_2ADDR, bc2ir.popLong(), resultType);
843    } else if (methodName == MagicNames.wordToInt) {
844      s = bc2ir._unaryHelper(ADDR_2INT, bc2ir.popAddress(), resultType);
845    } else if (methodName == MagicNames.wordToLong) {
846      s = bc2ir._unaryDualHelper(ADDR_2LONG, bc2ir.popAddress(), resultType);
847    } else if (methodName == MagicNames.wordToWord) {
848      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popAddress(), resultType);
849    } else if (methodName == MagicNames.wordToAddress) {
850      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popRef(), resultType);
851    } else if (methodName == MagicNames.wordToObject) {
852      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popRef(), resultType);
853    } else if (methodName == MagicNames.wordToObjectReference || methodName == MagicNames.wordFromObject) {
854      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popRef(), resultType);
855    } else if (methodName == MagicNames.wordToOffset) {
856      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popAddress(), resultType);
857    } else if (methodName == MagicNames.wordToExtent) {
858      s = bc2ir._moveHelper(REF_MOVE, bc2ir.popAddress(), resultType);
859    } else if (methodName == MagicNames.codeArrayAsObject) {
860      s = bc2ir._moveHelper(REF_MOVE, bc2ir.pop(TypeReference.CodeArray), resultType);
861    } else if (methodName == MagicNames.tibAsObject) {
862      s = bc2ir._moveHelper(REF_MOVE, bc2ir.pop(TypeReference.TIB), resultType);
863    } else if (methodName == MagicNames.wordPlus) {
864      Operand o2 = bc2ir.pop();
865      if (VM.BuildFor64Addr && o2.isInt()) {
866        s = bc2ir._unaryHelper(INT_2ADDRSigExt, o2, resultType);
867        if (s != null) bc2ir.appendInstruction(s);
868        o2 = bc2ir.pop();
869      }
870      Operand o1 = bc2ir.pop();
871      s = bc2ir._binaryHelper(REF_ADD, o1, o2, resultType);
872    } else if (methodName == MagicNames.wordMinus) {
873      Operand o2 = bc2ir.pop();
874      if (VM.BuildFor64Addr && o2.isInt()) {
875        s = bc2ir._unaryHelper(INT_2ADDRSigExt, o2, resultType);
876        if (s != null) bc2ir.appendInstruction(s);
877        o2 = bc2ir.pop();
878      }
879      Operand o1 = bc2ir.pop();
880      s = bc2ir._binaryHelper(REF_SUB, o1, o2, resultType);
881    } else if (methodName == MagicNames.wordDiff) {
882      Operand o2 = bc2ir.pop();
883      Operand o1 = bc2ir.pop();
884      s = bc2ir._binaryHelper(REF_SUB, o1, o2, resultType);
885    } else if (methodName == MagicNames.wordAnd) {
886      Operand o2 = bc2ir.pop();
887      Operand o1 = bc2ir.pop();
888      s = bc2ir._binaryHelper(REF_AND, o1, o2, resultType);
889    } else if (methodName == MagicNames.wordOr) {
890      Operand o2 = bc2ir.pop();
891      Operand o1 = bc2ir.pop();
892      s = bc2ir._binaryHelper(REF_OR, o1, o2, resultType);
893    } else if (methodName == MagicNames.wordXor) {
894      Operand o2 = bc2ir.pop();
895      Operand o1 = bc2ir.pop();
896      s = bc2ir._binaryHelper(REF_XOR, o1, o2, resultType);
897    } else if (methodName == MagicNames.wordNot) {
898      Operand o1 = bc2ir.pop();
899      s = bc2ir._unaryHelper(REF_NOT, o1, resultType);
900    } else if (methodName == MagicNames.wordZero || methodName == MagicNames.wordNull) {
901      s = bc2ir._moveHelper(REF_MOVE, AC(Address.zero()), resultType);
902    } else if (methodName == MagicNames.wordOne) {
903      s = bc2ir._moveHelper(REF_MOVE, AC(Address.fromIntZeroExtend(1)), resultType);
904    } else if (methodName == MagicNames.wordMax) {
905      s = bc2ir._moveHelper(REF_MOVE, AC(Address.max()), resultType);
906    } else if (methodName == MagicNames.wordIsNull || methodName == MagicNames.wordIsZero) {
907      s = _cmpHelper(bc2ir, gc, ConditionOperand.EQUAL(), AC(Address.zero()));
908    } else if (methodName == MagicNames.wordIsMax) {
909      s = _cmpHelper(bc2ir, gc, ConditionOperand.EQUAL(), AC(Address.max()));
910    } else if (methodName == MagicNames.wordEQ) {
911      s = _cmpHelper(bc2ir, gc, ConditionOperand.EQUAL(), null);
912    } else if (methodName == MagicNames.wordNE) {
913      s = _cmpHelper(bc2ir, gc, ConditionOperand.NOT_EQUAL(), null);
914    } else if (methodName == MagicNames.wordLT) {
915      s = _cmpHelper(bc2ir, gc, ConditionOperand.LOWER(), null);
916    } else if (methodName == MagicNames.wordLE) {
917      s = _cmpHelper(bc2ir, gc, ConditionOperand.LOWER_EQUAL(), null);
918    } else if (methodName == MagicNames.wordGT) {
919      s = _cmpHelper(bc2ir, gc, ConditionOperand.HIGHER(), null);
920    } else if (methodName == MagicNames.wordGE) {
921      s = _cmpHelper(bc2ir, gc, ConditionOperand.HIGHER_EQUAL(), null);
922    } else if (methodName == MagicNames.wordsLT) {
923      s = _cmpHelper(bc2ir, gc, ConditionOperand.LESS(), null);
924    } else if (methodName == MagicNames.wordsLE) {
925      s = _cmpHelper(bc2ir, gc, ConditionOperand.LESS_EQUAL(), null);
926    } else if (methodName == MagicNames.wordsGT) {
927      s = _cmpHelper(bc2ir, gc, ConditionOperand.GREATER(), null);
928    } else if (methodName == MagicNames.wordsGE) {
929      s = _cmpHelper(bc2ir, gc, ConditionOperand.GREATER_EQUAL(), null);
930    } else if (methodName == MagicNames.wordLsh) {
931      Operand op2 = bc2ir.popInt();
932      Operand op1 = bc2ir.popAddress();
933      s = bc2ir._binaryHelper(REF_SHL, op1, op2, resultType);
934    } else if (methodName == MagicNames.wordRshl) {
935      Operand op2 = bc2ir.popInt();
936      Operand op1 = bc2ir.popAddress();
937      s = bc2ir._binaryHelper(REF_USHR, op1, op2, resultType);
938    } else if (methodName == MagicNames.wordRsha) {
939      Operand op2 = bc2ir.popInt();
940      Operand op1 = bc2ir.popAddress();
941      s = bc2ir._binaryHelper(REF_SHR, op1, op2, resultType);
942    } else {
943      return false;
944    }
945    if (s != null) {
946      bc2ir.appendInstruction(s);
947    }
948    return true;
949  }
950
951  private static Instruction _cmpHelper(BC2IR bc2ir, GenerationContext gc, ConditionOperand cond,
952                                Operand given_o2) {
953    Operand o2 = given_o2 == null ? bc2ir.pop() : given_o2;
954    Operand o1 = bc2ir.pop();
955    RegisterOperand res = gc.getTemps().makeTempInt();
956    Instruction s = BooleanCmp.create(BOOLEAN_CMP_ADDR, res, o1, o2, cond, new BranchProfileOperand());
957    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
958    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
959      gc.getTemps().release(res);
960      bc2ir.push(Move.getClearVal(s));
961      return null;
962    } else {
963      bc2ir.push(res.copyD2U());
964      return s;
965    }
966  }
967
968  private static LocationOperand mapToMetadata(Operand metadata) {
969    if (metadata instanceof IntConstantOperand) {
970      int index = ((IntConstantOperand) metadata).value;
971      if (index == 0) return null;
972      MemberReference mr = MemberReference.getMemberRef(index);
973      return new LocationOperand(mr.asFieldReference());
974    }
975    return null;
976  }
977
978  private static final int LOAD_OP = 1;
979  private static final int PREPARE_OP = 2;
980  private static final int STORE_OP = 3;
981  private static final int ATTEMPT_OP = 4;
982
983  private static Operator getOperator(TypeReference type, int operatorClass)
984      throws MagicNotImplementedException {
985    if (operatorClass == LOAD_OP) {
986      if (type == TypeReference.Address) return REF_LOAD;
987      if (type == TypeReference.ObjectReference) return REF_LOAD;
988      if (type == TypeReference.Word) return REF_LOAD;
989      if (type == TypeReference.Offset) return REF_LOAD;
990      if (type == TypeReference.Extent) return REF_LOAD;
991      if (type == TypeReference.Int) return INT_LOAD;
992      if (type == TypeReference.Byte) return BYTE_LOAD;
993      if (type == TypeReference.Short) return SHORT_LOAD;
994      if (type == TypeReference.Char) return USHORT_LOAD;
995      if (type == TypeReference.Float) return FLOAT_LOAD;
996      if (type == TypeReference.Double) return DOUBLE_LOAD;
997      if (type == TypeReference.Long) return LONG_LOAD;
998    } else if (operatorClass == PREPARE_OP) {
999      if (type == TypeReference.Address) return PREPARE_ADDR;
1000      if (type == TypeReference.ObjectReference) return PREPARE_ADDR;
1001      if (type == TypeReference.Word) return PREPARE_ADDR;
1002      if (type == TypeReference.Int) return PREPARE_INT;
1003      if (type == TypeReference.Long) return PREPARE_LONG;
1004    } else if (operatorClass == ATTEMPT_OP) {
1005      if (type == TypeReference.Address) return ATTEMPT_ADDR;
1006      if (type == TypeReference.ObjectReference) return ATTEMPT_ADDR;
1007      if (type == TypeReference.Word) return ATTEMPT_ADDR;
1008      if (type == TypeReference.Int) return ATTEMPT_INT;
1009      if (type == TypeReference.Long) return ATTEMPT_LONG;
1010    } else if (operatorClass == STORE_OP) {
1011      if (type == TypeReference.Address) return REF_STORE;
1012      if (type == TypeReference.ObjectReference) return REF_STORE;
1013      if (type == TypeReference.Word) return REF_STORE;
1014      if (type == TypeReference.Offset) return REF_STORE;
1015      if (type == TypeReference.Extent) return REF_STORE;
1016      if (type == TypeReference.Int) return INT_STORE;
1017      if (type == TypeReference.Byte || type == TypeReference.Boolean) return BYTE_STORE;
1018      if (type == TypeReference.Short) return SHORT_STORE;
1019      if (type == TypeReference.Char) return SHORT_STORE;
1020      if (type == TypeReference.Float) return FLOAT_STORE;
1021      if (type == TypeReference.Double) return DOUBLE_STORE;
1022      if (type == TypeReference.Long) return LONG_STORE;
1023    }
1024    String msg = " Unexpected call to getOperator";
1025    throw MagicNotImplementedException.UNEXPECTED(msg);
1026  }
1027
1028  private static boolean isLoad(Atom methodName) {
1029    return isPrefix(MagicNames.loadPrefix, methodName.toByteArray());
1030  }
1031
1032  private static boolean isPrepare(Atom methodName) {
1033    return isPrefix(MagicNames.preparePrefix, methodName.toByteArray());
1034  }
1035
1036  /**
1037   * Is string <code>a</code> a prefix of string
1038   * <code>b</code>. String <code>b</code> is encoded as an ASCII byte
1039   * array.
1040   *
1041   * @param prefix  Prefix atom
1042   * @param b       String which may contain prefix, encoded as an ASCII
1043   * byte array.
1044   * @return <code>true</code> if <code>a</code> is a prefix of
1045   * <code>b</code>
1046   */
1047  @Interruptible
1048  private static boolean isPrefix(Atom prefix, byte[] b) {
1049    byte[] a = prefix.toByteArray();
1050    int aLen = a.length;
1051    if (aLen > b.length) {
1052      return false;
1053    }
1054    for (int i = 0; i < aLen; i++) {
1055      if (a[i] != b[i]) {
1056        return false;
1057      }
1058    }
1059    return true;
1060  }
1061
1062}