/** * Emit an implicit conversion for an argument which must be of the given pclass. * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface. * * @param ptype type of value present on stack * @param pclass type of value required on stack * @param arg compile-time representation of value on stack (Node, constant) or null if none */ private void emitImplicitConversion(BasicType ptype, Class pclass, object arg) { //assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller if (pclass == ptype.basicTypeClass() && ptype != BasicType.L_TYPE) { return; // nothing to do } switch (ptype.name()) { case "L_TYPE": if (VerifyType.isNullConversion(CoreClasses.java.lang.Object.Wrapper.ClassObject, pclass, false)) { //if (PROFILE_LEVEL > 0) // emitReferenceCast(Object.class, arg); return; } emitReferenceCast(pclass, arg); return; case "I_TYPE": if (!VerifyType.isNullConversion(java.lang.Integer.TYPE, pclass, false)) { emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass)); } return; } throw new BailoutException(Bailout.PreconditionViolated, "bad implicit conversion: tc=" + ptype + ": " + pclass); }
private void emitPushArgument(Class ptype, object arg) { BasicType bptype = BasicType.basicType(ptype); if (arg is Name) { Name n = (Name)arg; emitLoadInsn(n._type(), n.index()); emitImplicitConversion(n._type(), ptype, n); } else if ((arg == null || arg is string) && bptype == BasicType.L_TYPE) { emitConst(arg); } else { if (Wrapper.isWrapperType(ikvm.extensions.ExtensionMethods.getClass(arg)) && bptype != BasicType.L_TYPE) { emitConst(arg); } else { EmitConstant(arg); emitImplicitConversion(BasicType.L_TYPE, ptype, arg); } } }
private void emitI2X(Wrapper type) { switch (type.name()) { case "BYTE": ilgen.Emit(OpCodes.Conv_I1); break; case "SHORT": ilgen.Emit(OpCodes.Conv_I2); break; case "CHAR": ilgen.Emit(OpCodes.Conv_U2); break; case "INT": /* naught */ break; case "LONG": ilgen.Emit(OpCodes.Conv_I8); break; case "FLOAT": ilgen.Emit(OpCodes.Conv_R4); break; case "DOUBLE": ilgen.Emit(OpCodes.Conv_R8); break; case "BOOLEAN": // For compatibility with ValueConversions and explicitCastArguments: ilgen.EmitLdc_I4(1); ilgen.Emit(OpCodes.And); break; default: throw new BailoutException(Bailout.PreconditionViolated, "unknown type: " + type); } }
private byte arrayTypeCode(Wrapper elementType) { switch (elementType.name()) { case "BOOLEAN": return(Opcodes.T_BOOLEAN); case "BYTE": return(Opcodes.T_BYTE); case "CHAR": return(Opcodes.T_CHAR); case "SHORT": return(Opcodes.T_SHORT); case "INT": return(Opcodes.T_INT); case "LONG": return(Opcodes.T_LONG); case "FLOAT": return(Opcodes.T_FLOAT); case "DOUBLE": return(Opcodes.T_DOUBLE); case "OBJECT": return(0); // in place of Opcodes.T_OBJECT default: throw new BailoutException(Bailout.PreconditionViolated, "elemendType = " + elementType); } }
void emitNewArray(Name name) { Class rtype = name.function.methodType().returnType(); if (name.arguments.Length == 0) { // The array will be a constant. object emptyArray; try { emptyArray = name.function._resolvedHandle().invoke(); } catch (Exception ex) { throw new java.lang.InternalError(ex); } //assert(java.lang.reflect.Array.getLength(emptyArray) == 0); //assert(emptyArray.getClass() == rtype); // exact typing //mv.visitLdcInsn(constantPlaceholder(emptyArray)); EmitConstant(emptyArray); emitReferenceCast(rtype, emptyArray); return; } Class arrayElementType = rtype.getComponentType(); //assert(arrayElementType != null); emitIconstInsn(name.arguments.Length); OpCode xas = OpCodes.Stelem_Ref; if (!arrayElementType.isPrimitive()) { TypeWrapper tw = TypeWrapper.FromClass(arrayElementType); if (tw.IsUnloadable || tw.IsGhost || tw.IsGhostArray || tw.IsNonPrimitiveValueType) { throw new BailoutException(Bailout.UnsupportedArrayType, tw); } ilgen.Emit(OpCodes.Newarr, tw.TypeAsArrayType); } else { byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType)); xas = arrayInsnOpcode(tc); //mv.visitIntInsn(Opcodes.NEWARRAY, tc); ilgen.Emit(OpCodes.Newarr, TypeWrapper.FromClass(arrayElementType).TypeAsArrayType); } // store arguments for (int i = 0; i < name.arguments.Length; i++) { //mv.visitInsn(Opcodes.DUP); ilgen.Emit(OpCodes.Dup); emitIconstInsn(i); emitPushArgument(name, i); //mv.visitInsn(xas); ilgen.Emit(xas); } // the array is left on the stack assertStaticType(rtype, name); }
void emitArrayLoad(Name name) { OpCode arrayOpcode = OpCodes.Ldelem_Ref; Class elementType = name.function.methodType().parameterType(0).getComponentType(); emitPushArguments(name); if (elementType.isPrimitive()) { Wrapper w = Wrapper.forPrimitiveType(elementType); arrayOpcode = arrayLoadOpcode(arrayTypeCode(w)); } ilgen.Emit(arrayOpcode); }
private void emitX2I(Wrapper type) { switch (type.name()) { case "LONG": ilgen.Emit(OpCodes.Conv_I4); break; case "FLOAT": ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2i); break; case "DOUBLE": ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2i); break; default: throw new BailoutException(Bailout.PreconditionViolated, "unknown type: " + type); } }
/** * Emit a type conversion bytecode casting from "from" to "to". */ private void emitPrimCast(Wrapper from, Wrapper to) { // Here's how. // - indicates forbidden // <-> indicates implicit // to ----> boolean byte short char int long float double // from boolean <-> - - - - - - - // byte - <-> i2s i2c <-> i2l i2f i2d // short - i2b <-> i2c <-> i2l i2f i2d // char - i2b i2s <-> <-> i2l i2f i2d // int - i2b i2s i2c <-> i2l i2f i2d // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <-> if (from == to) { // no cast required, should be dead code anyway return; } if (from.isSubwordOrInt()) { // cast from {byte,short,char,int} to anything emitI2X(to); } else { // cast from {long,float,double} to anything if (to.isSubwordOrInt()) { // cast to {byte,short,char,int} emitX2I(from); if (to.bitWidth() < 32) { // targets other than int require another conversion emitI2X(to); } } else { // cast to {long,float,double} - this is verbose bool error = false; switch (from.name()) { case "LONG": switch (to.name()) { case "FLOAT": ilgen.Emit(OpCodes.Conv_R4); break; case "DOUBLE": ilgen.Emit(OpCodes.Conv_R8); break; default: error = true; break; } break; case "FLOAT": switch (to.name()) { case "LONG": ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2l); break; case "DOUBLE": ilgen.Emit(OpCodes.Conv_R8); break; default: error = true; break; } break; case "DOUBLE": switch (to.name()) { case "LONG": ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2l); break; case "FLOAT": ilgen.Emit(OpCodes.Conv_R4); break; default: error = true; break; } break; default: error = true; break; } if (error) { throw new BailoutException(Bailout.PreconditionViolated, "unhandled prim cast: " + from + "2" + to); } } } }
/** * Emit a type conversion bytecode casting from "from" to "to". */ private void emitPrimCast(Wrapper from, Wrapper to) { // Here's how. // - indicates forbidden // <-> indicates implicit // to ----> boolean byte short char int long float double // from boolean <-> - - - - - - - // byte - <-> i2s i2c <-> i2l i2f i2d // short - i2b <-> i2c <-> i2l i2f i2d // char - i2b i2s <-> <-> i2l i2f i2d // int - i2b i2s i2c <-> i2l i2f i2d // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <-> if (from == to) { // no cast required, should be dead code anyway return; } if (from.isSubwordOrInt()) { // cast from {byte,short,char,int} to anything emitI2X(to); } else { // cast from {long,float,double} to anything if (to.isSubwordOrInt()) { // cast to {byte,short,char,int} emitX2I(from); if (to.bitWidth() < 32) { // targets other than int require another conversion emitI2X(to); } } else { // cast to {long,float,double} - this is verbose bool error = false; switch (from.name()) { case "LONG": switch (to.name()) { case "FLOAT": ilgen.Emit(OpCodes.Conv_R4); break; case "DOUBLE": ilgen.Emit(OpCodes.Conv_R8); break; default: error = true; break; } break; case "FLOAT": switch (to.name()) { case "LONG": ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2l); break; case "DOUBLE": ilgen.Emit(OpCodes.Conv_R8); break; default: error = true; break; } break; case "DOUBLE": switch (to.name()) { case "LONG" : ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2l); break; case "FLOAT": ilgen.Emit(OpCodes.Conv_R4); break; default: error = true; break; } break; default: error = true; break; } if (error) { throw new BailoutException(Bailout.PreconditionViolated, "unhandled prim cast: " + from + "2" + to); } } } }
private byte arrayTypeCode(Wrapper elementType) { switch (elementType.name()) { case "BOOLEAN": return Opcodes.T_BOOLEAN; case "BYTE": return Opcodes.T_BYTE; case "CHAR": return Opcodes.T_CHAR; case "SHORT": return Opcodes.T_SHORT; case "INT": return Opcodes.T_INT; case "LONG": return Opcodes.T_LONG; case "FLOAT": return Opcodes.T_FLOAT; case "DOUBLE": return Opcodes.T_DOUBLE; case "OBJECT": return 0; // in place of Opcodes.T_OBJECT default: throw new BailoutException(Bailout.PreconditionViolated, "elemendType = " + elementType); } }