コード例 #1
0
        public object ReadObjectFromLS(uint objectIndex, object storage)
        {
            if (objectIndex == 0)
            {
                return(null);
            }

            if (!KnownObjectsById.ContainsKey(objectIndex))
            {
                ObjectTableEntry e      = ObjectTable[objectIndex];
                Type             eltype = FindElementType(objectIndex);
                ISerializer      s;
                Serializers.TryGetValue(eltype, out s);
                if (s == null && eltype.IsArray)
                {
                    Serializers.TryGetValue(typeof(Array), out s);
                }
                if (s == null)
                {
                    throw new Exception("Unable to deserialize element of type: " + eltype.FullName);
                }

                SPEEmulator.EndianBitConverter c = new SPEEmulator.EndianBitConverter(new byte[e.AlignedSize]);
                Converter.ReadBytes(e.Offset, c.Data);

                object el = s.Deserialize(c, e, storage);

                KnownObjectsById[objectIndex] = el;
                KnownObjectsByObj[el]         = objectIndex;
            }

            return(KnownObjectsById[objectIndex]);
        }
コード例 #2
0
        private static ObjectTableWrapper ReadObjectTable(SPEEmulator.IEndianBitConverter conv)
        {
            uint object_table_size = conv.ReadUInt(SPEJITCompiler.OBJECT_TABLE_OFFSET);

            SPEEmulator.EndianBitConverter obj_tb_tmp = new SPEEmulator.EndianBitConverter(new byte[(object_table_size + 1) * 16]);
            conv.ReadBytes(SPEJITCompiler.OBJECT_TABLE_OFFSET, obj_tb_tmp.Data);
            uint[] object_table = new uint[(object_table_size + 1) * 4];
            for (int i = 0; i < object_table.Length; i++)
            {
                object_table[i] = obj_tb_tmp.ReadUInt();
            }

            ObjectTableWrapper objtable = new ObjectTableWrapper(object_table);

            /*Console.WriteLine("#Size {0}, nextFree: {1}, nextOffset: {2}, memSize: {3}", objtable.Size, objtable.NextFree, objtable.NextOffset, objtable.Memsize);
             * foreach (var e in objtable)
             *  Console.WriteLine(e.ToString());*/


            foreach (var v in objtable.Where(c => c.KnownType == AccCIL.KnownObjectTypes.String))
            {
                byte[] localdata = new byte[v.AlignedSize];
                conv.ReadBytes(v.Offset, localdata);

                objtable.Strings.Add(System.Text.Encoding.UTF8.GetString(localdata, 0, (int)v.Size), v.Index);
            }

            return(objtable);
        }
コード例 #3
0
        public override T Execute <T>(params object[] args)
        {
            bool showGui = this.ShowGUI;

            SPEEmulator.SPEProcessor     spe;
            SPEEmulatorTestApp.Simulator sx = null;

            if (showGui)
            {
                // Run program
                sx = new SPEEmulatorTestApp.Simulator(new string[] { m_elf });
                sx.StartAndPause();
                spe = sx.SPE;
            }
            else
            {
                spe = new SPEEmulator.SPEProcessor();
                spe.LoadELF(m_elf);
                m_workingEvent = new System.Threading.ManualResetEvent(false);
            }

            SPEEmulator.EndianBitConverter conv      = new SPEEmulator.EndianBitConverter(spe.LS);
            SPEObjectManager       manager           = new SPEObjectManager(conv);
            Dictionary <uint, int> transferedObjects = base.LoadInitialArguments(conv, manager, args);

            spe.RegisterCallbackHandler(SPEJITCompiler.STOP_METHOD_CALL & 0xff, spe_callback);

            if (showGui)
            {
                System.Windows.Forms.Application.Run(sx);
            }
            else
            {
                m_exitCode = 0;
                m_workingEvent.Reset();
                spe.SPEStopped += new SPEEmulator.StatusEventDelegate(spe_SPEStopped);
                spe.Exit       += new SPEEmulator.ExitEventDelegate(spe_Exit);
                spe.Start();
                m_workingEvent.WaitOne();
                spe.SPEStopped -= new SPEEmulator.StatusEventDelegate(spe_SPEStopped);
                spe.Exit       -= new SPEEmulator.ExitEventDelegate(spe_Exit);

                Console.WriteLine("Executed {0} instructions while running function {1}", spe.SPU.InstructionsExecuted, m_loadedMethod.DeclaringType.FullName + "::" + m_loadedMethod.Name);

                if (m_exitCode != SPEJITCompiler.STOP_SUCCESSFULL)
                {
                    throw new Exception("Invalid exitcode: " + m_exitCode);
                }
            }

            spe.UnregisterCallbackHandler(SPEJITCompiler.STOP_METHOD_CALL & 0xff);

            return(base.FinalizeAndReturn <T>(conv, manager, transferedObjects, args));
        }
