public static CilType CastMaybeGeneric(CilType castType, bool valueOnly, JavaCode code) { if (!castType.IsGenericParameter) { return(castType); } if (!valueOnly) { GenericUtil.ValueLoad(code); } var genericMark = CilMain.GenericStack.Mark(); var(resolvedType, resolvedIndex) = CilMain.GenericStack.Resolve(castType.JavaName); if (resolvedIndex == 0) { if (valueOnly) { // this flag is set when called from LoadFieldAddress. we can cast // the generic field to the actual type only if it is a value type if (resolvedType.IsValueClass) { castType = resolvedType; code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null); } else if (castType.IsByReference) { var boxedType = new BoxedType(resolvedType, false); code.NewInstruction(0xC0 /* checkcast */, boxedType, null); castType = boxedType; } } else { // this flag is clear whe called from LoadFieldValue and // PushMethodReturnType. we can cast to any known actual types. var arrayRank = castType.GetMethodGenericParameter()?.ArrayRank ?? 0; castType = (arrayRank == 0) ? resolvedType : resolvedType.AdjustRank(arrayRank); if (!castType.IsReference) { var boxedType = new BoxedType(castType, false); code.NewInstruction(0xC0 /* checkcast */, boxedType, null); boxedType.GetValue(code); } else { code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null); } } } CilMain.GenericStack.Release(genericMark); return(castType); }
void UnboxObject(Code cilOp, object data) { if (data is TypeReference typeRef) { var dataType = CilType.From(typeRef); if (dataType.IsValueClass) { if (dataType.IsGenericParameter) { if (cilOp == Code.Unbox_Any) { // unboxing (casting) a concrete type as a generic type var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where); if (stackTop.Equals(JavaType.ObjectType) || dataType.Equals(stackTop)) { code.NewInstruction(0x00 /* nop */, null, null); } else { code.NewInstruction(0xC0 /* checkcast */, dataType, null); } code.StackMap.PushStack(dataType); } else // plain Unbox { throw new InvalidProgramException(); } } else { code.StackMap.PopStack(CilMain.Where); code.NewInstruction(0xC0 /* checkcast */, dataType, null); code.StackMap.PushStack(dataType); } } else if (!dataType.IsReference) { var boxedType = new BoxedType(dataType, false); var fromType = code.StackMap.PopStack(CilMain.Where); if (!fromType.Equals(boxedType)) { code.NewInstruction(0xC0 /* checkcast */, boxedType, null); } boxedType.GetValue(code); code.StackMap.PushStack(dataType); } else { if (cilOp == Code.Unbox_Any) { NullCheck(); CastToClass(data); } else // plain Unbox { throw new InvalidProgramException(); } } } }
public static void BuildGenericProxy2(CilInterfaceMethod ifcMethod, CilMethod targetMethod, bool parentField, CilType intoType, JavaClass ifcClass) { // // create proxy method // var targetMethod2 = targetMethod.WithGenericParameters; var ifcMethod2 = ifcMethod.Method.WithGenericParameters; var newMethod = new JavaMethod(ifcClass, targetMethod2); newMethod.Name = ifcMethod2.Name; newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE; var code = newMethod.Code = new JavaCode(); code.Method = newMethod; code.Instructions = new List <JavaCode.Instruction>(); // // push a reference to the parent object // code.NewInstruction(0x19 /* aload */, null, (int)0); if (parentField) { code.NewInstruction(0xB4 /* getfield */, new JavaType(0, 0, ifcClass.Name), new JavaFieldRef(ParentFieldName, intoType)); } // // push all other parameters // int numArgs = newMethod.Parameters.Count; int index = 1; int maxStack = 1; for (int i = 0; i < numArgs; i++) { var ifcArg = ifcMethod2.Parameters[i].Type; code.NewInstruction(ifcArg.LoadOpcode, null, (int)index); index += ifcArg.Category; var clsArg = (CilType)targetMethod2.Parameters[i].Type; if (JavaType.ObjectType.Equals(ifcArg)) { if (!clsArg.IsReference) { var boxedArg = new BoxedType(clsArg, false); code.NewInstruction(0xC0 /* checkcast */, boxedArg, null); boxedArg.GetValue(code); } else if (!JavaType.ObjectType.Equals(clsArg)) { code.NewInstruction(0xC0 /* checkcast */, clsArg, null); } // a parameter in the target method may be a concrete type, // but if it is a generic java.lang.Object in the interface, // then it must be a generic java.lang.Object in the proxy newMethod.Parameters[i] = new JavaFieldRef("", ifcArg); } maxStack += clsArg.Category; } // // invoke proxy target method // code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod2); // // return value from method // var clsRet = (CilType)targetMethod2.ReturnType; var ifcRet = ifcMethod2.ReturnType; if (JavaType.ObjectType.Equals(ifcRet)) { if (!clsRet.IsReference) { var boxedArg = new BoxedType(clsRet, false); boxedArg.BoxValue(code); } // the return value in the target method may be a concrete type, // but if it is a generic java.lang.Object in the interface, // then it must also be a generic java.lang.Object in the proxy newMethod.ReturnType = ifcRet; code.NewInstruction(ifcRet.ReturnOpcode, null, null); } else { code.NewInstruction(clsRet.ReturnOpcode, null, null); } code.MaxLocals = index; code.MaxStack = maxStack; ifcClass.Methods.Add(newMethod); }