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