void LoadStoreField(Code op, object data) { bool ok = false; if (data is FieldReference fieldRef) { var fldName = CilMain.MakeValidMemberName(fieldRef.Name); var fldClass = CilMain.GenericStack.EnterType(fieldRef.DeclaringType); var fldType = ValueUtil.GetBoxedFieldType(fldClass, fieldRef); if (fldClass.Equals(JavaType.StringType) || fldClass.Equals(JavaType.ThrowableType)) { // generally we translate System.String to java.lang.String, // and System.Exception to java.lang.Throwable, // but not in the case of a field reference fldClass = CilType.From(new JavaType(0, 0, fldClass.JavaName)); } bool isLoad = (op != Code.Stfld && op != Code.Stsfld); bool isStatic = (op == Code.Ldsfld || op == Code.Ldsflda || op == Code.Stsfld); bool isAddress = (op == Code.Ldflda || op == Code.Ldsflda); bool isVolatile = CheckVolatile(fldType); if (isLoad) { if (isAddress) { ok = LoadFieldAddress(fldName, fldType, fldClass, isStatic); } else { ok = LoadFieldValue(fldName, fldType, fldClass, isStatic, isVolatile); } } else { ok = StoreFieldValue(fldName, fldType, fldClass, isStatic, isVolatile); } } if (!ok) { throw new InvalidProgramException(); } }
void InsertMethodInitCode() { if (method.IsStatic) { if ((!method.IsConstructor) && method.DeclType.HasGenericParameters) { // in a static method in a generic class, if the class has // a static initializer, then we want to start with a call to // GetType(), to force initialization of the static data class foreach (var m in defMethod.DeclaringType.Methods) { if (m.IsConstructor && m.IsStatic) { GenericUtil.LoadMaybeGeneric(method.DeclType, code); code.NewInstruction(0x57 /* pop */, null, null); code.StackMap.PopStack(CilMain.Where); break; } } } } else if (method.IsConstructor) { if (method.DeclType.HasGenericParameters) { // in a constructor of a generic class, we want to start // with a call to GetType() and store the result in the // $type field GenericUtil.InitializeTypeField(method.DeclType, code); } // init the array of generic interfaces InterfaceBuilder.InitInterfaceArrayField( method.DeclType, numCastableInterfaces, code, 0); // in any constructor, we want to allocate boxed instance fields ValueUtil.InitializeInstanceFields(newMethod.Class, method.DeclType, defMethodBody.Instructions, code); } }
int InitLocalsVars(MethodBody cilBody, List <CilType> localTypes, int nextIndex) { int highestIndex = -1; if (cilBody.HasVariables) { foreach (var cilVar in cilBody.Variables) { if (cilVar.Index > highestIndex) { highestIndex = cilVar.Index; } } } varToLocalMap = new int[highestIndex + 1]; if (cilBody.HasVariables) { foreach (var cilVar in cilBody.Variables) { CilMain.Where.Push("local #" + cilVar.Index); var genericMark = CilMain.GenericStack.Mark(); var varType = CilMain.GenericStack.EnterType(cilVar.VariableType); if (varType.IsValueClass || varType.IsPointer) { bool isByReference = varType.IsByReference; if (varType.IsPointer) { varType = CilType.MakeSpanOf(varType); } // value classes are allocated at the top of the method if (!isByReference) { ValueUtil.InitLocal(varType, nextIndex, code); varType = varType.MakeClonedAtTop(); } } else if (varType.IsByReference) { varType = new BoxedType(varType, false); } else if (varType.IsArray && varType.IsGenericParameter) { // note that GenericArrayType is compared by reference // in CodeArrays, to detect an array of a generic type T[] varType = CodeArrays.GenericArrayType; } varToLocalMap[cilVar.Index] = nextIndex; nextIndex += varType.Category; localTypes.Add(varType); while (nextIndex > localTypes.Count) { localTypes.Add(null); } CilMain.GenericStack.Release(genericMark); CilMain.Where.Pop(); } } return(nextIndex); }
internal static void BuildJavaClass(TypeDefinition cilType, JavaClass parentClass) { CilMain.Where.Push($"class '{cilType.FullName}'"); var genericMark = CilMain.GenericStack.Mark(); var myType = CilMain.GenericStack.EnterType(cilType); var jclass = new JavaClass(); jclass.Name = myType.JavaName; jclass.Flags = AttributesToAccessFlags(cilType.Attributes, myType.IsInterface); if (myType.IsInterface) { jclass.Super = JavaType.ObjectType.ClassName; // java.lang.Object } else if (cilType.BaseType != null) { var myBaseType = CilType.From(cilType.BaseType); jclass.Super = myBaseType.Equals(JavaType.ObjectType) ? JavaType.ObjectType.ClassName // java.lang.Object : myBaseType.JavaName; } else { throw CilMain.Where.Exception("missing base class"); } var myInterfaces = ImportInterfaces(jclass, myType, cilType); int numCastableInterfaces = myType.IsGenericThisOrSuper ? InterfaceBuilder.CastableInterfaceCount(myInterfaces) : 0; ImportFields(jclass, cilType, myType.IsRetainName); ImportMethods(jclass, cilType, numCastableInterfaces); if (myType.JavaName == "system.Convert") { DiscardBase64MethodsInConvertClass(jclass); } ValueUtil.InitializeStaticFields(jclass, myType); if (myType.IsValueClass) { ValueUtil.MakeValueClass(jclass, myType, numCastableInterfaces); } else if (myType.IsEnum) { ValueUtil.MakeEnumClass(jclass, myType, cilType.HasCustomAttribute("System.FlagsAttribute", true)); } else if (myType.IsDelegate) { var delegateInterface = Delegate.FixClass(jclass, myType); CilMain.JavaClasses.Add(delegateInterface); } // if derives directly from object, and does not implement ToString CodeBuilder.CreateToStringMethod(jclass); ResetFieldReferences(jclass); LinkClasses(jclass, parentClass, cilType); var interfaceClasses = InterfaceBuilder.BuildProxyMethods( myInterfaces, cilType, myType, jclass); if (interfaceClasses != null) { foreach (var childClass in interfaceClasses) { CilMain.JavaClasses.Add(childClass); } } if (myType.HasGenericParameters) { JavaClass dataClass; if (!myType.IsInterface) { dataClass = GenericUtil.MakeGenericClass(jclass, myType); if (dataClass != null) { CilMain.JavaClasses.Add(dataClass); } } else { dataClass = null; } JavaClass infoClass = jclass; if (myType.IsInterface) { // Android 'D8' desugars static methods on an interface by // moving into a separate class, so we do it ourselves. // see also system.RuntimeType.CreateGeneric() in baselib infoClass = CilMain.CreateInnerClass(jclass, jclass.Name + "$$info"); CilMain.JavaClasses.Add(infoClass); } GenericUtil.CreateGenericInfoMethod(infoClass, dataClass, myType); GenericUtil.CreateGenericVarianceField(infoClass, myType, cilType); } if (myType.IsGenericThisOrSuper) { jclass.Signature = GenericUtil.MakeGenericSignature(cilType, jclass.Super); if (!myInterfaces.Exists(x => x.InterfaceType.JavaName == "system.IGenericObject")) { if (!myType.IsInterface) { // create IGenericObject methods GetType and TryCast // only if class did not already implement IGenericObject if (!myType.HasGenericParameters) { GenericUtil.BuildGetTypeMethod(jclass, myType); } InterfaceBuilder.BuildTryCastMethod( myInterfaces, myType, numCastableInterfaces, jclass); } } } CilMain.GenericStack.Release(genericMark); CilMain.Where.Pop(); }
public static void ImportFields(JavaClass jclass, TypeDefinition cilType, bool isRetainName) { if (cilType.HasFields) { int n = cilType.Fields.Count; if (n > 0) { if (isRetainName) { throw CilMain.Where.Exception("fields not supported in a [RetainName] type"); } jclass.Fields = new List <JavaField>(n); for (int i = 0; i < n; i++) { var cilField = cilType.Fields[i]; CilMain.Where.Push($"field '{cilField.Name}'"); if (cilField.InitialValue.Length != 0) { throw CilMain.Where.Exception("unsupported InitialValue in field"); } var myField = new JavaField(); myField.Name = CilMain.MakeValidMemberName(cilField.Name); myField.Class = jclass; myField.Flags = AttributesToAccessFlags( cilField.Attributes, (cilType.HasNestedTypes || cilType.HasGenericParameters)); if (cilType.IsEnum) { myField.Type = CilType.From(cilField.FieldType); if (cilField.Constant != null) { myField.InitConstant(cilField.Constant, CilMain.Where); } } else { myField.Type = ValueUtil.GetBoxedFieldType(null, cilField); if (((CilType)myField.Type).IsValueClass) { myField.Constant = cilField; } else { if (cilField.Constant != null) { myField.InitConstant(cilField.Constant, CilMain.Where); } if (((CilType)myField.Type).IsVolatile) { myField.Flags |= JavaAccessFlags.ACC_VOLATILE; } } } jclass.Fields.Add(myField); CilMain.Where.Pop(); } } } }