internal GenericMethodInstance(Type declaringType, MethodInfo method, Type[] methodArgs)
		{
			System.Diagnostics.Debug.Assert(!(method is GenericMethodInstance));
			this.declaringType = declaringType;
			this.method = method;
			this.methodArgs = methodArgs;
		}
Beispiel #2
0
		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());
					}
				}
			}
Beispiel #6
0
		internal MethodInfoWithReflectedType(Type reflectedType, MethodInfo method)
		{
			Debug.Assert(reflectedType != method.DeclaringType);
			this.reflectedType = reflectedType;
			this.method = method;
		}
Beispiel #7
0
        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");
        }
Beispiel #8
0
			internal ParameterInfoImpl(MethodInfo method, Type type, int pos)
			{
				this.method = method;
				this.type = type;
				this.pos = pos;
			}
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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 ();
        }
Beispiel #12
0
 public IUnresolvedMethod ReadMethod(MethodInfo method, IUnresolvedTypeDefinition parentType, EntityType methodType = EntityType.Method)
 {
     return ReadMethod(method, parentType, methodType, null);
 }
Beispiel #13
0
        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;
        }
Beispiel #14
0
 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;
		}
Beispiel #17
0
		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);
		}
Beispiel #19
0
		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;
		}
Beispiel #20
0
        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);
        }