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); }
public SPEObjectManager(SPEEmulator.IEndianBitConverter conv) { this.Converter = conv; this.ObjectTable = ReadObjectTable(conv); KnownObjectsById = new Dictionary <uint, object>(); KnownObjectsByObj = new Dictionary <object, uint>(new PointerComparer()); Serializers = GetDefaultSerializers(); }
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); } }
/// <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); }
public EntryEnumerator(ObjectTableWrapper owner) { m_owner = owner; }