public static bool CheckCast(CilType castType, bool @throw, JavaCode code) { if (object.ReferenceEquals(castType, GenericArrayType) || (castType.IsArray && (castType.IsInterface || castType.IsGenericParameter || castType.ClassName == JavaType.ObjectType.ClassName || castType.ClassName == CilType.SystemValueType.ClassName))) { // if casting to Object[], ValueType[], to an array of interface type, // or to an array of a generic parameter, we can't rely on a simple // 'checkcast' or 'instanceof', because the jvm will permit the cast // of a value type array to the aforementioned reference types. // // instead, we generate a call to system.Array.CheckCast in baselib, // except if we are generating code for the system.Array class itself. if (code.Method.Class.Name.StartsWith("system.Array")) { return(false); } // note the caller of this method already popped the stack once. // which we have to undo that, before we push anything else. code.StackMap.PushStack(JavaType.ObjectType); // array var method = new JavaMethodRef("CheckCast", JavaType.ObjectType); method.Parameters.Add(new JavaFieldRef("", JavaType.ObjectType)); if (object.ReferenceEquals(castType, GenericArrayType) || castType.IsGenericParameter) { method.Parameters.Add(new JavaFieldRef("", CilType.SystemTypeType)); GenericUtil.LoadMaybeGeneric(castType, code); // CilType.SystemTypeType pushed to the stack } else { method.Parameters.Add(new JavaFieldRef("", JavaType.ClassType)); code.NewInstruction(0x12 /* ldc */, castType.AdjustRank(-1), null); code.StackMap.PushStack(JavaType.ClassType); } method.Parameters.Add(new JavaFieldRef("", JavaType.BooleanType)); code.NewInstruction(0x12 /* ldc */, null, (int)(@throw ? 1 : 0)); code.StackMap.PushStack(JavaType.IntegerType); // boolean code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, method); code.StackMap.PopStack(CilMain.Where); // boolean code.StackMap.PopStack(CilMain.Where); // class/type code.StackMap.PopStack(CilMain.Where); // array return(true); } return(false); }
public static void LoadMaybeGeneric(CilType loadType, JavaCode code) { if (loadType.IsGenericParameter) { LoadGeneric(loadType.JavaName, code); } else { // all GetType variants take a first parameter of type java.lang.Class List <JavaFieldRef> parameters = new List <JavaFieldRef>(); parameters.Add(new JavaFieldRef("", JavaType.ClassType)); int arrayRank = loadType.ArrayRank; if (arrayRank == 0 || (!loadType.IsGenericParameter)) { code.NewInstruction(0x12 /* ldc */, loadType.AsWritableClass, null); } else { // for a generic type T[], we want to load just the element T, // and then (see below) call MakeArrayType on the result var loadTypeElem = loadType.AdjustRank(-arrayRank); code.NewInstruction(0x12 /* ldc */, loadTypeElem.AsWritableClass, null); } code.StackMap.PushStack(JavaType.ClassType); if (loadType.HasGenericParameters) { LoadGenericInstance(loadType, parameters, code); } code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType, new JavaMethodRef("GetType", CilType.SystemTypeType, parameters)); for (int i = 0; i < parameters.Count; i++) { code.StackMap.PopStack(CilMain.Where); } code.StackMap.PushStack(CilType.SystemTypeType); if (arrayRank != 0 && loadType.IsGenericParameter) { code.NewInstruction(0x12 /* ldc */, null, (int)arrayRank); code.StackMap.PushStack(JavaType.IntegerType); code.NewInstruction(0xB6 /* invokevirtual */, CilType.SystemTypeType, new JavaMethodRef("MakeArrayType", CilType.SystemTypeType, JavaType.IntegerType)); code.StackMap.PopStack(CilMain.Where); } } }
public void Address(CilType arrayType) { stackMap.PopStack(CilMain.Where); // index if (arrayType == null) { arrayType = (CilType)stackMap.PopStack(CilMain.Where); } else { stackMap.PopStack(CilMain.Where); // array } var elemType = arrayType.AdjustRank(-arrayType.ArrayRank); if (elemType.IsReference) { if (elemType.IsGenericParameter) { // call system.Array.Box(object array, int index) code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, new JavaMethodRef("Box", CilType.SystemValueType, JavaType.ObjectType, JavaType.IntegerType)); } else if (elemType.IsValueClass) { code.NewInstruction(0x32 /* aaload */, null, null); } else { // call system.Reference.Box(object a, int i) elemType = new BoxedType(elemType, false); code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, JavaType.ObjectType, JavaType.IntegerType)); } stackMap.PushStack(elemType); } else { // call system.(PrimitiveType).Box(primitiveType[] a, int i) var typeCode = elemType.PrimitiveType; stackMap.PushStack(new BoxedType(elemType, false)); arrayType = elemType.AdjustRank(1); elemType = elemType.AsWritableClass; code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, arrayType, JavaType.IntegerType)); } }
void Load(CilType arrayType, CilType elemType, Mono.Cecil.Cil.Instruction inst) { if (arrayType == null) { arrayType = elemType.AdjustRank(1); } /*Console.WriteLine("(LOAD) ARRAY TYPE = " + arrayType + "," + arrayType.ArrayRank + " ELEM TYPE = " + elemType + "," + elemType.ArrayRank + " ELEMVAL? " + elemType.IsValueClass + " ELEMGEN? " + elemType.IsGenericParameter);*/ if (object.ReferenceEquals(arrayType, GenericArrayType) || elemType.IsGenericParameter || arrayType.IsGenericParameter) { code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, LoadArrayMethod); if (elemType.ArrayRank != 0) { elemType = GenericArrayType; } } else { if (elemType.PrimitiveType == TypeCode.Int16 && (arrayType.PrimitiveType == TypeCode.Char || arrayType.PrimitiveType == TypeCode.UInt16)) { // ldelem.i2 with a char[] array, should be 'caload' not 'saload' elemType = arrayType.AdjustRank(-arrayType.ArrayRank); } code.NewInstruction(elemType.LoadArrayOpcode, null, null); if (arrayType.IsValueClass || elemType.IsValueClass) { CilMethod.ValueMethod(CilMethod.ValueClone, code); } } stackMap.PushStack(elemType); }
public void Load(Code op, object data, Mono.Cecil.Cil.Instruction inst) { stackMap.PopStack(CilMain.Where); // pop index CilType arrayType = (CilType)stackMap.PopStack(CilMain.Where); CilType elemType = null; TypeCode elemCode = 0; switch (op) { case Code.Ldelem_Ref: if (arrayType.IsValueClass) { throw new InvalidProgramException(); } elemType = arrayType.AdjustRank(-1); break; case Code.Ldelem_Any: //if (data is ArrayType || (! (data is TypeReference))) if (!(data is TypeReference)) { throw new InvalidProgramException(); } elemType = CilType.From((TypeReference)data); // check if array element is loaded and boxed, only to check // its type or check if null. in this case we take a shortcut // and load directly from the array, without making a copy. var next = inst.Next; if (next != null && next.OpCode.Code == Code.Box) { next = next.Next; if (next != null && CodeBuilder.IsBrTrueBrFalseIsInst(next.OpCode.Code)) { code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, "java.lang.reflect.Array"), new JavaMethodRef("get", JavaType.ObjectType, JavaType.ObjectType, JavaType.IntegerType)); stackMap.PushStack(elemType); return; } } break; case Code.Ldelem_I1: case Code.Ldelem_U1: elemCode = TypeCode.Byte; break; case Code.Ldelem_U2: elemCode = TypeCode.Char; break; case Code.Ldelem_I2: elemCode = TypeCode.Int16; break; case Code.Ldelem_I4: case Code.Ldelem_U4: elemCode = TypeCode.Int32; break; case Code.Ldelem_I8: case Code.Ldelem_I: elemCode = TypeCode.Int64; break; case Code.Ldelem_R4: elemCode = TypeCode.Single; break; case Code.Ldelem_R8: elemCode = TypeCode.Double; break; default: throw new InvalidProgramException(); } if (elemCode != 0) { elemType = CilType.From(new JavaType(elemCode, 0, null)); } Load(arrayType, elemType, inst); }
public void Address(CilType arrayType, Mono.Cecil.Cil.Instruction inst) { stackMap.PopStack(CilMain.Where); // index if (arrayType == null) { arrayType = (CilType)stackMap.PopStack(CilMain.Where); } else { stackMap.PopStack(CilMain.Where); // array } var elemType = arrayType.AdjustRank(-arrayType.ArrayRank); if (inst != null && inst.Next != null) { var(spanType, _) = locals.GetLocalFromStoreInst( inst.Next.OpCode.Code, inst.Next.Operand); if (CodeSpan.AddressArray(elemType, spanType, code)) { return; } } if (elemType.IsReference) { if (elemType.IsGenericParameter) { // call system.Array.Box(object array, int index) code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, new JavaMethodRef("Box", CilType.SystemValueType, JavaType.ObjectType, JavaType.IntegerType)); } else if (elemType.IsValueClass) { code.NewInstruction(0x32 /* aaload */, null, null); } else { // call system.Reference.Box(object a, int i) elemType = new BoxedType(elemType, false); code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, JavaType.ObjectType, JavaType.IntegerType)); } stackMap.PushStack(elemType); } else { // call system.(PrimitiveType).Box(primitiveType[] a, int i) var typeCode = elemType.PrimitiveType; stackMap.PushStack(new BoxedType(elemType, false)); arrayType = elemType.AdjustRank(1); elemType = elemType.AsWritableClass; code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, arrayType, JavaType.IntegerType)); } }
void Load(CilType arrayType, CilType elemType, Mono.Cecil.Cil.Instruction inst) { if (arrayType == null) { arrayType = elemType.AdjustRank(1); } /*Console.WriteLine("(LOAD) ARRAY TYPE = " + arrayType + "," + arrayType.ArrayRank + " ELEM TYPE = " + elemType + "," + elemType.ArrayRank + " ELEMVAL? " + elemType.IsValueClass + " ELEMGEN? " + elemType.IsGenericParameter);*/ if (object.ReferenceEquals(arrayType, GenericArrayType) || elemType.IsGenericParameter || arrayType.IsGenericParameter) { code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, LoadArrayMethod); if (elemType.ArrayRank != 0) { elemType = GenericArrayType; } } else { if (elemType.PrimitiveType == TypeCode.Int16 && (arrayType.PrimitiveType == TypeCode.Char || arrayType.PrimitiveType == TypeCode.UInt16)) { // ldelem.i2 with a char[] array, should be 'caload' not 'saload' elemType = arrayType.AdjustRank(-arrayType.ArrayRank); } code.NewInstruction(elemType.LoadArrayOpcode, null, null); if (elemType.PrimitiveType == TypeCode.Byte) { // unsigned byte result should be truncated to 8-bits // (unless already followed by "ldc.i4 255 ; and") bool followedByAndWith255 = CodeBuilder.IsLoadConstant(inst.Next) == 0xFF && inst.Next.Next?.OpCode.Code == Code.And; if (!followedByAndWith255) { stackMap.PushStack(JavaType.IntegerType); code.NewInstruction(0x12 /* ldc */, null, (int)0xFF); code.NewInstruction(0x7E /* iand */, null, null); stackMap.PopStack(CilMain.Where); } } if (arrayType.IsValueClass || elemType.IsValueClass) { CilMethod.ValueMethod(CilMethod.ValueClone, code); if (elemType.IsValueClass) { code.NewInstruction(0xC0 /* checkcast */, elemType, null); } } } stackMap.PushStack(elemType); }