internal GenericMethodInstance(Type declaringType, MethodInfo method, Type[] methodArgs) { System.Diagnostics.Debug.Assert(!(method is GenericMethodInstance)); this.declaringType = declaringType; this.method = method; this.methodArgs = methodArgs; }
private MethodInfo TryGetForwarder() { if (forwarder == null && !declaringType.__IsMissing) { MethodBase mb = declaringType.FindMethod(name, signature); ConstructorInfo ci = mb as ConstructorInfo; if (ci != null) { forwarder = ci.GetMethodInfo(); } else { forwarder = (MethodInfo)mb; } } return forwarder; }
internal void SetMain(MethodInfo m, PEFileKinds target, Dictionary<string, string> props, bool noglobbing, Type apartmentAttributeType) { MethodBuilder mainStub = this.GetTypeWrapperFactory().ModuleBuilder.DefineGlobalMethod("main", MethodAttributes.Public | MethodAttributes.Static, Types.Int32, new Type[] { Types.String.MakeArrayType() }); if(apartmentAttributeType != null) { mainStub.SetCustomAttribute(new CustomAttributeBuilder(apartmentAttributeType.GetConstructor(Type.EmptyTypes), new object[0])); } CodeEmitter ilgen = CodeEmitter.Create(mainStub); CodeEmitterLocal rc = ilgen.DeclareLocal(Types.Int32); TypeWrapper startupType = LoadClassByDottedName("ikvm.runtime.Startup"); if(props.Count > 0) { ilgen.Emit(OpCodes.Newobj, JVM.Import(typeof(System.Collections.Generic.Dictionary<string, string>)).GetConstructor(Type.EmptyTypes)); foreach(KeyValuePair<string, string> kv in props) { ilgen.Emit(OpCodes.Dup); ilgen.Emit(OpCodes.Ldstr, kv.Key); ilgen.Emit(OpCodes.Ldstr, kv.Value); if(kv.Value.IndexOf('%') < kv.Value.LastIndexOf('%')) { ilgen.Emit(OpCodes.Call, JVM.Import(typeof(Environment)).GetMethod("ExpandEnvironmentVariables", new Type[] { Types.String })); } ilgen.Emit(OpCodes.Callvirt, JVM.Import(typeof(System.Collections.Generic.Dictionary<string, string>)).GetMethod("Add")); } startupType.GetMethodWrapper("setProperties", "(Lcli.System.Collections.IDictionary;)V", false).EmitCall(ilgen); } ilgen.BeginExceptionBlock(); startupType.GetMethodWrapper("enterMainThread", "()V", false).EmitCall(ilgen); ilgen.Emit(OpCodes.Ldarg_0); if (!noglobbing) { ilgen.Emit(OpCodes.Ldc_I4_0); startupType.GetMethodWrapper("glob", "([Ljava.lang.String;I)[Ljava.lang.String;", false).EmitCall(ilgen); } ilgen.Emit(OpCodes.Call, m); CodeEmitterLabel label = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Leave, label); ilgen.BeginCatchBlock(Types.Exception); LoadClassByDottedName("ikvm.runtime.Util").GetMethodWrapper("mapException", "(Ljava.lang.Throwable;)Ljava.lang.Throwable;", false).EmitCall(ilgen); CodeEmitterLocal exceptionLocal = ilgen.DeclareLocal(Types.Exception); ilgen.Emit(OpCodes.Stloc, exceptionLocal); TypeWrapper threadTypeWrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Thread"); CodeEmitterLocal threadLocal = ilgen.DeclareLocal(threadTypeWrapper.TypeAsLocalOrStackType); threadTypeWrapper.GetMethodWrapper("currentThread", "()Ljava.lang.Thread;", false).EmitCall(ilgen); ilgen.Emit(OpCodes.Stloc, threadLocal); ilgen.Emit(OpCodes.Ldloc, threadLocal); threadTypeWrapper.GetMethodWrapper("getThreadGroup", "()Ljava.lang.ThreadGroup;", false).EmitCallvirt(ilgen); ilgen.Emit(OpCodes.Ldloc, threadLocal); ilgen.Emit(OpCodes.Ldloc, exceptionLocal); ClassLoaderWrapper.LoadClassCritical("java.lang.ThreadGroup").GetMethodWrapper("uncaughtException", "(Ljava.lang.Thread;Ljava.lang.Throwable;)V", false).EmitCallvirt(ilgen); ilgen.Emit(OpCodes.Ldc_I4_1); ilgen.Emit(OpCodes.Stloc, rc); ilgen.Emit(OpCodes.Leave, label); ilgen.BeginFinallyBlock(); startupType.GetMethodWrapper("exitMainThread", "()V", false).EmitCall(ilgen); ilgen.Emit(OpCodes.Endfinally); ilgen.EndExceptionBlock(); ilgen.MarkLabel(label); ilgen.Emit(OpCodes.Ldloc, rc); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); assemblyBuilder.SetEntryPoint(mainStub, target); }
private static string MakeMethodKey(MethodInfo method) { StringBuilder sb = new StringBuilder(); sb.Append(method.ReturnType.AssemblyQualifiedName).Append(":").Append(method.Name); ParameterInfo[] paramInfo = method.GetParameters(); Type[] paramTypes = new Type[paramInfo.Length]; for(int i = 0; i < paramInfo.Length; i++) { paramTypes[i] = paramInfo[i].ParameterType; sb.Append(":").Append(paramInfo[i].ParameterType.AssemblyQualifiedName); } return sb.ToString(); }
private static void CopyLinkDemands(MethodBuilder mb, MethodInfo mi) { foreach (CustomAttributeData cad in CustomAttributeData.__GetDeclarativeSecurity(mi)) { if (cad.ConstructorArguments.Count == 0 || (int)cad.ConstructorArguments[0].Value == (int)SecurityAction.LinkDemand) { mb.__AddDeclarativeSecurity(cad.__ToBuilder()); } } }
internal MethodInfoWithReflectedType(Type reflectedType, MethodInfo method) { Debug.Assert(reflectedType != method.DeclaringType); this.reflectedType = reflectedType; this.method = method; }
private static void LoadAll() { // Types function = Load(typeof(TotemFunction)); value = Load(typeof(TotemValue)); tstring = Load(typeof(TotemString)); arguments = Load(typeof(TotemArguments)); parameter = Load(typeof(TotemParameter)); @bool = Load(typeof(TotemBool)); map = Load(typeof(TotemMap)); array = Load(typeof(TotemArray)); scope = Load(typeof(TotemFunction.ScopeWrapper)); arr_parameters = Load(typeof(TotemParameter[])); sys_bool = Load(typeof(bool)); // Methods value_val = Load(typeof(TotemValue)).GetProperty("ByTotemValue").GetGetMethod(); function_run = Load(typeof(TotemFunction)).GetMethod("TotemRun", r.BindingFlags.NonPublic | r.BindingFlags.Instance); execute = Load(typeof(TotemValue)).GetMethod("Execute"); function_ctor = Load(typeof(TotemFunction)).GetConstructor(r.BindingFlags.NonPublic | r.BindingFlags.Instance, null, new IKType[] { Load(typeof(TotemScope)), Load(typeof(string)), Load(typeof(TotemParameter[])) }, null); function_local_set = Load(typeof(TotemFunction)).GetMethod("LocalSet", r.BindingFlags.NonPublic | r.BindingFlags.Instance); function_local_get = Load(typeof(TotemFunction)).GetMethod("LocalGet", r.BindingFlags.NonPublic | r.BindingFlags.Instance); function_local_dec = Load(typeof(TotemFunction)).GetMethod("LocalDec", r.BindingFlags.NonPublic | r.BindingFlags.Instance); function_env = Load(typeof(TotemFunction)).GetProperty("Scope", r.BindingFlags.NonPublic | r.BindingFlags.Instance).GetGetMethod(true); arguments_ctor = Load(typeof(TotemArguments)).GetConstructor(IKType.EmptyTypes); arguments_add = Load(typeof(TotemArguments)).GetMethod("Add", r.BindingFlags.Public | r.BindingFlags.Instance | r.BindingFlags.DeclaredOnly); number_ctor_long = Load(typeof(TotemNumber)).GetConstructor(new IKType[] { Load(typeof(long)) }); string_ctor = Load(typeof(TotemString)).GetConstructor(new IKType[] { Load(typeof(string)) }); parameter_ctor = Load(typeof(TotemParameter)).GetConstructor(new IKType[] { Load(typeof(string)), Load(typeof(TotemValue)) }); undefined = Load(typeof(TotemValue)).GetProperty("Undefined").GetGetMethod(); @null = Load(typeof(TotemValue)).GetProperty("Null").GetGetMethod(); value_add = Load(typeof(TotemValue)).GetMethod("op_Addition", r.BindingFlags.Static | r.BindingFlags.Public); value_sub = Load(typeof(TotemValue)).GetMethod("op_Subtraction", r.BindingFlags.Static | r.BindingFlags.Public); value_mul = Load(typeof(TotemValue)).GetMethod("op_Multiply", r.BindingFlags.Static | r.BindingFlags.Public); value_div = Load(typeof(TotemValue)).GetMethod("op_Division", r.BindingFlags.Static | r.BindingFlags.Public); value_eq = Load(typeof(TotemValue)).GetMethod("op_Equality", r.BindingFlags.Static | r.BindingFlags.Public); value_neq = Load(typeof(TotemValue)).GetMethod("op_Inequality", r.BindingFlags.Static | r.BindingFlags.Public); value_lt = Load(typeof(TotemValue)).GetMethod("op_LessThan", r.BindingFlags.Static | r.BindingFlags.Public); value_gt = Load(typeof(TotemValue)).GetMethod("op_GreaterThan", r.BindingFlags.Static | r.BindingFlags.Public); value_lte = Load(typeof(TotemValue)).GetMethod("op_LessThanOrEqual", r.BindingFlags.Static | r.BindingFlags.Public); value_gte = Load(typeof(TotemValue)).GetMethod("op_GreaterThanOrEqual", r.BindingFlags.Static | r.BindingFlags.Public); value_incr = Load(typeof(TotemValue)).GetMethod("op_Increment", r.BindingFlags.Static | r.BindingFlags.Public); value_decr = Load(typeof(TotemValue)).GetMethod("op_Decrement", r.BindingFlags.Static | r.BindingFlags.Public); value_istrue = Load(typeof(TotemValue)).GetMethod("op_Explicit", r.BindingFlags.Static | r.BindingFlags.Public, null, r.CallingConventions.Standard, new IKType[] { Load(typeof(TotemValue)) }, null); value_lookup_get = Load(typeof(TotemValue)).GetProperty("Item", value, new IKType[] { value }).GetGetMethod(); value_lookup_set = Load(typeof(TotemValue)).GetProperty("Item", value, new IKType[] { value }).GetSetMethod(); scope_ctor = Load(typeof(TotemFunction.ScopeWrapper)).GetConstructor(new IKType[] { Load(typeof(TotemFunction)) }); dispose = Load(typeof(IDisposable)).GetMethod("Dispose"); get_prop = Load(typeof(TotemValue)).GetMethod("GetProp"); set_prop = Load(typeof(TotemValue)).GetMethod("SetProp"); bool_ctor = Load(typeof(TotemBool)).GetConstructor(new IKType[] { Load(typeof(bool)) }); map_ctor = map.GetConstructor(IKType.EmptyTypes); map_add = map.GetMethod("AddItem"); array_ctor = array.GetConstructor(IKType.EmptyTypes); array_add = array.GetMethod("AddItem"); }
internal ParameterInfoImpl(MethodInfo method, Type type, int pos) { this.method = method; this.type = type; this.pos = pos; }
void AddAttributes(MethodInfo methodDefinition, IList<IUnresolvedAttribute> attributes, ICollection<IUnresolvedAttribute> returnTypeAttributes) { var implAttributes = methodDefinition.MethodImplementationFlags; #region DllImportAttribute if (methodDefinition.Attributes.HasFlag (MethodAttributes.PinvokeImpl)) { ImplMapFlags flags; string importName; string importScope; if (methodDefinition.__TryGetImplMap(out flags, out importName, out importScope)) { var dllImport = new DefaultUnresolvedAttribute(dllImportAttributeTypeRef, new[] { KnownTypeReference.String }); dllImport.PositionalArguments.Add(CreateSimpleConstantValue(KnownTypeReference.String, importScope)); if (flags.HasFlag (ImplMapFlags.BestFitOff)) dllImport.AddNamedFieldArgument("BestFitMapping", falseValue); if (flags.HasFlag (ImplMapFlags.BestFitOn)) dllImport.AddNamedFieldArgument("BestFitMapping", trueValue); CallingConvention callingConvention; switch (flags & ImplMapFlags.CallConvMask) { case (ImplMapFlags)0: Debug.WriteLine ("P/Invoke calling convention not set on:" + methodDefinition.Name); callingConvention = CallingConvention.StdCall; break; case ImplMapFlags.CallConvCdecl: callingConvention = CallingConvention.Cdecl; break; case ImplMapFlags.CallConvFastcall: callingConvention = CallingConvention.FastCall; break; case ImplMapFlags.CallConvStdcall: callingConvention = CallingConvention.StdCall; break; case ImplMapFlags.CallConvThiscall: callingConvention = CallingConvention.ThisCall; break; case ImplMapFlags.CallConvWinapi: callingConvention = CallingConvention.Winapi; break; default: throw new NotSupportedException("unknown calling convention"); } if (!flags.HasFlag (ImplMapFlags.CallConvWinapi)) dllImport.AddNamedFieldArgument("CallingConvention", CreateSimpleConstantValue(callingConventionTypeRef, (int)callingConvention)); CharSet charSet = CharSet.None; switch (flags & ImplMapFlags.CharSetMask) { case ImplMapFlags.CharSetAnsi: charSet = CharSet.Ansi; break; case ImplMapFlags.CharSetAuto: charSet = CharSet.Auto; break; case ImplMapFlags.CharSetUnicode: charSet = CharSet.Unicode; break; } if (charSet != CharSet.None) dllImport.AddNamedFieldArgument("CharSet", CreateSimpleConstantValue(charSetTypeRef, (int)charSet)); if (!string.IsNullOrEmpty(importName) && importName != methodDefinition.Name) dllImport.AddNamedFieldArgument("EntryPoint", CreateSimpleConstantValue(KnownTypeReference.String, importName)); if (flags.HasFlag (ImplMapFlags.NoMangle)) dllImport.AddNamedFieldArgument("ExactSpelling", trueValue); if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig) implAttributes &= ~MethodImplAttributes.PreserveSig; else dllImport.AddNamedFieldArgument("PreserveSig", falseValue); if (flags.HasFlag (ImplMapFlags.SupportsLastError)) dllImport.AddNamedFieldArgument("SetLastError", trueValue); if (flags.HasFlag (ImplMapFlags.CharMapErrorOff)) dllImport.AddNamedFieldArgument("ThrowOnUnmappableChar", falseValue); if (flags.HasFlag (ImplMapFlags.CharMapErrorOn)) dllImport.AddNamedFieldArgument("ThrowOnUnmappableChar", trueValue); attributes.Add(interningProvider.Intern(dllImport)); } } #endregion #region PreserveSigAttribute if (implAttributes == MethodImplAttributes.PreserveSig) { attributes.Add(preserveSigAttribute); implAttributes = (MethodImplAttributes)0; } #endregion #region MethodImplAttribute if (implAttributes != MethodImplAttributes.IL) { var methodImpl = new DefaultUnresolvedAttribute(methodImplAttributeTypeRef, new[] { methodImplOptionsTypeRef }); methodImpl.PositionalArguments.Add(CreateSimpleConstantValue(methodImplOptionsTypeRef, (int)implAttributes)); attributes.Add(interningProvider.Intern(methodImpl)); } #endregion var customAttributes = methodDefinition.CustomAttributes; AddCustomAttributes (customAttributes, attributes); if (methodDefinition.Attributes.HasFlag (MethodAttributes.HasSecurity)) { AddSecurityAttributes(CustomAttributeData.__GetDeclarativeSecurity (methodDefinition), attributes); } FieldMarshal marshalInfo; if (methodDefinition.ReturnParameter.__TryGetFieldMarshal (out marshalInfo)) { returnTypeAttributes.Add(ConvertMarshalInfo(marshalInfo)); } // TODO: Not needed in ikvm - maybe a work around for a cecil bug ? // AddCustomAttributes(methodDefinition.ReturnType.CustomAttributes, returnTypeAttributes); }
static bool IsAccessor(MethodInfo methodInfo) { if (!methodInfo.IsSpecialName) return false; var name = methodInfo.Name; return name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal) || name.StartsWith("add_", StringComparison.Ordinal) || name.StartsWith("remove_", StringComparison.Ordinal) || name.StartsWith("raise_", StringComparison.Ordinal); }
static bool HasAnyAttributes(MethodInfo methodDefinition) { if (methodDefinition.Attributes.HasFlag (MethodAttributes.PinvokeImpl)) return true; if (methodDefinition.MethodImplementationFlags.HasFlag (MethodImplAttributes.CodeTypeMask)) return true; if (methodDefinition.ReturnParameter.Attributes.HasFlag (ParameterAttributes.HasFieldMarshal)) return true; return methodDefinition.CustomAttributes.Any (); }
public IUnresolvedMethod ReadMethod(MethodInfo method, IUnresolvedTypeDefinition parentType, EntityType methodType = EntityType.Method) { return ReadMethod(method, parentType, methodType, null); }
IUnresolvedMethod ReadMethod(MethodInfo method, IUnresolvedTypeDefinition parentType, EntityType methodType, IUnresolvedMember accessorOwner) { if (method == null) return null; var m = new DefaultUnresolvedMethod(parentType, method.Name); m.EntityType = methodType; m.AccessorOwner = accessorOwner; m.HasBody = method.GetMethodBody () != null; var genericArguments = method.GetGenericArguments (); if (genericArguments != null) { for (int i = 0; i < genericArguments.Length; i++) { if (genericArguments[i].GenericParameterPosition != i) throw new InvalidOperationException("g.Position != i"); m.TypeParameters.Add(new DefaultUnresolvedTypeParameter( EntityType.Method, i, genericArguments[i].Name)); } for (int i = 0; i < genericArguments.Length; i++) { var tp = (DefaultUnresolvedTypeParameter)m.TypeParameters[i]; AddConstraints(tp, genericArguments[i]); tp.ApplyInterningProvider(interningProvider); } } m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.ReturnParameter.CustomAttributes); if (HasAnyAttributes(method)) AddAttributes(method, m.Attributes, m.ReturnTypeAttributes); TranslateModifiers(method, m); foreach (var p in method.GetParameters ()) { m.Parameters.Add(ReadParameter(p)); } // mark as extension method if the attribute is set if (method.IsStatic && HasExtensionAttribute(method)) { m.IsExtensionMethod = true; } int lastDot = method.Name.LastIndexOf('.'); if (lastDot >= 0 /*&& method.HasOverrides*/) { // To be consistent with the parser-initialized type system, shorten the method name: m.Name = method.Name.Substring(lastDot + 1); m.IsExplicitInterfaceImplementation = true; foreach (var or in method.__GetMethodImpls ()) { m.ExplicitInterfaceImplementations.Add(new DefaultMemberReference( accessorOwner != null ? EntityType.Accessor : EntityType.Method, ReadTypeReference(or.DeclaringType), or.Name, or.GetGenericArguments ().Length, m.Parameters.Select(p => p.Type).ToList())); } } FinishReadMember(m, method); return m; }
static void Process(MethodInfo method) { foreach (var attr in method.__GetCustomAttributes (TypeManager.AttributeType, false)) if (attr.AttributeType.FullName == "Mono.Embedding.ThunkAttribute") Process(method, method.ReturnType, attr); }
internal MissingTypeParameter(MethodInfo owner, int index) : this(owner, index, Signature.ELEMENT_TYPE_MVAR) { }
internal ConstructorInfoImpl(MethodInfo method) { this.method = method; }
internal void FillInExplicitInterfaceMethods(MethodInfo[] interfaceMethods, MethodInfo[] targetMethods) { __MethodImplMap impl = __GetMethodImplMap(); for (int i = 0; i < impl.MethodDeclarations.Length; i++) { for (int j = 0; j < impl.MethodDeclarations[i].Length; j++) { int index = Array.IndexOf(interfaceMethods, impl.MethodDeclarations[i][j]); if (index != -1 && targetMethods[index] == null) { targetMethods[index] = impl.MethodBodies[i]; } } } }
private MethodInfo Wrap(MethodInfo method) { if (method == null) { return null; } return new GenericMethodInstance(typeInstance, method, null); }
private static bool FindMethod(List<MethodInfo> methods, MethodInfo method) { foreach (MethodInfo m in methods) { if (m.Name == method.Name && m.MethodSignature.Equals(method.MethodSignature)) { return true; } } return false; }
private static IKVM.Reflection.Emit.AssemblyBuilder FromBinary( string assemblyName, Reader reader, Universe universe, IKVM.Reflection.Type instanceContainer, IKVM.Reflection.Type exportContainer, IEnumerable <RuntimeImport> imports ) { if (reader.ReadUInt32() != Module.Magic) { throw new ModuleLoadException("File preamble magic value is incorrect.", 0); } switch (reader.ReadUInt32()) { case 0x1: //First release case 0xd: //Final pre-release, binary format is identical with first release. break; default: throw new ModuleLoadException("Unsupported version, only version 0x1 and 0xd are accepted.", 4); } uint memoryPagesMinimum = 0; uint memoryPagesMaximum = 0; Signature[] signatures = null; Signature[] functionSignatures = null; KeyValuePair <string, uint>[] exportedFunctions = null; var previousSection = Section.None; var assembly = universe.DefineDynamicAssembly( new IKVM.Reflection.AssemblyName(assemblyName), new IKVM.Reflection.Emit.AssemblyBuilderAccess() ); var dllName = assemblyName + ".dll"; var module = assembly.DefineDynamicModule(assemblyName, dllName); const IKVM.Reflection.TypeAttributes classAttributes = IKVM.Reflection.TypeAttributes.Public | IKVM.Reflection.TypeAttributes.Class | IKVM.Reflection.TypeAttributes.BeforeFieldInit ; const IKVM.Reflection.MethodAttributes constructorAttributes = IKVM.Reflection.MethodAttributes.Public | IKVM.Reflection.MethodAttributes.HideBySig | IKVM.Reflection.MethodAttributes.SpecialName | IKVM.Reflection.MethodAttributes.RTSpecialName ; const IKVM.Reflection.MethodAttributes internalFunctionAttributes = IKVM.Reflection.MethodAttributes.Assembly | IKVM.Reflection.MethodAttributes.Static | IKVM.Reflection.MethodAttributes.HideBySig ; const IKVM.Reflection.MethodAttributes exportedFunctionAttributes = IKVM.Reflection.MethodAttributes.Public | IKVM.Reflection.MethodAttributes.Virtual | IKVM.Reflection.MethodAttributes.Final | IKVM.Reflection.MethodAttributes.HideBySig ; var exportsBuilder = module.DefineType("CompiledExports", classAttributes, exportContainer); IKVM.Reflection.MethodInfo importedMemoryProvider = null; IKVM.Reflection.Emit.FieldBuilder memory = null; IKVM.Reflection.Emit.ILGenerator instanceConstructorIL; { var instanceConstructor = exportsBuilder.DefineConstructor(constructorAttributes, IKVM.Reflection.CallingConventions.Standard, IKVM.Reflection.Type.EmptyTypes); instanceConstructorIL = instanceConstructor.GetILGenerator(); { var usableConstructor = exportContainer.GetTypeInfo().DeclaredConstructors.FirstOrDefault(c => c.GetParameters().Length == 0); if (usableConstructor != null) { instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, usableConstructor); } } } var exports = exportsBuilder.AsType(); var importedFunctions = 0; IKVM.Reflection.MethodInfo[] internalFunctions = null; Indirect[] functionElements = null; GlobalInfo[] globalGetters = null; GlobalInfo[] globalSetters = null; IKVMCompilationContext context = null; IKVM.Reflection.MethodInfo startFunction = null; var preSectionOffset = reader.Offset; while (reader.TryReadVarUInt7(out var id)) //At points where TryRead is used, the stream can safely end. { if (id != 0 && (Section)id < previousSection) { throw new ModuleLoadException($"Sections out of order; section {(Section)id} encounterd after {previousSection}.", preSectionOffset); } var payloadLength = reader.ReadVarUInt32(); switch ((Section)id) { case Section.None: { var preNameOffset = reader.Offset; reader.ReadString(reader.ReadVarUInt32()); //Name reader.ReadBytes(payloadLength - checked ((uint)(reader.Offset - preNameOffset))); //Content } break; case Section.Type: { signatures = new Signature[reader.ReadVarUInt32()]; for (var i = 0; i < signatures.Length; i++) { signatures[i] = new Signature(universe, reader, (uint)i); } } break; case Section.Import: { if (imports == null) { imports = Enumerable.Empty <RuntimeImport>(); } var importsByName = imports.ToDictionary(import => new Tuple <string, string>(import.ModuleName, import.FieldName)); var count = checked ((int)reader.ReadVarUInt32()); var functionImports = new List <IKVM.Reflection.MethodInfo>(count); var functionImportTypes = new List <Signature>(count); for (var i = 0; i < count; i++) { var moduleName = reader.ReadString(reader.ReadVarUInt32()); var fieldName = reader.ReadString(reader.ReadVarUInt32()); if (!importsByName.TryGetValue(new Tuple <string, string>(moduleName, fieldName), out var import)) { throw new CompilerException($"Import not found for {moduleName}::{fieldName}."); } var preKindOffset = reader.Offset; var kind = (ExternalKind)reader.ReadByte(); switch (kind) { case ExternalKind.Function: var typeIndex = reader.ReadVarUInt32(); if (!(import is FunctionImport functionImport)) { throw new CompilerException($"{moduleName}::{fieldName} is expected to be a function, but provided import was not."); } var signature = signatures[typeIndex]; if (!signature.Equals(functionImport.Type)) { throw new CompilerException($"{moduleName}::{fieldName} did not match the required type signature."); } functionImports.Add(functionImport.IKVMMethod); functionImportTypes.Add(signature); break; case ExternalKind.Memory: var limits = new ResizableLimits(reader); if (!(import is MemoryImport memoryImport)) { throw new CompilerException($"{moduleName}::{fieldName} is expected to be memory, but provided import was not."); } importedMemoryProvider = memoryImport.IKVMMethod; break; case ExternalKind.Table: break; case ExternalKind.Global: throw new ModuleLoadException($"Imported external kind of {kind} is not currently supported.", preKindOffset); default: throw new ModuleLoadException($"Imported external kind of {kind} is not recognized.", preKindOffset); } } importedFunctions = functionImports.Count; internalFunctions = functionImports.ToArray(); functionSignatures = functionImportTypes.ToArray(); } break; case Section.Function: { var importedFunctionCount = internalFunctions == null ? 0 : internalFunctions.Length; var functionIndexSize = checked ((int)(importedFunctionCount + reader.ReadVarUInt32())); if (functionSignatures != null) { Array.Resize(ref functionSignatures, functionIndexSize); } else { functionSignatures = new Signature[functionIndexSize]; } if (importedFunctionCount != 0) { Array.Resize(ref internalFunctions, checked (functionSignatures.Length)); } else { internalFunctions = new IKVM.Reflection.MethodInfo[functionSignatures.Length]; } for (var i = importedFunctionCount; i < functionSignatures.Length; i++) { var signature = functionSignatures[i] = signatures[reader.ReadVarUInt32()]; var parms = signature.IKVMParameterTypes.Concat(new[] { exports }).ToArray(); internalFunctions[i] = exportsBuilder.DefineMethod( $"👻 {i}", internalFunctionAttributes, IKVM.Reflection.CallingConventions.Standard, signature.IKVMReturnTypes.FirstOrDefault(), parms ); } } break; case Section.Table: { var count = reader.ReadVarUInt32(); for (var i = 0; i < count; i++) { var elementType = (ElementType)reader.ReadVarInt7(); switch (elementType) { default: throw new ModuleLoadException($"Element type {elementType} not supported.", reader.Offset - 1); case ElementType.AnyFunction: var setFlags = (ResizableLimits.Flags)reader.ReadVarUInt32(); functionElements = new Indirect[reader.ReadVarUInt32()]; if ((setFlags & ResizableLimits.Flags.Maximum) != 0) { reader.ReadVarUInt32(); //Not used. } break; } } } break; case Section.Memory: { var preCountOffset = reader.Offset; var count = reader.ReadVarUInt32(); if (count > 1) { throw new ModuleLoadException("Multiple memory values are not supported.", preCountOffset); } var setFlags = (ResizableLimits.Flags)reader.ReadVarUInt32(); memoryPagesMinimum = reader.ReadVarUInt32(); if ((setFlags & ResizableLimits.Flags.Maximum) != 0) { memoryPagesMaximum = Math.Min(reader.ReadVarUInt32(), uint.MaxValue / Memory.PageSize); } else { memoryPagesMaximum = uint.MaxValue / Memory.PageSize; } memory = exportsBuilder.DefineField("☣ Memory", universe.Import(typeof(Runtime.UnmanagedMemory)), IKVM.Reflection.FieldAttributes.Private | IKVM.Reflection.FieldAttributes.InitOnly); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); if (importedMemoryProvider == null) { Instructions.Int32Constant.Emit(instanceConstructorIL, (int)memoryPagesMinimum); Instructions.Int32Constant.Emit(instanceConstructorIL, (int)memoryPagesMaximum); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Newobj, universe.Import(typeof(uint?)).GetTypeInfo().DeclaredConstructors.Where(info => { var parms = info.GetParameters(); return(parms.Length == 1 && parms[0].ParameterType == universe.Import(typeof(uint))); }).First()); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Newobj, universe.Import(typeof(Runtime.UnmanagedMemory)).GetTypeInfo().DeclaredConstructors.Where(info => { var parms = info.GetParameters(); return(parms.Length == 2 && parms[0].ParameterType == universe.Import(typeof(uint)) && parms[1].ParameterType == universe.Import(typeof(uint?))); }).First()); } else { instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, importedMemoryProvider); } instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Stfld, memory); exportsBuilder.AddInterfaceImplementation(universe.Import(typeof(IDisposable))); List <IKVM.Reflection.Type> ikvmEmptyTypes = new List <IKVM.Reflection.Type>(); foreach (System.Type type in System.Type.EmptyTypes) { ikvmEmptyTypes.Add(universe.Import(type)); } var dispose = exportsBuilder.DefineMethod( "Dispose", IKVM.Reflection.MethodAttributes.Public | IKVM.Reflection.MethodAttributes.Virtual | IKVM.Reflection.MethodAttributes.Final | IKVM.Reflection.MethodAttributes.HideBySig | IKVM.Reflection.MethodAttributes.NewSlot, IKVM.Reflection.CallingConventions.HasThis, universe.Import(typeof(void)), ikvmEmptyTypes.ToArray() ); var disposeIL = dispose.GetILGenerator(); disposeIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); disposeIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, memory); disposeIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, universe.Import(typeof(Runtime.UnmanagedMemory)) .GetTypeInfo() .DeclaredMethods .Where(info => info.ReturnType == universe.Import(typeof(void)) && info.GetParameters().Length == 0 && info.Name == nameof(Runtime.UnmanagedMemory.Dispose)) .First()); disposeIL.Emit(IKVM.Reflection.Emit.OpCodes.Ret); } break; case Section.Global: { var count = reader.ReadVarUInt32(); globalGetters = new GlobalInfo[count]; globalSetters = new GlobalInfo[count]; context = new IKVMCompilationContext( universe, exportsBuilder, memory, functionSignatures, internalFunctions, signatures, null, module, globalGetters, globalSetters ); var emptySignature = Signature.Empty; for (var i = 0; i < globalGetters.Length; i++) { var contentType = (ValueType)reader.ReadVarInt7(); var isMutable = reader.ReadVarUInt1() == 1; var getter = exportsBuilder.DefineMethod( $"🌍 Get {i}", internalFunctionAttributes, IKVM.Reflection.CallingConventions.Standard, universe.Import(contentType.ToSystemType()), isMutable ? new[] { exports } : null ); globalGetters[i] = new GlobalInfo(contentType, isMutable, getter); var il = getter.GetILGenerator(); var getterSignature = new Signature(contentType); if (isMutable == false) { context.Reset( il, getterSignature, getterSignature.RawParameterTypes ); foreach (var instruction in Instruction.ParseInitializerExpression(reader)) { instruction.CompileIKVM(context, universe); context.Previous = instruction.OpCode; } } else //Mutable { var field = exportsBuilder.DefineField( $"🌍 {i}", universe.Import(contentType.ToSystemType()), IKVM.Reflection.FieldAttributes.Private | (isMutable ? 0 : IKVM.Reflection.FieldAttributes.InitOnly) ); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, field); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); var setter = exportsBuilder.DefineMethod( $"🌍 Set {i}", internalFunctionAttributes, IKVM.Reflection.CallingConventions.Standard, universe.Import(typeof(void)), new[] { universe.Import(contentType.ToSystemType()), exports } ); il = setter.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Stfld, field); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); globalSetters[i] = new GlobalInfo(contentType, isMutable, setter); context.Reset( instanceConstructorIL, emptySignature, emptySignature.RawParameterTypes ); context.EmitLoadThis(); var ended = false; foreach (var instruction in Instruction.ParseInitializerExpression(reader)) { if (ended) { throw new CompilerException("Only a single End is allowed within an initializer expression."); } if (instruction.OpCode == OpCode.End) { context.Emit(IKVM.Reflection.Emit.OpCodes.Stfld, field); ended = true; continue; } instruction.CompileIKVM(context, universe); context.Previous = instruction.OpCode; } } } } break; case Section.Export: { const IKVM.Reflection.MethodAttributes exportedPropertyAttributes = IKVM.Reflection.MethodAttributes.Public | IKVM.Reflection.MethodAttributes.HideBySig | IKVM.Reflection.MethodAttributes.SpecialName | IKVM.Reflection.MethodAttributes.Virtual | IKVM.Reflection.MethodAttributes.Final; var totalExports = reader.ReadVarUInt32(); var xFunctions = new List <KeyValuePair <string, uint> >((int)Math.Min(int.MaxValue, totalExports)); for (var i = 0; i < totalExports; i++) { var name = reader.ReadString(reader.ReadVarUInt32()); var kind = (ExternalKind)reader.ReadByte(); var preIndexOffset = reader.Offset; var index = reader.ReadVarUInt32(); switch (kind) { case ExternalKind.Function: xFunctions.Add(new KeyValuePair <string, uint>(name, index)); break; case ExternalKind.Table: throw new NotSupportedException($"Unsupported export kind {kind}."); case ExternalKind.Memory: if (index != 0) { throw new ModuleLoadException($"Exported memory must be of index 0, found {index}.", preIndexOffset); } if (memory == null) { throw new CompilerException("Cannot export linear memory when linear memory is not defined."); } { var memoryGetter = exportsBuilder.DefineMethod("get_" + name, exportedPropertyAttributes, IKVM.Reflection.CallingConventions.HasThis, universe.Import(typeof(Runtime.UnmanagedMemory)), IKVM.Reflection.Type.EmptyTypes ); var getterIL = memoryGetter.GetILGenerator(); getterIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); getterIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, memory); getterIL.Emit(IKVM.Reflection.Emit.OpCodes.Ret); exportsBuilder.DefineProperty(name, IKVM.Reflection.PropertyAttributes.None, universe.Import(typeof(Runtime.UnmanagedMemory)), IKVM.Reflection.Type.EmptyTypes) .SetGetMethod(memoryGetter); } break; case ExternalKind.Global: if (index >= globalGetters.Length) { throw new ModuleLoadException($"Exported global index of {index} is greater than the number of globals {globalGetters.Length}.", preIndexOffset); } { var getter = globalGetters[i]; var setter = globalSetters[i]; var property = exportsBuilder.DefineProperty(name, IKVM.Reflection.PropertyAttributes.None, universe.Import(getter.Type.ToSystemType()), IKVM.Reflection.Type.EmptyTypes); var wrappedGet = exportsBuilder.DefineMethod("get_" + name, exportedPropertyAttributes, IKVM.Reflection.CallingConventions.HasThis, universe.Import(getter.Type.ToSystemType()), IKVM.Reflection.Type.EmptyTypes ); var wrappedGetIL = wrappedGet.GetILGenerator(); if (getter.IsMutable) { wrappedGetIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); } wrappedGetIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, getter.Builder); wrappedGetIL.Emit(IKVM.Reflection.Emit.OpCodes.Ret); property.SetGetMethod(wrappedGet); if (setter != null) { var wrappedSet = exportsBuilder.DefineMethod("set_" + name, exportedPropertyAttributes, IKVM.Reflection.CallingConventions.HasThis, null, new[] { universe.Import(getter.Type.ToSystemType()) } ); var wrappedSetIL = wrappedSet.GetILGenerator(); wrappedSetIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); wrappedSetIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); wrappedSetIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, setter.Builder); wrappedSetIL.Emit(IKVM.Reflection.Emit.OpCodes.Ret); property.SetSetMethod(wrappedSet); } } break; default: throw new NotSupportedException($"Unrecognized export kind {kind}."); } } exportedFunctions = xFunctions.ToArray(); } break; case Section.Start: { var preReadOffset = reader.Offset; var startIndex = reader.ReadVarInt32(); if (startIndex >= internalFunctions.Length) { throw new ModuleLoadException($"Start function of index {startIndex} exceeds available functions of {internalFunctions.Length}", preReadOffset); } startFunction = internalFunctions[startIndex]; } break; case Section.Element: { if (functionElements == null) { throw new ModuleLoadException("Element section found without an associated table section.", preSectionOffset); } var count = reader.ReadVarUInt32(); for (var i = 0; i < count; i++) { var preIndexOffset = reader.Offset; var index = reader.ReadVarUInt32(); if (index != 0) { throw new ModuleLoadException($"Index value of anything other than 0 is not supported, {index} found.", preIndexOffset); } { var preInitializerOffset = reader.Offset; var initializer = Instruction.ParseInitializerExpression(reader).ToArray(); if (initializer.Length != 2 || !(initializer[0] is Instructions.Int32Constant c) || c.Value != 0 || !(initializer[1] is Instructions.End)) { throw new ModuleLoadException("Initializer expression support for the Element section is limited to a single Int32 constant of 0 followed by end.", preInitializerOffset); } } var preElementsOffset = reader.Offset; var elements = reader.ReadVarUInt32(); if (elements != functionElements.Length) { throw new ModuleLoadException($"Element count {elements} does not match the indication provided by the earlier table {functionElements.Length}.", preElementsOffset); } for (var j = 0; j < functionElements.Length; j++) { var functionIndex = reader.ReadVarUInt32(); functionElements[j] = new Indirect( functionSignatures[functionIndex].TypeIndex, (IKVM.Reflection.Emit.MethodBuilder)internalFunctions[importedFunctions + functionIndex] ); } } } break; case Section.Code: { var preBodiesIndex = reader.Offset; var functionBodies = reader.ReadVarUInt32(); if (functionBodies > 0 && (functionSignatures == null || functionSignatures.Length == importedFunctions)) { throw new ModuleLoadException("Code section is invalid when Function section is missing.", preBodiesIndex); } if (functionBodies != functionSignatures.Length - importedFunctions) { throw new ModuleLoadException($"Code section has {functionBodies} functions described but {functionSignatures.Length - importedFunctions} were expected.", preBodiesIndex); } if (context == null) //Might have been created by the Global section, if present. { context = new IKVMCompilationContext( universe, exportsBuilder, memory, functionSignatures, internalFunctions, signatures, functionElements, module, globalGetters, globalSetters ); } for (var functionBodyIndex = 0; functionBodyIndex < functionBodies; functionBodyIndex++) { var signature = functionSignatures[importedFunctions + functionBodyIndex]; var byteLength = reader.ReadVarUInt32(); var startingOffset = reader.Offset; var locals = new Local[reader.ReadVarUInt32()]; for (var localIndex = 0; localIndex < locals.Length; localIndex++) { locals[localIndex] = new Local(reader); } var il = ((IKVM.Reflection.Emit.MethodBuilder)internalFunctions[importedFunctions + functionBodyIndex]).GetILGenerator(); context.Reset( il, signature, signature.RawParameterTypes.Concat( locals .SelectMany(local => Enumerable.Range(0, checked ((int)local.Count)).Select(_ => local.Type)) ).ToArray() ); foreach (var local in locals.SelectMany(local => Enumerable.Range(0, checked ((int)local.Count)).Select(_ => local.Type))) { il.DeclareLocal(universe.Import(local.ToSystemType())); } foreach (var instruction in Instruction.Parse(reader)) { instruction.CompileIKVM(context, universe); context.Previous = instruction.OpCode; } if (reader.Offset - startingOffset != byteLength) { throw new ModuleLoadException($"Instruction sequence reader ended after readering {reader.Offset - startingOffset} characters, expected {byteLength}.", reader.Offset); } } } break; case Section.Data: { if (memory == null) { throw new ModuleLoadException("Data section cannot be used unless a memory section is defined.", preSectionOffset); } var count = reader.ReadVarUInt32(); if (context == null) //Would only be null if there is no Global or Code section, but have to check. { context = new IKVMCompilationContext( universe, exportsBuilder, memory, new Signature[0], new IKVM.Reflection.MethodInfo[0], new Signature[0], functionElements, module, globalGetters, globalSetters ); } context.Reset( instanceConstructorIL, Signature.Empty, Signature.Empty.RawParameterTypes ); var block = new Instructions.Block(BlockType.Int32); var address = instanceConstructorIL.DeclareLocal(universe.Import(typeof(uint))); for (var i = 0; i < count; i++) { var startingOffset = reader.Offset; { var index = reader.ReadVarUInt32(); if (index != 0) { throw new ModuleLoadException($"Data index must be 0, found {index}.", startingOffset); } } block.CompileIKVM(context, universe); //Prevents "end" instruction of the initializer expression from becoming a return. foreach (var instruction in Instruction.ParseInitializerExpression(reader)) { instruction.CompileIKVM(context, universe); context.Previous = instruction.OpCode; } context.Stack.Pop(); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Stloc, address); var data = reader.ReadBytes(reader.ReadVarUInt32()); //Ensure sufficient memory is allocated, error if max is exceeded. instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldloc, address); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, data.Length); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Add_Ovf_Un); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, Instructions.MemoryImmediateInstruction.IKVMCreateRangeCheck(HelperMethod.RangeCheck8, context, universe)); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Pop); if (data.Length > 0x3f0000) //Limitation of DefineInitializedData, can be corrected by splitting the data. { throw new NotSupportedException($"Data segment {i} is length {data.Length}, exceeding the current implementation limit of 4128768."); } var field = exportsBuilder.DefineInitializedData($"☣ Data {i}", data, IKVM.Reflection.FieldAttributes.Assembly | IKVM.Reflection.FieldAttributes.InitOnly); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, memory); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, Runtime.UnmanagedMemory.IKVMStartGetter(universe)); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldloc, address); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Conv_I); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Add_Ovf_Un); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldsflda, field); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, data.Length); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Cpblk); } } break; default: throw new ModuleLoadException($"Unrecognized section type {(Section)id}.", preSectionOffset); } previousSection = (Section)id; } if (exportedFunctions != null) { for (var i = 0; i < exportedFunctions.Length; i++) { var exported = exportedFunctions[i]; var signature = functionSignatures[exported.Value]; List <IKVM.Reflection.Type> signaturearray = new List <IKVM.Reflection.Type>(); foreach (var s in signature.ParameterTypes) { signaturearray.Add(universe.Import(s)); } var method = exportsBuilder.DefineMethod( exported.Key, exportedFunctionAttributes, IKVM.Reflection.CallingConventions.HasThis, universe.Import(signature.ReturnTypes.FirstOrDefault()), signaturearray.ToArray() ); var il = method.GetILGenerator(); for (var parm = 0; parm < signature.ParameterTypes.Length; parm++) { il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg, parm + 1); } il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, internalFunctions[exported.Value]); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); } } if (startFunction != null) { instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Call, startFunction); } instanceConstructorIL.Emit(IKVM.Reflection.Emit.OpCodes.Ret); //Finish the constructor. var exportInfo = exportsBuilder.CreateTypeInfo(); IKVM.Reflection.TypeInfo instance; { var instanceBuilder = module.DefineType("CompiledInstance", classAttributes, instanceContainer); var instanceConstructor = instanceBuilder.DefineConstructor(constructorAttributes, IKVM.Reflection.CallingConventions.Standard, null); var il = instanceConstructor.GetILGenerator(); var memoryAllocated = checked (memoryPagesMaximum * Memory.PageSize); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Newobj, exportInfo.DeclaredConstructors.First()); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, instanceContainer .GetTypeInfo() .DeclaredConstructors .First(info => info.GetParameters() .FirstOrDefault() ?.ParameterType == exportContainer )); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); instance = instanceBuilder.CreateTypeInfo(); } module.CreateGlobalFunctions(); return(assembly); }