コード例 #4
0
        private static void WriteObjectTable(SPEEmulator.IEndianBitConverter conv, ObjectTableWrapper objtable)
        {
            SPEEmulator.EndianBitConverter obj_tb_tmp = new SPEEmulator.EndianBitConverter(new byte[objtable.Data.Length * 4]);
            foreach (uint u in objtable.Data)
            {
                obj_tb_tmp.WriteUInt(u);
            }

            conv.WriteBytes(SPEJITCompiler.OBJECT_TABLE_OFFSET, obj_tb_tmp.Data);

            foreach (KeyValuePair <string, uint> k in objtable.Strings)
            {
                ObjectTableEntry e = objtable[k.Value];

                System.Diagnostics.Debug.Assert(e.KnownType == AccCIL.KnownObjectTypes.String);
                System.Diagnostics.Debug.Assert(e.Size == k.Key.Length);

                byte[] localdata = new byte[e.AlignedSize];
                System.Text.Encoding.UTF8.GetBytes(k.Key, 0, k.Key.Length, localdata, 0);

                conv.WriteBytes(e.Offset, localdata);
            }
        }
コード例 #5
0
        /// <summary>
        /// Emits an instruction stream.
        /// </summary>
        /// <param name="outstream">The output stream</param>
        /// <param name="assemblyOutput">The assembly text output, can be null</param>
        /// <param name="methods">The compiled methods</param>
        /// <returns>A lookup table with all method calls</returns>
        public Dictionary <int, Mono.Cecil.MethodReference> EmitInstructionStream(System.IO.Stream outstream, System.IO.TextWriter assemblyOutput, IEnumerable <ICompiledMethod> _methods, out uint bootloader_offset)
        {
            //Prepare the call lookup table
            Dictionary <int, Mono.Cecil.MethodReference> callpoints = new Dictionary <int, Mono.Cecil.MethodReference>();

            //Typecast list
            List <CompiledMethod> methods = _methods.Select(x => (CompiledMethod)x).ToList();

            //Get a list of builtins
            Dictionary <string, Mono.Cecil.MethodDefinition> builtins = new Dictionary <string, Mono.Cecil.MethodDefinition>(CompiledMethod.m_spe_builtins);

            //Get list of already compiled builtins
            IDictionary <string, CompiledMethod> includedBuiltins = methods.Where(x => x.Method.Method.DeclaringType.FullName == "SPEJIT.BuiltInSPEMethods").ToDictionary(x => x.Method.Method.Name);

            //Add any built-in methods
            for (int i = 0; i < methods.Count; i++)
            {
                foreach (Mono.Cecil.MethodReference mr in methods[i].CalledMethods)
                {
                    if (mr.DeclaringType.FullName == "SPEJIT.BuiltInSPEMethods" && builtins.ContainsKey(mr.Name) && !includedBuiltins.ContainsKey(mr.Name))
                    {
                        methods.Add((CompiledMethod)AccCIL.AccCIL.JIT(this, builtins[mr.Name]));
                        builtins.Remove(mr.Name);
                    }
                }
            }

            //The size allocated for bootloader and call handler
            int BOOTLOADER_LENGTH = BOOT_LOADER.Length + (4 - BOOT_LOADER.Length % 4) % 4;

            BOOTLOADER_LENGTH += CALL_HANDLER.Length + (4 - CALL_HANDLER.Length % 4) % 4;
            BOOTLOADER_LENGTH *= 4;

            //We write in the default size in the ELF, but the actual loader is free to change it
            ObjectTableWrapper objtable = new ObjectTableWrapper(OBJECT_TABLE_SIZE, 256 * 1024);
            uint objtableindex          = objtable.AddObject(KnownObjectTypes.UInt, (uint)(OBJECT_TABLE_SIZE * 16), null);
            uint bootloadertableindex   = objtable.AddObject(KnownObjectTypes.Bootloader, (uint)BOOTLOADER_LENGTH, null);

            objtable[objtableindex].Refcount        = 1;
            objtable[bootloadertableindex].Refcount = 1;

            uint method_object_offset = objtable.NextFree;

            Dictionary <string, int> stringLiteralCounts = new Dictionary <string, int>();

            foreach (CompiledMethod cm in methods)
            {
                foreach (string s in cm.StringLiterals)
                {
                    if (!stringLiteralCounts.ContainsKey(s))
                    {
                        stringLiteralCounts.Add(s, 0);
                    }
                    stringLiteralCounts[s]++;
                }
            }

            //Register all loaded functions in the object table
            Dictionary <CompiledMethod, int> methodOffsets = new Dictionary <CompiledMethod, int>();

            foreach (CompiledMethod cm in methods)
            {
                cm.Prolouge = GenerateProlouge(cm);
                cm.Epilouge = GenerateEpilouge(cm);

                uint index = objtable.AddObject(KnownObjectTypes.Code, (uint)cm.TotalSize, null);
                objtable[index].Refcount = 1;
                methodOffsets.Add(cm, (int)objtable[index].Offset);
            }

            //Register all string literals as objects
            Dictionary <string, uint> stringLiteralRefs = new Dictionary <string, uint>();

            foreach (KeyValuePair <string, int> w in stringLiteralCounts)
            {
                uint index = objtable.AddObject(KnownObjectTypes.String, (uint)System.Text.Encoding.UTF8.GetByteCount(w.Key), null);
                stringLiteralRefs.Add(w.Key, index);

                //Assign the correct ref count
                objtable[index].Refcount = (uint)stringLiteralCounts[w.Key];
            }

            //Patch all code object types to have a string reference
            foreach (CompiledMethod cm in methods)
            {
                uint index = (uint)(methods.IndexOf(cm) + method_object_offset);
                System.Diagnostics.Debug.Assert(objtable[index].KnownType == KnownObjectTypes.Code);
                objtable[index].Type = stringLiteralRefs[cm.Fullname];
            }

            //Write a placeholder for the startup arguments
            byte[] zeroentry = new byte[16];
            outstream.Write(zeroentry, 0, 16);

            SPEEmulator.EndianBitConverter c = new SPEEmulator.EndianBitConverter(new byte[objtable.Data.Length * 4]);
            foreach (var u in objtable.Data)
            {
                c.WriteUInt(u);
            }

            outstream.Write(c.Data, 0, c.Data.Length);

            if (assemblyOutput != null)
            {
                assemblyOutput.WriteLine("### Object table ###");
                assemblyOutput.WriteLine("#Size {0}, nextFree: {1}, nextOffset: {2}, memSize: {3}", objtable.Size, objtable.NextFree, objtable.NextOffset, objtable.Memsize);

                foreach (var e in objtable)
                {
                    assemblyOutput.WriteLine(e.ToString());
                }
            }

            bootloader_offset = (uint)outstream.Length;
            if (assemblyOutput != null)
            {
                assemblyOutput.WriteLine("# Bootloader");
            }

            //Flush loader code
            InstructionsToBytes(BOOT_LOADER, outstream, assemblyOutput, null);
            outstream.Write(zeroentry, 0, (16 - (BOOT_LOADER.Length * 4) % 16) % 16);

            int callhandlerOffset = (int)outstream.Length / 4;

            if (assemblyOutput != null)
            {
                assemblyOutput.WriteLine("# Callhandler");
            }

            //Flush loader code
            InstructionsToBytes(CALL_HANDLER, outstream, assemblyOutput, null);
            outstream.Write(zeroentry, 0, (16 - (CALL_HANDLER.Length * 4) % 16) % 16);

            //Create a fast lookup table
            Dictionary <Mono.Cecil.MethodReference, int> methodOffsetLookup = methodOffsets.ToDictionary(x => (Mono.Cecil.MethodReference)x.Key.Method.Method, x => x.Value / 4);

            //We know the layout of each method, we can patch the call instructions
            foreach (CompiledMethod cm in methods)
            {
                List <string>            constants = cm.Constants.Distinct().ToList();
                Dictionary <string, int> offsets   = new Dictionary <string, int>();

                uint index = (uint)methods.IndexOf(cm) + method_object_offset;

                System.Diagnostics.Debug.Assert(objtable[index].KnownType == KnownObjectTypes.Code);
                System.Diagnostics.Debug.Assert(objtable[index].Offset == (uint)outstream.Length);
                System.Diagnostics.Debug.Assert(objtable[index].Type == stringLiteralRefs[cm.Fullname]);

                int constantOffsets = (cm.Instructions.Count + cm.Epilouge.Count) + (4 - (cm.Instructions.Count + cm.Prolouge.Count + cm.Epilouge.Count) % 4) % 4;
                for (int i = 0; i < constants.Count; i++)
                {
                    offsets.Add(constants[i], i * 4 + constantOffsets);
                }

                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("###########################################");
                    assemblyOutput.WriteLine("# Begin Function: " + cm.Method.Method.Name);
                    assemblyOutput.WriteLine("###########################################");
                    assemblyOutput.WriteLine();
                }

                cm.PatchBranches();
                cm.PatchCalls(methodOffsetLookup, callhandlerOffset, callpoints);
                cm.PatchConstants(offsets);
                cm.PatchStringLoads(stringLiteralRefs);

                int offset = (cm.Prolouge.Count + cm.Instructions.Count + cm.Epilouge.Count) * 4;

                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("### Prolouge Begin ###");
                }
                InstructionsToBytes(cm.Prolouge, outstream, assemblyOutput, null);
                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("### Prolouge End ###");
                }
