internal static FieldInfo GetClassLiteralField(Type type) { Debug.Assert(type != Types.Void); if (classLiteralType == null) { #if STATIC_COMPILER classLiteralType = JVM.CoreAssembly.GetType("ikvm.internal.ClassLiteral`1"); #elif !FIRST_PASS classLiteralType = typeof([email protected] <>); #endif } #if !STATIC_COMPILER if (!IsTypeBuilder(type)) { return(classLiteralType.MakeGenericType(type).GetField("Value", BindingFlags.Public | BindingFlags.Static)); } #endif if (classLiteralField == null) { classLiteralField = classLiteralType.GetField("Value", BindingFlags.Public | BindingFlags.Static); } #if !NOEMIT return(TypeBuilder.GetField(classLiteralType.MakeGenericType(type), classLiteralField)); #else return(null); #endif }
internal static Type GetAttributeReturnValueType(Type attributeType) { return(genericAttributeAnnotationReturnValueType.MakeGenericType(attributeType)); }
internal static Type GetAttributeMultipleType(Type attributeType) { return(genericAttributeAnnotationMultipleType.MakeGenericType(attributeType)); }
internal static Type GetDelegateType(Type delegateType) { return(genericDelegateInterfaceType.MakeGenericType(delegateType)); }
internal static Type GetEnumType(Type enumType) { return(genericEnumEnumType.MakeGenericType(enumType)); }
MethodInfo GetEnumeratorInfo(TypeModel model, out MethodInfo moveNext, out MethodInfo current) { #if WINRT TypeInfo enumeratorType = null, iteratorType, expectedType = ExpectedType.GetTypeInfo(); #else Type enumeratorType = null, iteratorType, expectedType = ExpectedType; #endif // try a custom enumerator MethodInfo getEnumerator = Helpers.GetInstanceMethod(expectedType, "GetEnumerator", null); Type itemType = Tail.ExpectedType; if (getEnumerator != null) { iteratorType = getEnumerator.ReturnType #if WINRT .GetTypeInfo() #endif ; moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext", null); PropertyInfo prop = Helpers.GetProperty(iteratorType, "Current"); current = prop == null ? null : Helpers.GetGetMethod(prop, false); if (moveNext == null && (model.MapType(ienumeratorType).IsAssignableFrom(iteratorType))) { moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext", null); } // fully typed if (moveNext != null && moveNext.ReturnType == model.MapType(typeof(bool)) && current != null && current.ReturnType == itemType) { return(getEnumerator); } moveNext = current = getEnumerator = null; } #if !NO_GENERICS // try IEnumerable<T> Type tmp = model.MapType(typeof(System.Collections.Generic.IEnumerable <>), false); if (tmp != null) { tmp = tmp.MakeGenericType(itemType); #if WINRT enumeratorType = tmp.GetTypeInfo(); #else enumeratorType = tmp; #endif } ; if (enumeratorType != null && enumeratorType.IsAssignableFrom(expectedType)) { getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator"); #if WINRT iteratorType = getEnumerator.ReturnType.GetTypeInfo(); #else iteratorType = getEnumerator.ReturnType; #endif moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext"); current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType, "Current"), false); return(getEnumerator); } #endif // give up and fall-back to non-generic IEnumerable enumeratorType = model.MapType(ienumerableType); getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator"); iteratorType = getEnumerator.ReturnType #if WINRT .GetTypeInfo() #endif ; moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext"); current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType, "Current"), false); return(getEnumerator); }
internal static Type GetAttributeType(Type type) { return(genericType.MakeGenericType(type)); }
void WriteIL(LineWriter lw, MethodBase mb, MethodBody body, Type[] genericTypeArguments, Type[] genericMethodArguments) { ParameterInfo[] parameters = mb.GetParameters(); int level = lw.Column; byte[] code = body.GetILAsByteArray(); lw.GoToColumn(level); lw.WriteLine("// Code size {0} (0x{0:x})", code.Length); lw.GoToColumn(level); lw.WriteLine(".maxstack {0}", body.MaxStackSize); IList <LocalVariableInfo> locals = body.LocalVariables; if (locals.Count != 0) { lw.GoToColumn(level); lw.Write(".locals "); if (body.InitLocals) { lw.Write("init "); } lw.Write("("); bool first = true; foreach (var local in locals) { if (!first) { lw.WriteLine(","); lw.GoToColumn(level + 9); } first = false; WriteSignatureType(lw, local.LocalType, TypeLocation.Local); if (local.IsPinned) { lw.Write(" pinned"); } WriteCustomModifiers(lw, local.__GetCustomModifiers()); lw.Write(" V_{0}", local.LocalIndex); } lw.WriteLine(")"); } var exceptions = new List <ExceptionHandlingClause>(); var exceptions2 = new List <ExceptionHandlingClause>(); SortExceptions(body.ExceptionHandlingClauses, exceptions, exceptions2); Stack <ExceptionHandlingClause> activeExceptions = new Stack <ExceptionHandlingClause>(); ExceptionHandlingClause currentException = null; bool extraNewLine = false; int nextFlatException = 0; int nextException = 0; bool handler = false; int pos = 0; while (pos < code.Length) { if (extraNewLine) { lw.WriteLine(); extraNewLine = false; } if (currentException != null) { if (currentException.HandlerOffset == pos) { switch (currentException.Flags) { case ExceptionHandlingClauseOptions.Clause: lw.GoToColumn(level - 2); if (currentException.TryOffset + currentException.TryLength == pos) { lw.WriteLine("} // end .try"); } else { lw.WriteLine("} // end handler"); } lw.GoToColumn(level - 2); lw.Write("catch "); if (currentException.CatchType.__IsMissing || !currentException.CatchType.IsGenericType) { WriteTypeDefOrRef(lw, currentException.CatchType); } else { WriteSignatureType(lw, currentException.CatchType); } lw.WriteLine(" "); lw.GoToColumn(level - 2); lw.WriteLine("{"); handler = true; break; case ExceptionHandlingClauseOptions.Finally: lw.GoToColumn(level - 2); lw.WriteLine("} // end .try"); lw.GoToColumn(level - 2); lw.WriteLine("finally"); lw.GoToColumn(level - 2); lw.WriteLine("{"); break; case ExceptionHandlingClauseOptions.Fault: lw.GoToColumn(level - 2); lw.WriteLine("} // end .try"); lw.GoToColumn(level - 2); lw.WriteLine("fault"); lw.GoToColumn(level - 2); lw.WriteLine("{"); break; case ExceptionHandlingClauseOptions.Filter: lw.GoToColumn(level - 2); lw.WriteLine("} // end filter"); lw.GoToColumn(level - 2); lw.WriteLine("{ // handler"); handler = true; break; default: throw new IKVM.Reflection.BadImageFormatException(); } } else if (currentException.FilterOffset == pos && pos != 0) { lw.GoToColumn(level - 2); if (handler) { lw.WriteLine("} // end handler"); } else { lw.WriteLine("} // end .try"); } lw.GoToColumn(level - 2); lw.WriteLine("filter"); lw.GoToColumn(level - 2); lw.WriteLine("{"); } } while (nextException < exceptions.Count && exceptions[nextException].TryOffset == pos) { activeExceptions.Push(currentException); ExceptionHandlingClause prevException = currentException; currentException = exceptions[nextException++]; if (prevException != null && currentException.TryOffset == prevException.TryOffset && currentException.TryLength == prevException.TryLength) { // another handler for the same block continue; } handler = false; lw.GoToColumn(level); lw.WriteLine(".try"); lw.GoToColumn(level); lw.WriteLine("{"); level += 2; } lw.GoToColumn(level); int currPos = pos; lw.Write("IL_{0:x4}: ", pos); int level1 = lw.Column; short opcodeValue = code[pos++]; if (opcodeValue == 0xFE) { opcodeValue = (short)(0xFE00 + code[pos++]); } OpCode opcode = opcodes[opcodeValue + 512]; lw.Write("{0}", opcode.Name); switch (opcode.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineBrTarget: lw.GoToColumn(level1 + 11); lw.Write("IL_{0:x4}", ReadInt32(code, ref pos) + pos); break; case OperandType.ShortInlineBrTarget: lw.GoToColumn(level1 + 11); lw.Write("IL_{0:x4}", (sbyte)code[pos++] + pos); break; case OperandType.InlineMethod: { lw.GoToColumn(level1 + 11); int token = ReadInt32(code, ref pos); MethodBase methodOrConstructor = ResolveMethod(token, genericTypeArguments, genericMethodArguments); if ((methodOrConstructor.CallingConvention & CallingConventions.Any) == CallingConventions.VarArgs) { CustomModifiers[] customModifiers; Type[] optionalParameterTypes = ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers); WriteInlineMethod(lw, methodOrConstructor, optionalParameterTypes, customModifiers); } else { WriteInlineMethod(lw, methodOrConstructor, Type.EmptyTypes, null); } } break; case OperandType.InlineField: lw.GoToColumn(level1 + 11); WriteInlineField(lw, ResolveField(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments)); break; case OperandType.InlineI: lw.GoToColumn(level1 + 11); WriteInlineI(lw, ReadInt32(code, ref pos)); break; case OperandType.InlineI8: lw.GoToColumn(level1 + 11); WriteInlineI8(lw, ReadInt64(code, ref pos)); break; case OperandType.ShortInlineI: lw.GoToColumn(level1 + 11); lw.Write("{0}", (sbyte)code[pos++]); break; case OperandType.InlineR: lw.GoToColumn(level1 + 11); WriteInlineR(lw, ReadDouble(code, ref pos), false); break; case OperandType.ShortInlineR: lw.GoToColumn(level1 + 11); WriteShortInlineR(lw, ReadSingle(code, ref pos), false); break; case OperandType.InlineType: if (opcode == OpCodes.Constrained) { // "constrained." is too long to fit in the opcode column lw.Write(" "); } else { lw.GoToColumn(level1 + 11); } WriteInlineType(lw, ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments); break; case OperandType.InlineTok: { int token = ReadInt32(code, ref pos); switch (token >> 24) { case 0x01: case 0x02: lw.GoToColumn(level1 + 11); WriteTypeDefOrRef(lw, ResolveType(token, genericTypeArguments, genericMethodArguments)); break; case 0x1B: { Type type = ResolveType(token, genericTypeArguments, genericMethodArguments); if (type.IsGenericTypeDefinition) { // HACK because typeof(Foo<>).MakeGenericType(typeof(Foo<>).GetGenericArguments()) == typeof(Foo<>) // we need to inflate the builder here type = type.MakeGenericType(type.GetGenericArguments()); } lw.GoToColumn(level1 + 11); WriteSignatureType(lw, type); break; } case 0x04: case 0x06: case 0x0A: case 0x2B: { MemberInfo member = ResolveMember(token, genericTypeArguments, genericMethodArguments); if (member is FieldInfo) { lw.GoToColumn(level1 + 11); lw.Write("field "); WriteInlineField(lw, (FieldInfo)member); } else { var mb1 = (MethodBase)member; lw.GoToColumn(level1 + 11); if (mb1.__IsMissing || !mb1.IsGenericMethod || compat != CompatLevel.V20) { lw.Write("method "); } WriteInlineMethod(lw, mb1, Type.EmptyTypes, null); } break; } default: throw new NotImplementedException("token type = " + (token >> 24)); } } break; case OperandType.InlineVar: lw.GoToColumn(level1 + 11); WriteInlineVar(lw, mb, opcode, parameters, ReadInt16(code, ref pos)); break; case OperandType.ShortInlineVar: lw.GoToColumn(level1 + 11); WriteInlineVar(lw, mb, opcode, parameters, code[pos++]); break; case OperandType.InlineString: lw.GoToColumn(level1 + 11); WriteInlineString(lw, module.ResolveString(ReadInt32(code, ref pos)), level); break; case OperandType.InlineSwitch: { lw.GoToColumn(level1 + 11); lw.WriteLine("( "); int count = ReadInt32(code, ref pos); int offset = pos + 4 * count; for (int i = 0; i < count - 1; i++) { lw.GoToColumn(level + 22); lw.WriteLine("IL_{0:x4},", offset + ReadInt32(code, ref pos)); } lw.GoToColumn(level + 22); lw.Write("IL_{0:x4})", offset + ReadInt32(code, ref pos)); } break; case OperandType.InlineSig: lw.GoToColumn(level1 + 11); WriteStandAloneMethodSig(lw, module.__ResolveStandAloneMethodSig(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments), false, false); break; default: throw new InvalidOperationException(); } lw.WriteLine(); if (opcode == OpCodes.Leave || opcode == OpCodes.Leave_S) { if (pos < code.Length) { lw.WriteLine(); } } else if (opcode != OpCodes.Switch && opcode != OpCodes.Rethrow && opcode != OpCodes.Endfilter && opcode != OpCodes.Endfinally) { switch (opcode.FlowControl) { case FlowControl.Branch: case FlowControl.Cond_Branch: case FlowControl.Throw: case FlowControl.Return: extraNewLine = true; break; } } if (nextFlatException < exceptions2.Count && exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength == currPos) { if (extraNewLine && pos < code.Length) { extraNewLine = false; lw.WriteLine(); } lw.GoToColumn(level); if (exceptions2[nextFlatException].FilterOffset == 0) { lw.Write(".try IL_{0:x4} to IL_{1:x4} catch ", exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength); if (exceptions2[nextFlatException].CatchType.__IsMissing || !exceptions2[nextFlatException].CatchType.IsGenericType) { WriteTypeDefOrRef(lw, exceptions2[nextFlatException].CatchType); } else { WriteSignatureType(lw, exceptions2[nextFlatException].CatchType); } lw.WriteLine(" handler IL_{0:x4} to IL_{1:x4}", exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength); } else { lw.WriteLine(".try IL_{0:x4} to IL_{1:x4} filter IL_{2:x4} handler IL_{3:x4} to IL_{4:x4}", exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength, exceptions2[nextFlatException].FilterOffset, exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength); } nextFlatException++; } while (currentException != null && currentException.HandlerOffset + currentException.HandlerLength == pos) { ExceptionHandlingClause prevException = currentException; currentException = activeExceptions.Pop(); if (currentException == null || currentException.TryOffset != prevException.TryOffset || currentException.TryLength != prevException.TryLength) { if (extraNewLine && pos < code.Length) { extraNewLine = false; lw.WriteLine(); } level -= 2; lw.GoToColumn(level); lw.WriteLine("} // end handler"); handler = false; } else { handler = true; } } } }
internal static bool IdentifyImmutable(TypeModel model, Type declaredType, out MethodInfo builderFactory, out MethodInfo add, out MethodInfo addRange, out MethodInfo finish) { builderFactory = add = addRange = finish = null; if (model == null || declaredType == null) { return(false); } #if WINRT || COREFX TypeInfo declaredTypeInfo = declaredType.GetTypeInfo(); #else Type declaredTypeInfo = declaredType; #endif // try to detect immutable collections; firstly, they are all generic, and all implement IReadOnlyCollection<T> for some T if (!declaredTypeInfo.IsGenericType) { return(false); } #if WINRT || COREFX Type[] typeArgs = declaredTypeInfo.GenericTypeArguments, effectiveType; #else Type[] typeArgs = declaredTypeInfo.GetGenericArguments(), effectiveType; #endif switch (typeArgs.Length) { case 1: effectiveType = typeArgs; break; // fine case 2: Type kvp = model.MapType(typeof(System.Collections.Generic.KeyValuePair <,>)); if (kvp == null) { return(false); } kvp = kvp.MakeGenericType(typeArgs); effectiveType = new Type[] { kvp }; break; default: return(false); // no clue! } if (ResolveIReadOnlyCollection(declaredType, null) == null) { return(false); // no IReadOnlyCollection<T> found } // and we want to use the builder API, so for generic Foo<T> or IFoo<T> we want to use Foo.CreateBuilder<T> string name = declaredType.Name; int i = name.IndexOf('`'); if (i <= 0) { return(false); } name = declaredTypeInfo.IsInterface ? name.Substring(1, i - 1) : name.Substring(0, i); Type outerType = model.GetType(declaredType.Namespace + "." + name, declaredTypeInfo.Assembly); // I hate special-cases... if (outerType == null && name == "ImmutableSet") { outerType = model.GetType(declaredType.Namespace + ".ImmutableHashSet", declaredTypeInfo.Assembly); } if (outerType == null) { return(false); } #if WINRT foreach (MethodInfo method in outerType.GetTypeInfo().DeclaredMethods) #else foreach (MethodInfo method in outerType.GetMethods()) #endif { if (!method.IsStatic || method.Name != "CreateBuilder" || !method.IsGenericMethodDefinition || method.GetParameters().Length != 0 || method.GetGenericArguments().Length != typeArgs.Length) { continue; } builderFactory = method.MakeGenericMethod(typeArgs); break; } Type voidType = model.MapType(typeof(void)); if (builderFactory == null || builderFactory.ReturnType == null || builderFactory.ReturnType == voidType) { return(false); } add = Helpers.GetInstanceMethod(builderFactory.ReturnType, "Add", effectiveType); if (add == null) { return(false); } finish = Helpers.GetInstanceMethod(builderFactory.ReturnType, "ToImmutable", Helpers.EmptyTypes); if (finish == null || finish.ReturnType == null || finish.ReturnType == voidType) { return(false); } if (!(finish.ReturnType == declaredType || Helpers.IsAssignableFrom(declaredType, finish.ReturnType))) { return(false); } addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { declaredType }); if (addRange == null) { Type enumerable = model.MapType(typeof(System.Collections.Generic.IEnumerable <>), false); if (enumerable != null) { addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { enumerable.MakeGenericType(effectiveType) }); } } return(true); }
internal TypeWrapper LoadGenericClass(string name) { // generic class name grammar: // // mangled(open_generic_type_name) "_$$$_" M(parameter_class_name) ( "_$$_" M(parameter_class_name) )* "_$$$$_" // // mangled() is the normal name mangling algorithm // M() is a replacement of "__" with "$$005F$$005F" followed by a replace of "." with "__" // int pos = name.IndexOf("_$$$_"); if (pos <= 0 || !name.EndsWith("_$$$$_")) { return(null); } Type type = GetGenericTypeDefinition(DotNetTypeWrapper.DemangleTypeName(name.Substring(0, pos))); if (type == null) { return(null); } List <string> typeParamNames = new List <string>(); pos += 5; int start = pos; int nest = 0; for (;;) { pos = name.IndexOf("_$$", pos); if (pos == -1) { return(null); } if (name.IndexOf("_$$_", pos, 4) == pos) { if (nest == 0) { typeParamNames.Add(name.Substring(start, pos - start)); start = pos + 4; } pos += 4; } else if (name.IndexOf("_$$$_", pos, 5) == pos) { nest++; pos += 5; } else if (name.IndexOf("_$$$$_", pos, 6) == pos) { if (nest == 0) { if (pos + 6 != name.Length) { return(null); } typeParamNames.Add(name.Substring(start, pos - start)); break; } nest--; pos += 6; } else { pos += 3; } } Type[] typeArguments = new Type[typeParamNames.Count]; for (int i = 0; i < typeArguments.Length; i++) { string s = (string)typeParamNames[i]; // only do the unmangling for non-generic types (because we don't want to convert // the double underscores in two adjacent _$$$_ or _$$$$_ markers) if (s.IndexOf("_$$$_") == -1) { s = s.Replace("__", "."); s = s.Replace("$$005F$$005F", "__"); } int dims = 0; while (s.Length > dims && s[dims] == 'A') { dims++; } if (s.Length == dims) { return(null); } TypeWrapper tw = null; switch (s[dims]) { case 'L': tw = LoadClassByDottedNameFast(s.Substring(dims + 1)); tw.Finish(); break; case 'Z': tw = PrimitiveTypeWrapper.BOOLEAN; break; case 'B': tw = PrimitiveTypeWrapper.BYTE; break; case 'S': tw = PrimitiveTypeWrapper.SHORT; break; case 'C': tw = PrimitiveTypeWrapper.CHAR; break; case 'I': tw = PrimitiveTypeWrapper.INT; break; case 'F': tw = PrimitiveTypeWrapper.FLOAT; break; case 'J': tw = PrimitiveTypeWrapper.LONG; break; case 'D': tw = PrimitiveTypeWrapper.DOUBLE; break; } if (tw == null) { return(null); } if (dims > 0) { tw = tw.MakeArrayType(dims); } typeArguments[i] = tw.TypeAsSignatureType; } try { type = type.MakeGenericType(typeArguments); } catch (ArgumentException) { // one of the typeArguments failed to meet the constraints return(null); } TypeWrapper wrapper = GetWrapperFromType(type); if (wrapper != null && wrapper.Name != name) { // the name specified was not in canonical form return(null); } return(wrapper); }