/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir; import org.jikesrvm.ArchitectureSpecific.OPT_GenerateMachineSpecificMagic; import org.jikesrvm.VM; import static org.jikesrvm.VM_SizeConstants.LOG_BYTES_IN_ADDRESS; import static org.jikesrvm.VM_SizeConstants.LOG_BYTES_IN_INT; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_Field; import org.jikesrvm.classloader.VM_MemberReference; import org.jikesrvm.classloader.VM_MethodReference; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.OPT_MagicNotImplementedException; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2INT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2LONG; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ARRAYLENGTH; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_ADDR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_INT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_LONG; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_ADDR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BYTE_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BYTE_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CALL; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_AS_LONG_BITS; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_AS_INT_BITS; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_OBJ_TIB; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TIME_BASE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TYPE_FROM_TIB; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRSigExt; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRZerExt; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ADD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_BITS_AS_FLOAT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHL; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2ADDR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_BITS_AS_DOUBLE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PREPARE_ADDR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PREPARE_INT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PREPARE_LONG; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ADD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_AND; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_MOVE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_NOT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_OR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHL; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SUB; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_USHR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_XOR; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SHORT_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SHORT_STORE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SYSCALL; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.UBYTE_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.USHORT_LOAD; import org.jikesrvm.objectmodel.VM_TIBLayoutConstants; import org.jikesrvm.runtime.VM_ArchEntrypoints; import org.jikesrvm.runtime.VM_MagicNames; import org.jikesrvm.scheduler.VM_Scheduler; import org.vmmagic.pragma.Interruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * This class implements the non-machine-specific magics for the opt compiler. * By non-machine-specific we mean that the IR generated to implement the magic * is independent of the target-architecture. * It does not mean that the eventual MIR that implements the magic * won't differ from architecture to architecture. */ public class OPT_GenerateMagic implements VM_TIBLayoutConstants { /** * "Semantic inlining" of methods of the VM_Magic class. * Based on the methodName, generate a sequence of opt instructions * that implement the magic, updating the expression stack as necessary. * * @param bc2ir the bc2ir object that is generating the * ir containing this magic * @param gc must be bc2ir.gc * @param meth the VM_Method that is the magic method */ static boolean generateMagic(OPT_BC2IR bc2ir, OPT_GenerationContext gc, VM_MethodReference meth) throws OPT_MagicNotImplementedException { if (gc.method.hasNoInlinePragma()) gc.allocFrame = true; // HACK: Don't schedule any bbs containing unsafe magics. // TODO: move this to individual magics that are unsafe. // -- igor 08/13/1999 bc2ir.markBBUnsafeForScheduling(); VM_Atom methodName = meth.getName(); boolean address = (meth.getType() == VM_TypeReference.Address); // Address magic VM_TypeReference[] types = meth.getParameterTypes(); VM_TypeReference returnType = meth.getReturnType(); if (address && isLoad(methodName)) { // LOAD OPT_Operand offset = (types.length == 0) ? new OPT_AddressConstantOperand(Address.zero()) : bc2ir.popAddress(); OPT_Operand base = bc2ir.popAddress(); OPT_RegisterOperand result = gc.temps.makeTemp(returnType); bc2ir.appendInstruction(Load.create(getOperator(returnType, LOAD_OP), result, base, offset, null)); bc2ir.push(result.copyD2U(), returnType); } else if (address && isPrepare(methodName)) { // PREPARE OPT_Operand offset = (types.length == 0) ? new OPT_AddressConstantOperand(Address.zero()) : bc2ir.popAddress(); OPT_Operand base = bc2ir.popAddress(); OPT_RegisterOperand result = gc.temps.makeTemp(returnType); bc2ir.appendInstruction(Prepare.create(getOperator(returnType, PREPARE_OP), result, base, offset, null)); bc2ir.push(result.copyD2U(), returnType); } else if (address && methodName == VM_MagicNames.attempt) { // ATTEMPT VM_TypeReference attemptType = types[0]; OPT_Operand offset = (types.length == 2) ? new OPT_AddressConstantOperand(Address.zero()) : bc2ir.popAddress(); OPT_Operand newVal = bc2ir.pop(); OPT_Operand oldVal = bc2ir.pop(); OPT_Operand base = bc2ir.popAddress(); OPT_RegisterOperand test = gc.temps.makeTempInt(); bc2ir.appendInstruction(Attempt.create(getOperator(attemptType, ATTEMPT_OP), test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U(), returnType); } else if (address && methodName == VM_MagicNames.store) { // STORE VM_TypeReference storeType = types[0]; OPT_Operand offset = (types.length == 1) ? new OPT_AddressConstantOperand(Address.zero()) : bc2ir.popAddress(); OPT_Operand val = bc2ir.pop(storeType); OPT_Operand base = bc2ir.popAddress(); bc2ir.appendInstruction(Store.create(getOperator(storeType, STORE_OP), val, base, offset, null)); } else if (methodName == VM_MagicNames.getProcessorRegister) { OPT_RegisterOperand rop = gc.temps.makePROp(); bc2ir.markGuardlessNonNull(rop); bc2ir.push(rop); } else if (methodName == VM_MagicNames.setProcessorRegister) { OPT_Operand val = bc2ir.popRef(); if (val instanceof OPT_RegisterOperand) { bc2ir.appendInstruction(Move.create(REF_MOVE, gc.temps.makePROp(), val)); } else { String msg = " Unexpected operand VM_Magic.setProcessorRegister"; throw OPT_MagicNotImplementedException.UNEXPECTED(msg); } } else if (methodName == VM_MagicNames.addressArrayCreate) { OPT_Instruction s = bc2ir.generateAnewarray(meth.getType().getArrayElementType()); bc2ir.appendInstruction(s); } else if (methodName == VM_MagicNames.addressArrayLength) { OPT_Operand op1 = bc2ir.pop(); bc2ir.clearCurrentGuard(); if (bc2ir.do_NullCheck(op1)) { return true; } OPT_RegisterOperand t = gc.temps.makeTempInt(); OPT_Instruction s = GuardedUnary.create(ARRAYLENGTH, t, op1, bc2ir.getCurrentGuard()); bc2ir.push(t.copyD2U()); bc2ir.appendInstruction(s); } else if (methodName == VM_MagicNames.addressArrayGet) { VM_TypeReference elementType = meth.getType().getArrayElementType(); OPT_Operand index = bc2ir.popInt(); OPT_Operand ref = bc2ir.popRef(); OPT_RegisterOperand offsetI = gc.temps.makeTempInt(); OPT_RegisterOperand offset = gc.temps.makeTempOffset(); OPT_RegisterOperand result; if (meth.getType().isCodeArrayType()) { if (VM.BuildForIA32) { result = gc.temps.makeTemp(VM_TypeReference.Byte); bc2ir.appendInstruction(Load.create(BYTE_LOAD, result, ref, index, new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } else if (VM.BuildForPowerPC) { result = gc.temps.makeTemp(VM_TypeReference.Int); bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new OPT_IntConstantOperand(LOG_BYTES_IN_INT))); bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy())); bc2ir.appendInstruction(Load.create(INT_LOAD, result, ref, offset.copy(), new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } } else { result = gc.temps.makeTemp(elementType); bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new OPT_IntConstantOperand(LOG_BYTES_IN_ADDRESS))); bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy())); bc2ir.appendInstruction(Load.create(REF_LOAD, result, ref, offset.copy(), new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } bc2ir.push(result.copyD2U()); } else if (methodName == VM_MagicNames.addressArraySet) { VM_TypeReference elementType = meth.getType().getArrayElementType(); OPT_Operand val = bc2ir.pop(); OPT_Operand index = bc2ir.popInt(); OPT_Operand ref = bc2ir.popRef(); OPT_RegisterOperand offsetI = gc.temps.makeTempInt(); OPT_RegisterOperand offset = gc.temps.makeTempOffset(); if (meth.getType().isCodeArrayType()) { if (VM.BuildForIA32) { bc2ir.appendInstruction(Store.create(BYTE_STORE, val, ref, index, new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } else if (VM.BuildForPowerPC) { bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new OPT_IntConstantOperand(LOG_BYTES_IN_INT))); bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy())); bc2ir.appendInstruction(Store.create(INT_STORE, val, ref, offset.copy(), new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } } else { bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new OPT_IntConstantOperand(LOG_BYTES_IN_ADDRESS))); bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy())); bc2ir.appendInstruction(Store.create(REF_STORE, val, ref, offset.copy(), new OPT_LocationOperand(elementType), new OPT_TrueGuardOperand())); } } else if (methodName == VM_MagicNames.getIntAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTempInt(); bc2ir.appendInstruction(Load.create(INT_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setIntAtOffset) { OPT_Operand val = bc2ir.popInt(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(INT_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getWordAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Word); bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setWordAtOffset) { OPT_Operand val = bc2ir.popRef(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getLongAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTempLong(); bc2ir.appendInstruction(Load.create(LONG_LOAD, val, object, offset, null)); bc2ir.pushDual(val.copyD2U()); } else if (methodName == VM_MagicNames.setLongAtOffset) { OPT_Operand val = bc2ir.popLong(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(LONG_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getDoubleAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTempDouble(); bc2ir.appendInstruction(Load.create(DOUBLE_LOAD, val, object, offset, null)); bc2ir.pushDual(val.copyD2U()); } else if (methodName == VM_MagicNames.setDoubleAtOffset) { OPT_Operand val = bc2ir.popDouble(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(DOUBLE_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getObjectAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.getObjectArrayAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.JavaLangObjectArray); bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setObjectAtOffset) { OPT_LocationOperand loc = null; if (meth.getParameterTypes().length == 4) { loc = mapToMetadata(bc2ir.popInt()); } OPT_Operand val = bc2ir.popRef(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, loc)); } else if (methodName == VM_MagicNames.getByteAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Byte); bc2ir.appendInstruction(Load.create(BYTE_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.getUnsignedByteAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Byte); bc2ir.appendInstruction(Load.create(UBYTE_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setByteAtOffset) { OPT_Operand val = bc2ir.popInt(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(BYTE_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getShortAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Char); bc2ir.appendInstruction(Load.create(SHORT_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.getCharAtOffset) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Char); bc2ir.appendInstruction(Load.create(USHORT_LOAD, val, object, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setCharAtOffset) { OPT_Operand val = bc2ir.popInt(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand object = bc2ir.popRef(); bc2ir.appendInstruction(Store.create(SHORT_STORE, val, object, offset, null)); } else if (methodName == VM_MagicNames.getMemoryInt) { OPT_Operand memAddr = bc2ir.popAddress(); OPT_RegisterOperand val = gc.temps.makeTempInt(); bc2ir.appendInstruction(Load.create(INT_LOAD, val, memAddr, new OPT_AddressConstantOperand(Offset.zero()), null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.getMemoryWord) { OPT_Operand memAddr = bc2ir.popAddress(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Word); bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, new OPT_AddressConstantOperand(Offset.zero()), null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.getMemoryAddress) { OPT_Operand memAddr = bc2ir.popAddress(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Address); bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, new OPT_AddressConstantOperand(Offset.zero()), null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.setMemoryInt) { OPT_Operand val = bc2ir.popInt(); OPT_Operand memAddr = bc2ir.popAddress(); bc2ir.appendInstruction(Store.create(INT_STORE, val, memAddr, new OPT_AddressConstantOperand(Offset.zero()), null)); } else if (methodName == VM_MagicNames.setMemoryWord) { OPT_Operand val = bc2ir.popRef(); OPT_Operand memAddr = bc2ir.popAddress(); bc2ir.appendInstruction(Store.create(REF_STORE, val, memAddr, new OPT_AddressConstantOperand(Offset.zero()), null)); } else if (meth.isSysCall()) { // All methods of VM_SysCall have the following signature: // callNAME(Address functionAddress, <var args to pass via native calling convention>) // With POWEROPEN_ABI, functionAddress points to the function descriptor VM_TypeReference[] args = meth.getParameterTypes(); OPT_Instruction call = Call.create(SYSCALL, null, null, null, null, args.length - 1); for (int i = args.length - 1; i >= 1; i--) { Call.setParam(call, i - 1, bc2ir.pop(args[i])); } OPT_Operand functionAddress = bc2ir.pop(args[0]); Call.setAddress(call, functionAddress); if (!returnType.isVoidType()) { OPT_RegisterOperand op0 = gc.temps.makeTemp(returnType); Call.setResult(call, op0); bc2ir.push(op0.copyD2U(), returnType); } bc2ir.appendInstruction(call); } else if (meth.isSpecializedInvoke()) { // The callsite looks like RETURN = INVOKE (ID, OBJECT, P0, P1 .. PN) // And the actual method will look like RETURN = INVOKE (OBJECT, P0, P1 .. PN) // Create the call instruction OPT_Instruction call = Call.create(CALL, null, null, null, null, types.length - 1); // Plumb all of the normal parameters into the call for (int i = types.length - 1; i >= 2; i--) { Call.setParam(call, i - 1, bc2ir.pop(types[i])); } // The object being specialized OPT_Operand objectOperand = bc2ir.pop(types[1]); Call.setParam(call, 0, objectOperand); OPT_Operand guard = OPT_BC2IR.getGuard(objectOperand); if (guard == null) { // it's magic, so assume that it's OK.... guard = new OPT_TrueGuardOperand(); } Call.setGuard(call, guard); // Load the tib of this object OPT_RegisterOperand tibObject = gc.temps.makeTemp(VM_TypeReference.JavaLangObjectArray); bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibObject, objectOperand.copy(), guard.copy())); // The index of the specialized method OPT_Operand methodId = bc2ir.popInt(); // Add the base offset for specialized methods and convert from index to address OPT_RegisterOperand tibOffset = gc.temps.makeTemp(VM_TypeReference.Int); bc2ir.appendInstruction(Binary.create(INT_ADD, tibOffset, methodId, new OPT_IntConstantOperand(TIB_FIRST_SPECIALIZED_METHOD_INDEX))); bc2ir.appendInstruction(Binary.create(INT_SHL, tibOffset.copyRO(), tibOffset.copyD2U(), new OPT_IntConstantOperand(LOG_BYTES_IN_ADDRESS))); // Load the code address from the TIB OPT_RegisterOperand codeAddress = gc.temps.makeTemp(VM_TypeReference.Address); bc2ir.appendInstruction(Load.create(REF_LOAD, codeAddress, tibObject.copyD2U(), tibOffset.copyD2U(), null)); Call.setAddress(call, codeAddress.copyD2U()); if (!returnType.isVoidType()) { OPT_RegisterOperand op0 = gc.temps.makeTemp(returnType); Call.setResult(call, op0); bc2ir.push(op0.copyD2U(), returnType); } bc2ir.appendInstruction(call); } else if (methodName == VM_MagicNames.threadAsCollectorThread) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.VM_CollectorThread); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsType) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.VM_Type); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsProcessor) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_Scheduler.getProcessorType()); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsThread) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_Scheduler.getThreadType()); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsAddress) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.Address); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.addressAsObject) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.addressAsObjectArray) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.JavaLangObjectArray); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.addressAsByteArray) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.ByteArray); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsShortArray) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.ShortArray); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.objectAsIntArray) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.IntArray); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.floatAsIntBits) { OPT_Operand val = bc2ir.popFloat(); OPT_RegisterOperand op0 = gc.temps.makeTempInt(); bc2ir.appendInstruction(Unary.create(FLOAT_AS_INT_BITS, op0, val)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.intBitsAsFloat) { OPT_Operand val = bc2ir.popInt(); OPT_RegisterOperand op0 = gc.temps.makeTempFloat(); bc2ir.appendInstruction(Unary.create(INT_BITS_AS_FLOAT, op0, val)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.doubleAsLongBits) { OPT_Operand val = bc2ir.popDouble(); OPT_RegisterOperand op0 = gc.temps.makeTempLong(); bc2ir.appendInstruction(Unary.create(DOUBLE_AS_LONG_BITS, op0, val)); bc2ir.pushDual(op0.copyD2U()); } else if (methodName == VM_MagicNames.longBitsAsDouble) { OPT_Operand val = bc2ir.popLong(); OPT_RegisterOperand op0 = gc.temps.makeTempDouble(); bc2ir.appendInstruction(Unary.create(LONG_BITS_AS_DOUBLE, op0, val)); bc2ir.pushDual(op0.copyD2U()); } else if (methodName == VM_MagicNames.getObjectType) { OPT_Operand val = bc2ir.popRef(); if(val.isObjectConstant()) { bc2ir.push(new OPT_ObjectConstantOperand(val.getType().peekType(), Offset.zero())); } else { OPT_Operand guard = OPT_BC2IR.getGuard(val); if (guard == null) { // it's magic, so assume that it's OK.... guard = new OPT_TrueGuardOperand(); } OPT_RegisterOperand tibPtr = gc.temps.makeTemp(VM_TypeReference.JavaLangObjectArray); bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibPtr, val, guard)); OPT_RegisterOperand op0; VM_TypeReference argType = val.getType(); if (argType.isArrayType()) { op0 = gc.temps.makeTemp(VM_TypeReference.VM_Array); } else { if (argType == VM_TypeReference.JavaLangObject || argType == VM_TypeReference.JavaLangCloneable || argType == VM_TypeReference.JavaIoSerializable) { // could be an array or a class, so make op0 be a VM_Type op0 = gc.temps.makeTemp(VM_TypeReference.VM_Type); } else { op0 = gc.temps.makeTemp(VM_TypeReference.VM_Class); } } bc2ir.markGuardlessNonNull(op0); bc2ir.appendInstruction(Unary.create(GET_TYPE_FROM_TIB, op0, tibPtr.copyD2U())); bc2ir.push(op0.copyD2U()); } } else if (methodName == VM_MagicNames.getArrayLength) { OPT_Operand val = bc2ir.popRef(); OPT_RegisterOperand op0 = gc.temps.makeTempInt(); bc2ir.appendInstruction(GuardedUnary.create(ARRAYLENGTH, op0, val, new OPT_TrueGuardOperand())); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.invokeClassInitializer) { OPT_Instruction s = Call.create0(CALL, null, bc2ir.popRef(), null); bc2ir.appendInstruction(s); } else if ((methodName == VM_MagicNames.invokeMethodReturningObject) || (methodName == VM_MagicNames.invokeMethodReturningVoid) || (methodName == VM_MagicNames.invokeMethodReturningLong) || (methodName == VM_MagicNames.invokeMethodReturningDouble) || (methodName == VM_MagicNames.invokeMethodReturningFloat) || (methodName == VM_MagicNames.invokeMethodReturningInt)) { OPT_Operand spills = bc2ir.popRef(); OPT_Operand fprmeta = bc2ir.popRef(); OPT_Operand fprs = bc2ir.popRef(); OPT_Operand gprs = bc2ir.popRef(); OPT_Operand code = bc2ir.popRef(); OPT_RegisterOperand res = null; if (methodName == VM_MagicNames.invokeMethodReturningObject) { res = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.push(res.copyD2U()); } else if (methodName == VM_MagicNames.invokeMethodReturningLong) { res = gc.temps.makeTemp(VM_TypeReference.Long); bc2ir.push(res.copyD2U(), VM_TypeReference.Long); } else if (methodName == VM_MagicNames.invokeMethodReturningDouble) { res = gc.temps.makeTempDouble(); bc2ir.push(res.copyD2U(), VM_TypeReference.Double); } else if (methodName == VM_MagicNames.invokeMethodReturningFloat) { res = gc.temps.makeTempFloat(); bc2ir.push(res.copyD2U(), VM_TypeReference.Float); } else if (methodName == VM_MagicNames.invokeMethodReturningInt) { res = gc.temps.makeTempInt(); bc2ir.push(res.copyD2U()); } VM_Field target = VM_ArchEntrypoints.reflectiveMethodInvokerInstructionsField; OPT_MethodOperand met = OPT_MethodOperand.STATIC(target); OPT_Instruction s = Call.create5(CALL, res, new OPT_AddressConstantOperand(target.getOffset()), met, code, gprs, fprs, fprmeta, spills); bc2ir.appendInstruction(s); } else if (methodName == VM_MagicNames.saveThreadState) { OPT_Operand p1 = bc2ir.popRef(); VM_Field target = VM_ArchEntrypoints.saveThreadStateInstructionsField; OPT_MethodOperand mo = OPT_MethodOperand.STATIC(target); bc2ir.appendInstruction(Call.create1(CALL, null, new OPT_AddressConstantOperand(target.getOffset()), mo, p1)); } else if (methodName == VM_MagicNames.threadSwitch) { OPT_Operand p2 = bc2ir.popRef(); OPT_Operand p1 = bc2ir.popRef(); VM_Field target = VM_ArchEntrypoints.threadSwitchInstructionsField; OPT_MethodOperand mo = OPT_MethodOperand.STATIC(target); bc2ir.appendInstruction(Call.create2(CALL, null, new OPT_AddressConstantOperand(target.getOffset()), mo, p1, p2)); } else if (methodName == VM_MagicNames.restoreHardwareExceptionState) { VM_Field target = VM_ArchEntrypoints.restoreHardwareExceptionStateInstructionsField; OPT_MethodOperand mo = OPT_MethodOperand.STATIC(target); bc2ir.appendInstruction(Call.create1(CALL, null, new OPT_AddressConstantOperand(target.getOffset()), mo, bc2ir.popRef())); } else if (methodName == VM_MagicNames.prepareInt) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTempInt(); bc2ir.appendInstruction(Prepare.create(PREPARE_INT, val, base, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.prepareLong) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTempLong(); bc2ir.appendInstruction(Prepare.create(PREPARE_LONG, val, base, offset, null)); bc2ir.pushDual(val.copyD2U()); } else if (methodName == VM_MagicNames.prepareObject) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.prepareAddress) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Address); bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.prepareWord) { OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand val = gc.temps.makeTemp(VM_TypeReference.Word); bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null)); bc2ir.push(val.copyD2U()); } else if (methodName == VM_MagicNames.attemptInt) { OPT_Operand newVal = bc2ir.popInt(); OPT_Operand oldVal = bc2ir.popInt(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand test = gc.temps.makeTempBoolean(); bc2ir.appendInstruction(Attempt.create(ATTEMPT_INT, test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U()); } else if (methodName == VM_MagicNames.attemptLong) { OPT_Operand newVal = bc2ir.popLong(); OPT_Operand oldVal = bc2ir.popLong(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand test = gc.temps.makeTempBoolean(); bc2ir.appendInstruction(Attempt.create(ATTEMPT_LONG, test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U()); } else if (methodName == VM_MagicNames.attemptObject) { OPT_Operand newVal = bc2ir.popRef(); OPT_Operand oldVal = bc2ir.popRef(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand test = gc.temps.makeTempBoolean(); bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U()); } else if (methodName == VM_MagicNames.attemptAddress) { OPT_Operand newVal = bc2ir.popAddress(); OPT_Operand oldVal = bc2ir.popAddress(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand test = gc.temps.makeTempBoolean(); bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U()); } else if (methodName == VM_MagicNames.attemptWord) { OPT_Operand newVal = bc2ir.pop(); OPT_Operand oldVal = bc2ir.pop(); OPT_Operand offset = bc2ir.popAddress(); OPT_Operand base = bc2ir.popRef(); OPT_RegisterOperand test = gc.temps.makeTempBoolean(); bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null)); bc2ir.push(test.copyD2U()); } else if (generatePolymorphicMagic(bc2ir, gc, meth, methodName)) { return true; } else if (methodName == VM_MagicNames.getTimeBase) { OPT_RegisterOperand op0 = gc.temps.makeTempLong(); bc2ir.appendInstruction(Nullary.create(GET_TIME_BASE, op0)); bc2ir.pushDual(op0.copyD2U()); } else { // Wasn't machine-independent, so try the machine-dependent magics next. return OPT_GenerateMachineSpecificMagic.generateMagic(bc2ir, gc, meth); } return true; } // generateMagic // Generate magic where the untype operational semantics is identified by name. // The operands' types are determined from the method signature. // static boolean generatePolymorphicMagic(OPT_BC2IR bc2ir, OPT_GenerationContext gc, VM_MethodReference meth, VM_Atom methodName) { VM_TypeReference resultType = meth.getReturnType(); if (methodName == VM_MagicNames.wordFromInt || methodName == VM_MagicNames.wordFromIntSignExtend) { OPT_RegisterOperand reg = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(INT_2ADDRSigExt, reg, bc2ir.popInt())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordFromIntZeroExtend) { OPT_RegisterOperand reg = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, reg, bc2ir.popInt())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordFromLong) { if (VM.BuildFor64Addr) { OPT_RegisterOperand reg = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(LONG_2ADDR, reg, bc2ir.popLong())); bc2ir.push(reg.copyD2U()); } else { VM._assert(false); //should not reach } } else if (methodName == VM_MagicNames.wordToInt) { OPT_RegisterOperand reg = gc.temps.makeTempInt(); bc2ir.appendInstruction(Unary.create(ADDR_2INT, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToLong) { OPT_RegisterOperand lreg = gc.temps.makeTempLong(); bc2ir.appendInstruction(Unary.create(ADDR_2LONG, lreg, bc2ir.popAddress())); bc2ir.pushDual(lreg.copyD2U()); } else if (methodName == VM_MagicNames.wordToWord) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.Word); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToAddress) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.Address); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToObject) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToObjectReference || methodName == VM_MagicNames.wordFromObject) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.ObjectReference); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToOffset) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.Offset); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordToExtent) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.Extent); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress())); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.codeArrayAsObject) { OPT_RegisterOperand reg = gc.temps.makeTemp(VM_TypeReference.JavaLangObject); bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.pop(VM_TypeReference.CodeArray))); bc2ir.push(reg.copyD2U()); } else if (methodName == VM_MagicNames.wordPlus) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); if (VM.BuildFor64Addr && o2.isInt()) { OPT_RegisterOperand op1 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(INT_2ADDRSigExt, op1, o2)); bc2ir.appendInstruction(Binary.create(REF_ADD, op0, o1, op1.copyD2U())); } else { bc2ir.appendInstruction(Binary.create(REF_ADD, op0, o1, o2)); } bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordMinus) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); if (VM.BuildFor64Addr && o2.isInt()) { OPT_RegisterOperand op1 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(INT_2ADDRSigExt, op1, o2)); bc2ir.appendInstruction(Binary.create(REF_SUB, op0, o1, op1)); } else { bc2ir.appendInstruction(Binary.create(REF_SUB, op0, o1, o2)); } bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordDiff) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_SUB, op0, o1, o2)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordAnd) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_AND, op0, o1, o2)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordOr) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_OR, op0, o1, o2)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordXor) { OPT_Operand o2 = bc2ir.pop(); OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_XOR, op0, o1, o2)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordNot) { OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Unary.create(REF_NOT, op0, o1)); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordZero || methodName == VM_MagicNames.wordNull) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.zero()))); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordOne) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.fromIntZeroExtend(1)))); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordMax) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.max()))); bc2ir.push(op0.copyD2U()); } else if (methodName == VM_MagicNames.wordIsNull) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.zero()))); OPT_ConditionOperand cond = OPT_ConditionOperand.EQUAL(); cmpHelper(bc2ir, gc, cond, op0.copyRO()); } else if (methodName == VM_MagicNames.wordIsZero) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.zero()))); OPT_ConditionOperand cond = OPT_ConditionOperand.EQUAL(); cmpHelper(bc2ir, gc, cond, op0.copyRO()); } else if (methodName == VM_MagicNames.wordIsMax) { OPT_RegisterOperand op0 = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Move.create(REF_MOVE, op0, new OPT_AddressConstantOperand(Address.max()))); OPT_ConditionOperand cond = OPT_ConditionOperand.EQUAL(); cmpHelper(bc2ir, gc, cond, op0.copyRO()); } else if (methodName == VM_MagicNames.wordEQ) { OPT_ConditionOperand cond = OPT_ConditionOperand.EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordNE) { OPT_ConditionOperand cond = OPT_ConditionOperand.NOT_EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordLT) { OPT_ConditionOperand cond = OPT_ConditionOperand.LOWER(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordLE) { OPT_ConditionOperand cond = OPT_ConditionOperand.LOWER_EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordGT) { OPT_ConditionOperand cond = OPT_ConditionOperand.HIGHER(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordGE) { OPT_ConditionOperand cond = OPT_ConditionOperand.HIGHER_EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordsLT) { OPT_ConditionOperand cond = OPT_ConditionOperand.LESS(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordsLE) { OPT_ConditionOperand cond = OPT_ConditionOperand.LESS_EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordsGT) { OPT_ConditionOperand cond = OPT_ConditionOperand.GREATER(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordsGE) { OPT_ConditionOperand cond = OPT_ConditionOperand.GREATER_EQUAL(); cmpHelper(bc2ir, gc, cond, null); } else if (methodName == VM_MagicNames.wordLsh) { OPT_Operand op2 = bc2ir.popInt(); OPT_Operand op1 = bc2ir.popAddress(); OPT_RegisterOperand res = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_SHL, res, op1, op2)); bc2ir.push(res.copyD2U()); } else if (methodName == VM_MagicNames.wordRshl) { OPT_Operand op2 = bc2ir.popInt(); OPT_Operand op1 = bc2ir.popAddress(); OPT_RegisterOperand res = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_USHR, res, op1, op2)); bc2ir.push(res.copyD2U()); } else if (methodName == VM_MagicNames.wordRsha) { OPT_Operand op2 = bc2ir.popInt(); OPT_Operand op1 = bc2ir.popAddress(); OPT_RegisterOperand res = gc.temps.makeTemp(resultType); bc2ir.appendInstruction(Binary.create(REF_SHR, res, op1, op2)); bc2ir.push(res.copyD2U()); } else { return false; } return true; } private static void cmpHelper(OPT_BC2IR bc2ir, OPT_GenerationContext gc, OPT_ConditionOperand cond, OPT_Operand given_o2) { OPT_Operand o2 = given_o2 == null ? bc2ir.pop() : given_o2; OPT_Operand o1 = bc2ir.pop(); OPT_RegisterOperand res = gc.temps.makeTempInt(); bc2ir.appendInstruction(BooleanCmp.create(BOOLEAN_CMP_ADDR, res.copyRO(), o1, o2, cond, new OPT_BranchProfileOperand())); bc2ir.push(res.copyD2U()); } private static OPT_LocationOperand mapToMetadata(OPT_Operand metadata) { if (metadata instanceof OPT_IntConstantOperand) { int index = ((OPT_IntConstantOperand) metadata).value; if (index == 0) return null; VM_MemberReference mr = VM_MemberReference.getMemberRef(index); return new OPT_LocationOperand(mr.asFieldReference()); } return null; } private static final int LOAD_OP = 1; private static final int PREPARE_OP = 2; private static final int STORE_OP = 3; private static final int ATTEMPT_OP = 4; private static OPT_Operator getOperator(VM_TypeReference type, int operatorClass) throws OPT_MagicNotImplementedException { if (operatorClass == LOAD_OP) { if (type == VM_TypeReference.Address) return REF_LOAD; if (type == VM_TypeReference.ObjectReference) return REF_LOAD; if (type == VM_TypeReference.Word) return REF_LOAD; if (type == VM_TypeReference.Offset) return REF_LOAD; if (type == VM_TypeReference.Extent) return REF_LOAD; if (type == VM_TypeReference.Int) return INT_LOAD; if (type == VM_TypeReference.Byte) return BYTE_LOAD; if (type == VM_TypeReference.Short) return SHORT_LOAD; if (type == VM_TypeReference.Char) return USHORT_LOAD; if (type == VM_TypeReference.Float) return FLOAT_LOAD; if (type == VM_TypeReference.Double) return DOUBLE_LOAD; if (type == VM_TypeReference.Long) return LONG_LOAD; } else if (operatorClass == PREPARE_OP) { if (type == VM_TypeReference.Address) return PREPARE_ADDR; if (type == VM_TypeReference.ObjectReference) return PREPARE_ADDR; if (type == VM_TypeReference.Word) return PREPARE_ADDR; if (type == VM_TypeReference.Int) return PREPARE_INT; if (type == VM_TypeReference.Long) return PREPARE_LONG; } else if (operatorClass == ATTEMPT_OP) { if (type == VM_TypeReference.Address) return ATTEMPT_ADDR; if (type == VM_TypeReference.ObjectReference) return ATTEMPT_ADDR; if (type == VM_TypeReference.Word) return ATTEMPT_ADDR; if (type == VM_TypeReference.Int) return ATTEMPT_INT; if (type == VM_TypeReference.Long) return ATTEMPT_LONG; } else if (operatorClass == STORE_OP) { if (type == VM_TypeReference.Address) return REF_STORE; if (type == VM_TypeReference.ObjectReference) return REF_STORE; if (type == VM_TypeReference.Word) return REF_STORE; if (type == VM_TypeReference.Offset) return REF_STORE; if (type == VM_TypeReference.Extent) return REF_STORE; if (type == VM_TypeReference.Int) return INT_STORE; if (type == VM_TypeReference.Byte) return BYTE_STORE; if (type == VM_TypeReference.Short) return SHORT_STORE; if (type == VM_TypeReference.Char) return SHORT_STORE; if (type == VM_TypeReference.Float) return FLOAT_STORE; if (type == VM_TypeReference.Double) return DOUBLE_STORE; if (type == VM_TypeReference.Long) return LONG_STORE; } String msg = " Unexpected call to getOperator"; throw OPT_MagicNotImplementedException.UNEXPECTED(msg); } private static boolean isLoad(VM_Atom methodName) { return isPrefix(VM_MagicNames.loadPrefix, methodName.toByteArray()); } private static boolean isPrepare(VM_Atom methodName) { return isPrefix(VM_MagicNames.preparePrefix, methodName.toByteArray()); } /** * Is string <code>a</code> a prefix of string * <code>b</code>. String <code>b</code> is encoded as an ASCII byte * array. * * @param prefix Prefix atom * @param b String which may contain prefix, encoded as an ASCII * byte array. * @return <code>true</code> if <code>a</code> is a prefix of * <code>b</code> */ @Interruptible private static boolean isPrefix(VM_Atom prefix, byte[] b) { byte[] a = prefix.toByteArray(); int aLen = a.length; if (aLen > b.length) { return false; } for (int i = 0; i < aLen; i++) { if (a[i] != b[i]) { return false; } } return true; } }