#if DEBUG
                long streamOffset = outstream.Position / 4;
                Dictionary <long, List <Mono.Cecil.Cil.Instruction> > instructionLookup = new Dictionary <long, List <Mono.Cecil.Cil.Instruction> >();
                foreach (KeyValuePair <Mono.Cecil.Cil.Instruction, int> x in cm.InstructionOffsets)
                {
                    List <Mono.Cecil.Cil.Instruction> ix;
                    instructionLookup.TryGetValue(x.Value + streamOffset, out ix);
                    if (ix == null)
                    {
                        instructionLookup.Add(x.Value + streamOffset, ix = new List <Mono.Cecil.Cil.Instruction>());
                    }
                    ix.Add(x.Key);
                }
#else
                Dictionary <long, List <Mono.Cecil.Cil.Instruction> > instructionLookup = null;
#endif

                InstructionsToBytes(cm.Instructions, outstream, assemblyOutput, instructionLookup);
                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("### Epilouge Begin ###");
                }
                InstructionsToBytes(cm.Epilouge, outstream, assemblyOutput, null);
                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("### Epilouge End ###");
                }

                outstream.Write(zeroentry, 0, (16 - offset % 16) % 16);

                foreach (string s in constants)
                {
                    ulong high = ulong.Parse(s.Substring(0, 16), System.Globalization.NumberStyles.HexNumber);
                    ulong low  = ulong.Parse(s.Substring(16), System.Globalization.NumberStyles.HexNumber);

                    outstream.Write(ReverseEndian(BitConverter.GetBytes(high)), 0, 8);
                    outstream.Write(ReverseEndian(BitConverter.GetBytes(low)), 0, 8);

                    if (assemblyOutput != null)
                    {
                        assemblyOutput.WriteLine("Constant: " + s);
                    }
                }

                System.Diagnostics.Debug.Assert(objtable[index].Size + objtable[index].Offset == (uint)outstream.Length);


                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine();
                    assemblyOutput.WriteLine();
                }
            }

            if (assemblyOutput != null)
            {
                assemblyOutput.WriteLine("# String literals");
            }

            foreach (KeyValuePair <string, uint> w in stringLiteralRefs)
            {
                System.Diagnostics.Debug.Assert(objtable[w.Value].KnownType == KnownObjectTypes.String);
                System.Diagnostics.Debug.Assert(objtable[w.Value].Offset == (uint)outstream.Length);

                byte[] data = System.Text.Encoding.UTF8.GetBytes(w.Key);
                System.Diagnostics.Debug.Assert(objtable[w.Value].Size == (uint)data.Length);

                outstream.Write(data, 0, data.Length);
                outstream.Write(zeroentry, 0, (16 - data.Length % 16) % 16);

                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("0x{0:x4}: \"{1}\" -> {2}", objtable[w.Value].Offset, w.Key, w.Value);
                }
            }

            return(callpoints);
        }
