public static bool AssembleBoxedMethod(metadata.MethodSpec ms, binary_library.IBinaryFile bf, target.Target t, TysilaState s, StringBuilder debug_passes = null, binary_library.ISection ts = null) { if (ts == null) { ts = bf.GetTextSection(); } s.bf = bf; s.text_section = ts; // Symbol List <binary_library.ISymbol> meth_syms = new List <binary_library.ISymbol>(); var mangled_name = ms.MangleMethod(); var meth_sym = bf.CreateSymbol(); meth_sym.Name = mangled_name; meth_sym.ObjectType = binary_library.SymbolObjectType.Function; meth_sym.Offset = (ulong)ts.Data.Count; meth_sym.Type = binary_library.SymbolType.Weak; ts.AddSymbol(meth_sym); meth_syms.Add(meth_sym); Code c = ms.ret_type_needs_boxing ? t.AssembleBoxRetTypeMethod(ms, s) : t.AssembleBoxedMethod(ms, s); c.t = t; t.AssemblePass(c); foreach (var sym in meth_syms) { sym.Size = ts.Data.Count - (int)sym.Offset; } DumpDebug(debug_passes, meth_syms, c); return(true); }
public static bool AssembleMethod(metadata.MethodSpec ms, binary_library.IBinaryFile bf, target.Target t, TysilaState s, StringBuilder debug_passes = null, MetadataStream base_m = null, Code code_override = null, binary_library.ISection ts = null, binary_library.ISection data_sect = null, dwarf.DwarfCU dcu = null) { if (ms.ret_type_needs_boxing) { throw new Exception("AssembleMethod called for box rettype stub - use AssembleBoxedMethod instead"); } if (ms.is_boxed) { throw new Exception("AssembleMethod called for boxed method - use AssembleBoxedMethod instead"); } if (ts == null) { ts = bf.GetTextSection(); } s.bf = bf; s.text_section = ts; binary_library.SymbolType sym_st = binary_library.SymbolType.Global; var csite = ms.msig; var mdef = ms.mdrow; var m = ms.m; /* Don't compile if not for this architecture */ if (!t.IsMethodValid(ms)) { return(false); } // Get method RVA, don't compile if no body var rva = m.GetIntEntry(metadata.MetadataStream.tid_MethodDef, mdef, 0); // New signature table s.sigt = new SignatureTable(ms.MangleMethod()); /* Is this an array method? */ if (rva == 0 && ms.type != null && ms.type.stype == TypeSpec.SpecialType.Array && code_override == null) { if (ms.name_override == "Get") { code_override = ir.ConvertToIR.CreateArrayGet(ms, t, s); } else if (ms.name_override == ".ctor") { // there are two constructors, choose the correct one var pcount = ms.m.GetMethodDefSigParamCount(ms.msig); if (pcount == ms.type.arr_rank) { code_override = ir.ConvertToIR.CreateArrayCtor1(ms, t, s); } else if (pcount == 2 * ms.type.arr_rank) { code_override = ir.ConvertToIR.CreateArrayCtor2(ms, t, s); } else { throw new NotSupportedException("Invalid number of parameters to " + ms.MangleMethod() + " for array of rank " + ms.type.arr_rank.ToString()); } } else if (ms.name_override == "Set") { code_override = ir.ConvertToIR.CreateArraySet(ms, t, s); } else if (ms.name_override == "Address") { code_override = ir.ConvertToIR.CreateArrayAddress(ms, t, s); } else { throw new NotImplementedException(ms.name_override); } sym_st = binary_library.SymbolType.Weak; } /* Is this a vector method? */ if (rva == 0 && ms.type != null && ms.type.stype == TypeSpec.SpecialType.SzArray && code_override == null) { if (ms.Name == "IndexOf") { code_override = ir.ConvertToIR.CreateVectorIndexOf(ms, t, s); } else if (ms.Name == "Insert") { code_override = ir.ConvertToIR.CreateVectorInsert(ms, t, s); } else if (ms.Name == "RemoveAt") { code_override = ir.ConvertToIR.CreateVectorRemoveAt(ms, t, s); } else if (ms.Name == "get_Item") { code_override = ir.ConvertToIR.CreateVectorget_Item(ms, t, s); } else if (ms.Name == "set_Item") { code_override = ir.ConvertToIR.CreateVectorset_Item(ms, t, s); } else if (ms.Name == "get_Count") { code_override = ir.ConvertToIR.CreateVectorget_Count(ms, t, s); } else if (ms.Name == "CopyTo") { code_override = ir.ConvertToIR.CreateVectorCopyTo(ms, t, s); } /*else if (ms.Name == "GetEnumerator") * code_override = ir.ConvertToIR.CreateVectorGetEnumerator(ms, t);*/ else if (ms.Name == "Add" || ms.Name == "Clear" || ms.Name == "Contains" || ms.Name == "Remove" || ms.Name == "get_IsReadOnly" || ms.Name == "get_IsSynchronized" || ms.Name == "get_SyncRoot" || ms.Name == "get_IsFixedSize" || ms.Name == "Clone" || ms.Name == "CompareTo" || ms.Name == "GetHashCode" || ms.Name == "Equals") { code_override = ir.ConvertToIR.CreateVectorUnimplemented(ms, t, s); } else { return(false); } sym_st = binary_library.SymbolType.Weak; } if (rva == 0 && code_override == null) { return(false); } // Get mangled name for defining a symbol List <binary_library.ISymbol> meth_syms = new List <binary_library.ISymbol>(); var mangled_name = m.MangleMethod(ms); var meth_sym = bf.CreateSymbol(); meth_sym.Name = mangled_name; meth_sym.ObjectType = binary_library.SymbolObjectType.Function; meth_sym.Offset = (ulong)ts.Data.Count; meth_sym.Type = binary_library.SymbolType.Global; ts.AddSymbol(meth_sym); meth_syms.Add(meth_sym); foreach (var alias in ms.MethodAliases) { var alias_sym = bf.CreateSymbol(); alias_sym.Name = alias; alias_sym.ObjectType = binary_library.SymbolObjectType.Function; alias_sym.Offset = (ulong)ts.Data.Count; alias_sym.Type = binary_library.SymbolType.Global; ts.AddSymbol(alias_sym); meth_syms.Add(alias_sym); } if (ms.HasCustomAttribute("_ZN14libsupcs#2Edll8libsupcs20WeakLinkageAttribute_7#2Ector_Rv_P1u1t")) { sym_st = binary_library.SymbolType.Weak; } if (base_m != null && ms.m != base_m) { sym_st = binary_library.SymbolType.Weak; } foreach (var sym in meth_syms) { sym.Type = sym_st; } // Get signature if not specified if (csite == 0) { csite = (int)m.GetIntEntry(metadata.MetadataStream.tid_MethodDef, mdef, 4); } Code cil; if (code_override == null) { var meth = m.GetRVA(rva); var flags = meth.ReadByte(0); int max_stack = 0; long code_size = 0; long lvar_sig_tok = 0; int boffset = 0; List <metadata.ExceptionHeader> ehdrs = null; bool has_exceptions = false; if ((flags & 0x3) == 0x2) { // Tiny header code_size = flags >> 2; max_stack = 8; boffset = 1; } else if ((flags & 0x3) == 0x3) { // Fat header uint fat_flags = meth.ReadUShort(0) & 0xfffU; int fat_hdr_len = (meth.ReadUShort(0) >> 12) * 4; max_stack = meth.ReadUShort(2); code_size = meth.ReadUInt(4); lvar_sig_tok = meth.ReadUInt(8); boffset = fat_hdr_len; if ((flags & 0x8) == 0x8) { has_exceptions = true; ehdrs = new List <metadata.ExceptionHeader>(); int ehdr_offset = boffset + (int)code_size; ehdr_offset = util.util.align(ehdr_offset, 4); while (true) { int kind = meth.ReadByte(ehdr_offset); if ((kind & 0x1) != 0x1) { throw new Exception("Invalid exception header"); } bool is_fat = false; if ((kind & 0x40) == 0x40) { is_fat = true; } int data_size = meth.ReadInt(ehdr_offset); data_size >>= 8; if (is_fat) { data_size &= 0xffffff; } else { data_size &= 0xff; } int clause_count; if (is_fat) { clause_count = (data_size - 4) / 24; } else { clause_count = (data_size - 4) / 12; } ehdr_offset += 4; for (int i = 0; i < clause_count; i++) { var ehdr = ParseExceptionHeader(meth, ref ehdr_offset, is_fat, ms); ehdr.EhdrIdx = i; ehdrs.Add(ehdr); } if ((kind & 0x80) != 0x80) { break; } } } } else { throw new Exception("Invalid method header flags"); } /* Parse CIL code */ cil = libtysila5.cil.CilParser.ParseCIL(meth, ms, boffset, (int)code_size, lvar_sig_tok, has_exceptions, ehdrs); cil.s = s; /* Allocate local vars and args */ t.AllocateLocalVarsArgs(cil); /* Convert to IR */ cil.t = t; ir.ConvertToIR.DoConversion(cil); } else { cil = code_override; } /* Allocate registers */ ir.AllocRegs.DoAllocation(cil); /* Choose instructions */ target.ChooseInstructions.DoChoosing(cil); t.AssemblePass(cil); //((target.x86.x86_Assembler)cil.t).AssemblePass(cil); foreach (var sym in meth_syms) { sym.Size = ts.Data.Count - (int)sym.Offset; } foreach (var extra_sym in cil.extra_labels) { var esym = bf.CreateSymbol(); esym.Name = extra_sym.Name; esym.ObjectType = binary_library.SymbolObjectType.Function; esym.Offset = (ulong)extra_sym.Offset; esym.Type = sym_st; ts.AddSymbol(esym); } /* Dump debug */ DumpDebug(debug_passes, meth_syms, cil); /* Signature table */ if (data_sect == null) { data_sect = bf.GetDataSection(); } s.sigt.WriteToOutput(bf, ms.m, t, data_sect); /* DWARF output */ if (dcu != null) { var ddie = dcu.GetMethodDie(ms); ddie.sym = meth_syms[0]; ddie.cil = cil; var ddts = dcu.GetTypeDie(ms.type) as dwarf.DwarfParentDIE; ddts.Children.Add(ddie); if (ms.ReturnType != null) { dcu.GetTypeDie(ms.ReturnType); if (ms.ReturnType.stype == TypeSpec.SpecialType.None && !ms.ReturnType.IsValueType) { dcu.GetTypeDie(ms.ReturnType.Pointer); } } foreach (var la in cil.la_types) { dcu.GetTypeDie(la); if (la.stype == TypeSpec.SpecialType.None && !la.IsValueType) { dcu.GetTypeDie(la.Pointer); } } foreach (var lv in cil.lv_types) { dcu.GetTypeDie(lv); if (lv.stype == TypeSpec.SpecialType.None && !lv.IsValueType) { dcu.GetTypeDie(lv.Pointer); } } if (!ms.IsStatic) { dcu.GetTypeDie(ms.type.Pointer); } // do we have source lines? if (ms.m.pdb != null && ms.mdrow > 0) { var sps = ms.m.pdb.DebugGetSeqPtForMDRow(ms.mdrow); if (sps != null && cil.cil != null && cil.cil.Count > 0) { /* Start building a Line Number Program * * We follow the example in DWARF4 D.5 (p251), with a few changes * * header - defined per CU * - add this/these source files to it if necessary * * DW_LNE_set_address - psize 0s, reloc to mangled name * DW_LNS_advance_pc - mc_offset of first cil instruction * DW_LNS_set_prologue_end * DW_LNS_set_file - source file * SPECIAL(0,0) - add first opcode * SPECIAL(x,y) - add rest of opcodes * DW_LNE_end_sequence * */ string cur_file = null; int cur_line = 1; int cur_mc = 0; int cur_col = 0; var lnp = dcu.lnp; // DW_LNE_set_address lnp.AddRange(new byte[] { 0x00, (byte)(t.psize + 1), 0x02 }); dcu.lnp_relocs.Add(lnp.Count, meth_syms[0]); for (int i = 0; i < t.psize; i++) { lnp.Add(0); } // DW_LNS_advance_pc lnp.Add(0x02); dwarf.DwarfDIE.w(lnp, (uint)cil.cil[0].mc_offset); cur_mc = cil.cil[0].mc_offset; // DW_LNS_set_prologue_end lnp.Add(0x0a); foreach (var cn in cil.cil) { var mc_advance = cn.mc_offset - cur_mc; // get current line number MetadataStream.SeqPt csp = null; foreach (var sp in sps) { if (sp.IlOffset == cn.il_offset & !sp.IsHidden) { csp = sp; break; } } if (csp != null) { var line_advance = csp.StartLine - cur_line; if (ddie.StartLine == 0) { ddie.StartLine = csp.StartLine; } if (ddie.StartColumn == 0) { ddie.StartColumn = csp.StartCol; } if (csp.DocName != cur_file) { // DW_LNS_set_file lnp.Add(0x04); uint file_no; if (!dcu.lnp_files.TryGetValue(csp.DocName, out file_no)) { file_no = (uint)(dcu.lnp_files.Count + 1); dcu.lnp_files[csp.DocName] = file_no; dcu.lnp_fnames.Add(csp.DocName); } if (ddie.SourceFileId == 0) { ddie.SourceFileId = (int)file_no; } dwarf.DwarfDIE.w(lnp, file_no); cur_file = csp.DocName; } if (csp.StartCol != cur_col) { // DW_LNS_set_column lnp.Add(0x05); dwarf.DwarfDIE.w(lnp, (uint)csp.StartCol); cur_col = csp.StartCol; } /* SPECIAL if possible * Use example on DWARF4 p132: * opcode_base = 13, line_base = -3, line_range = 12 * * Gives a line advance range of [-3,8] and op_advance [0,19] */ if ((line_advance >= dcu.line_base && line_advance < (dcu.line_base + dcu.line_range)) && (mc_advance >= 0 && mc_advance < dcu.mc_advance_max)) { var spec_opcode = (line_advance - dcu.line_base) + (dcu.line_range * mc_advance) + dcu.opcode_base; lnp.Add((byte)spec_opcode); } else { // DW_LNS_advance_pc lnp.Add(0x02); dwarf.DwarfDIE.w(lnp, (uint)mc_advance); // DW_LNS_advance_line lnp.Add(0x03); dwarf.DwarfDIE.w(lnp, line_advance); // SPECIAL(0,0) var spec_opcode = (0 - dcu.line_base) + dcu.opcode_base; lnp.Add((byte)spec_opcode); } cur_line += line_advance; cur_mc += mc_advance; } } // Advance to end var to_advance = (int)meth_syms[0].Size - cur_mc; lnp.Add(0x02); dwarf.DwarfDIE.w(lnp, to_advance); // DW_LNE_end_sequence lnp.Add(0x00); lnp.Add(0x01); lnp.Add(0x01); } } } return(true); }