コード例 #6
0
            public byte[] Serialize(object element, out uint size)
            {
                if (element == null)
                {
                    throw new ArgumentNullException("element");
                }

                Array arr    = (Array)element;
                Type  eltype = element.GetType().GetElementType();

                AccCIL.KnownObjectTypes objt;
                uint   elsize;
                string typename;

                if (eltype.IsPrimitive)
                {
                    objt     = AccCIL.AccCIL.GetObjType(eltype);
                    elsize   = 1u << (int)BuiltInSPEMethods.get_array_elem_len_mult((uint)objt);
                    typename = null;
                }
                else
                {
                    elsize   = 4;
                    objt     = AccCIL.KnownObjectTypes.Object;
                    typename = element.GetType().FullName;
                }

                size = (uint)arr.Length * elsize;
                uint alignedSize = ((size + 15) >> 4) << 4;

                SPEEmulator.EndianBitConverter c = new SPEEmulator.EndianBitConverter(new byte[alignedSize]);

                if (eltype.IsPrimitive)
                {
                    ISerializer elserializer;
                    m_parent.Serializers.TryGetValue(eltype, out elserializer);
                    if (elserializer == null)
                    {
                        throw new Exception("Unsupported inner type: " + eltype.FullName);
                    }

                    for (int i = 0; i < arr.Length; i++)
                    {
                        //TODO: This is inefficient, it should write directly into the target buffer
                        uint   s;
                        byte[] localdata = elserializer.Serialize(arr.GetValue(i), out s);
                        Array.Copy(localdata, 0, c.Data, c.Position, localdata.Length);
                        c.Position += s;
                    }
                }
                else
                {
                    for (int i = 0; i < arr.Length; i++)
                    {
                        object value = arr.GetValue(i);
                        if (value == null)
                        {
                            c.WriteUInt(0);
                        }
                        else
                        {
                            //If we are writing back the array, write back the element as well
                            if (m_parent.KnownObjectsByObj.ContainsKey(element) && m_parent.KnownObjectsByObj.ContainsKey(value))
                            {
                                m_parent.WriteObjectToLS(m_parent.KnownObjectsByObj[value], value);
                            }
                            else
                            {
                                c.WriteUInt(m_parent.CreateObjectOnLS(value));
                            }
                        }
                    }
                }

                return(c.Data);
            }
コード例 #7
0
ファイル: SPEJITCompiler.cs プロジェクト: kenkendk/ac3il
        /// <summary>
        /// Emits an instruction stream.
        /// </summary>
        /// <param name="outstream">The output stream</param>
        /// <param name="assemblyOutput">The assembly text output, can be null</param>
        /// <param name="methods">The compiled methods</param>
        /// <returns>A lookup table with all method calls</returns>
        public Dictionary<int, Mono.Cecil.MethodReference> EmitInstructionStream(System.IO.Stream outstream, System.IO.TextWriter assemblyOutput, IEnumerable<ICompiledMethod> _methods, out uint bootloader_offset)
        {
            //Prepare the call lookup table
            Dictionary<int, Mono.Cecil.MethodReference> callpoints = new Dictionary<int, Mono.Cecil.MethodReference>();

            //Typecast list
            List<CompiledMethod> methods = _methods.Select(x => (CompiledMethod)x).ToList();

            //Get a list of builtins
            Dictionary<string, Mono.Cecil.MethodDefinition> builtins = new Dictionary<string, Mono.Cecil.MethodDefinition>(CompiledMethod.m_spe_builtins);

            //Get list of already compiled builtins
            IDictionary<string, CompiledMethod> includedBuiltins = methods.Where(x => x.Method.Method.DeclaringType.FullName == "SPEJIT.BuiltInSPEMethods").ToDictionary(x => x.Method.Method.Name);

            //Add any built-in methods
            for(int i = 0; i < methods.Count; i++)
                foreach (Mono.Cecil.MethodReference mr in methods[i].CalledMethods)
                    if (mr.DeclaringType.FullName == "SPEJIT.BuiltInSPEMethods" && builtins.ContainsKey(mr.Name) && !includedBuiltins.ContainsKey(mr.Name))
                    {
                        methods.Add((CompiledMethod)AccCIL.AccCIL.JIT(this, builtins[mr.Name]));
                        builtins.Remove(mr.Name);
                    }

            //The size allocated for bootloader and call handler
            int BOOTLOADER_LENGTH = BOOT_LOADER.Length + (4 - BOOT_LOADER.Length % 4) % 4;
            BOOTLOADER_LENGTH += CALL_HANDLER.Length + (4 - CALL_HANDLER.Length % 4) % 4;
            BOOTLOADER_LENGTH *= 4;

            //We write in the default size in the ELF, but the actual loader is free to change it
            ObjectTableWrapper objtable = new ObjectTableWrapper(OBJECT_TABLE_SIZE, 256 * 1024);
            uint objtableindex = objtable.AddObject(KnownObjectTypes.UInt, (uint)(OBJECT_TABLE_SIZE * 16), null);
            uint bootloadertableindex = objtable.AddObject(KnownObjectTypes.Bootloader, (uint)BOOTLOADER_LENGTH, null);

            objtable[objtableindex].Refcount = 1;
            objtable[bootloadertableindex].Refcount = 1;

            uint method_object_offset = objtable.NextFree;

            Dictionary<string, int> stringLiteralCounts = new Dictionary<string, int>();
            foreach (CompiledMethod cm in methods)
                foreach (string s in cm.StringLiterals)
                {
                    if (!stringLiteralCounts.ContainsKey(s))
                        stringLiteralCounts.Add(s, 0);
                    stringLiteralCounts[s]++;
                }

            //Register all loaded functions in the object table
            Dictionary<CompiledMethod, int> methodOffsets = new Dictionary<CompiledMethod,int>();
            foreach(CompiledMethod cm in methods)
            {
                cm.Prolouge = GenerateProlouge(cm);
                cm.Epilouge = GenerateEpilouge(cm);

                uint index = objtable.AddObject(KnownObjectTypes.Code, (uint)cm.TotalSize, null);
                objtable[index].Refcount = 1;
                methodOffsets.Add(cm, (int)objtable[index].Offset);
            }

            //Register all string literals as objects
            Dictionary<string, uint> stringLiteralRefs = new Dictionary<string, uint>();
            foreach (KeyValuePair<string, int> w in stringLiteralCounts)
            {
                uint index = objtable.AddObject(KnownObjectTypes.String, (uint)System.Text.Encoding.UTF8.GetByteCount(w.Key), null);
                stringLiteralRefs.Add(w.Key, index);

                //Assign the correct ref count
                objtable[index].Refcount = (uint)stringLiteralCounts[w.Key];
            }

            //Patch all code object types to have a string reference
            foreach (CompiledMethod cm in methods)
            {
                uint index = (uint)(methods.IndexOf(cm) + method_object_offset);
                System.Diagnostics.Debug.Assert(objtable[index].KnownType == KnownObjectTypes.Code);
                objtable[index].Type = stringLiteralRefs[cm.Fullname];
            }

            //Write a placeholder for the startup arguments
            byte[] zeroentry = new byte[16];
            outstream.Write(zeroentry, 0, 16);

            SPEEmulator.EndianBitConverter c = new SPEEmulator.EndianBitConverter(new byte[objtable.Data.Length * 4]);
            foreach (var u in objtable.Data)
                c.WriteUInt(u);

            outstream.Write(c.Data, 0, c.Data.Length);

            if (assemblyOutput != null)
            {
                assemblyOutput.WriteLine("### Object table ###");
                assemblyOutput.WriteLine("#Size {0}, nextFree: {1}, nextOffset: {2}, memSize: {3}", objtable.Size, objtable.NextFree, objtable.NextOffset, objtable.Memsize);

                foreach (var e in objtable)
                    assemblyOutput.WriteLine(e.ToString());
            }

            bootloader_offset = (uint)outstream.Length;
            if (assemblyOutput != null)
                assemblyOutput.WriteLine("# Bootloader");

            //Flush loader code
            InstructionsToBytes(BOOT_LOADER, outstream, assemblyOutput, null);
            outstream.Write(zeroentry, 0, (16 - (BOOT_LOADER.Length * 4) % 16) % 16);

            int callhandlerOffset = (int)outstream.Length / 4;

            if (assemblyOutput != null)
                assemblyOutput.WriteLine("# Callhandler");

            //Flush loader code
            InstructionsToBytes(CALL_HANDLER, outstream, assemblyOutput, null);
            outstream.Write(zeroentry, 0, (16 - (CALL_HANDLER.Length * 4) % 16) % 16);

            //Create a fast lookup table
            Dictionary<Mono.Cecil.MethodReference, int> methodOffsetLookup = methodOffsets.ToDictionary(x => (Mono.Cecil.MethodReference)x.Key.Method.Method, x => x.Value / 4);

            //We know the layout of each method, we can patch the call instructions
            foreach (CompiledMethod cm in methods)
            {
                List<string> constants = cm.Constants.Distinct().ToList();
                Dictionary<string, int> offsets = new Dictionary<string, int>();

                uint index = (uint)methods.IndexOf(cm) + method_object_offset;

                System.Diagnostics.Debug.Assert(objtable[index].KnownType == KnownObjectTypes.Code);
                System.Diagnostics.Debug.Assert(objtable[index].Offset == (uint)outstream.Length);
                System.Diagnostics.Debug.Assert(objtable[index].Type == stringLiteralRefs[cm.Fullname]);

                int constantOffsets = (cm.Instructions.Count + cm.Epilouge.Count) + (4 - (cm.Instructions.Count + cm.Prolouge.Count + cm.Epilouge.Count) % 4) % 4;
                for(int i = 0; i < constants.Count; i++)
                    offsets.Add(constants[i], i * 4 + constantOffsets);

                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine("###########################################");
                    assemblyOutput.WriteLine("# Begin Function: " + cm.Method.Method.Name);
                    assemblyOutput.WriteLine("###########################################");
                    assemblyOutput.WriteLine();
                }

                cm.PatchBranches();
                cm.PatchCalls(methodOffsetLookup, callhandlerOffset, callpoints);
                cm.PatchConstants(offsets);
                cm.PatchStringLoads(stringLiteralRefs);

                int offset = (cm.Prolouge.Count + cm.Instructions.Count + cm.Epilouge.Count) * 4;

                if (assemblyOutput != null)
                    assemblyOutput.WriteLine("### Prolouge Begin ###");
                InstructionsToBytes(cm.Prolouge, outstream, assemblyOutput, null);
                if (assemblyOutput != null)
                    assemblyOutput.WriteLine("### Prolouge End ###");
            #if DEBUG
                long streamOffset = outstream.Position / 4;
                Dictionary<long, List<Mono.Cecil.Cil.Instruction>> instructionLookup = new Dictionary<long, List<Mono.Cecil.Cil.Instruction>>();
                foreach (KeyValuePair<Mono.Cecil.Cil.Instruction, int> x in cm.InstructionOffsets)
                {
                    List<Mono.Cecil.Cil.Instruction> ix;
                    instructionLookup.TryGetValue(x.Value + streamOffset, out ix);
                    if (ix == null)
                        instructionLookup.Add(x.Value + streamOffset, ix = new List<Mono.Cecil.Cil.Instruction>());
                    ix.Add(x.Key);
                }
            #else
                Dictionary<long, List<Mono.Cecil.Cil.Instruction>> instructionLookup = null;
            #endif

                InstructionsToBytes(cm.Instructions, outstream, assemblyOutput, instructionLookup);
                if (assemblyOutput != null)
                    assemblyOutput.WriteLine("### Epilouge Begin ###");
                InstructionsToBytes(cm.Epilouge, outstream, assemblyOutput, null);
                if (assemblyOutput != null)
                    assemblyOutput.WriteLine("### Epilouge End ###");

                outstream.Write(zeroentry, 0, (16 - offset % 16) % 16);

                foreach (string s in constants)
                {
                    ulong high = ulong.Parse(s.Substring(0, 16), System.Globalization.NumberStyles.HexNumber);
                    ulong low = ulong.Parse(s.Substring(16), System.Globalization.NumberStyles.HexNumber);

                    outstream.Write(ReverseEndian(BitConverter.GetBytes(high)), 0, 8);
                    outstream.Write(ReverseEndian(BitConverter.GetBytes(low)), 0, 8);

                    if (assemblyOutput != null)
                        assemblyOutput.WriteLine("Constant: " + s);
                }

                System.Diagnostics.Debug.Assert(objtable[index].Size + objtable[index].Offset == (uint)outstream.Length);

                if (assemblyOutput != null)
                {
                    assemblyOutput.WriteLine();
                    assemblyOutput.WriteLine();
                }
            }

            if (assemblyOutput != null)
                assemblyOutput.WriteLine("# String literals");

            foreach (KeyValuePair<string, uint> w in stringLiteralRefs)
            {
                System.Diagnostics.Debug.Assert(objtable[w.Value].KnownType == KnownObjectTypes.String);
                System.Diagnostics.Debug.Assert(objtable[w.Value].Offset == (uint)outstream.Length);

                byte[] data = System.Text.Encoding.UTF8.GetBytes(w.Key);
                System.Diagnostics.Debug.Assert(objtable[w.Value].Size == (uint)data.Length);

                outstream.Write(data, 0, data.Length);
                outstream.Write(zeroentry, 0, (16 - data.Length % 16) % 16);

                if (assemblyOutput != null)
                    assemblyOutput.WriteLine("0x{0:x4}: \"{1}\" -> {2}", objtable[w.Value].Offset, w.Key, w.Value);
            }

            return callpoints;
        }