private static List <MCInst> handle_call(CilNode.IRNode n, Code c, metadata.MethodSpec call_ms, ir.Param[] p, Reg dest, string target = null, Reg temp_reg = null) { /* used for handling calls to utility functions * (e.g. memcpy/memset etc) whilst ensuring that * all required registers are saved around the * call */ return(handle_call(n, c, false, c.t, target, call_ms, p, dest, dest != null)); }
public InteractiveMethodSpec(metadata.MethodSpec _ms) { ms = _ms; StringBuilder sb = new StringBuilder(); var meth_name = ms.m.GetStringEntry(metadata.MetadataStream.tid_MethodDef, ms.mdrow, 3); var cur_sig = (int)ms.m.GetIntEntry(metadata.MetadataStream.tid_MethodDef, ms.mdrow, 4); sb.Append(meth_name); if (ms.IsInstantiatedGenericMethod) { sb.Append("<"); for (int idx = 0; idx < ms.gmparams.Length; idx++) { if (idx > 0) { sb.Append(","); } sb.Append(((InteractiveTypeSpec)ms.gmparams[idx]).Name); } sb.Append(">"); } sb.Append("("); var need_this = ms.m.GetMethodDefSigHasNonExplicitThis(cur_sig); var pcount = ms.m.GetMethodDefSigParamCount(cur_sig); cur_sig = ms.m.GetMethodDefSigRetTypeIndex(cur_sig); if (need_this) { sb.Append("this"); } // skip ret type ms.m.GetTypeSpec(ref cur_sig, ms.gtparams, ms.gmparams); for (int idx = 0; idx < pcount; idx++) { if (idx > 0 || need_this) { sb.Append(","); } sb.Append(((InteractiveTypeSpec)ms.m.GetTypeSpec(ref cur_sig, ms.gtparams, ms.gmparams)).Name); } sb.Append(")"); Name = sb.ToString(); }
static List <Reg> get_push_list(CilNode.IRNode n, Code c, metadata.MethodSpec call_ms, out metadata.TypeSpec rt, ref Reg dest, out int rct, bool want_return = true) { /* Determine which registers we need to save */ var caller_preserves = c.t.cc_caller_preserves_map[call_ms.CallingConvention]; ulong defined = 0; foreach (var si in n.stack_after) { defined |= si.reg.mask; } foreach (var si in n.stack_before) { defined |= si.reg.mask; } var rt_idx = call_ms.m.GetMethodDefSigRetTypeIndex(call_ms.msig); rt = call_ms.m.GetTypeSpec(ref rt_idx, call_ms.gtparams, call_ms.gmparams); rct = ir.Opcode.ct_unknown; if (rt != null && want_return) { defined &= ~n.stack_after.Peek().reg.mask; if (dest == null) { dest = n.stack_after.Peek().reg; } rct = ir.Opcode.GetCTFromType(rt); } var to_push = new util.Set(); to_push.Union(defined); to_push.Intersect(caller_preserves); List <Reg> push_list = new List <Reg>(); while (!to_push.Empty) { var first_set = to_push.get_first_set(); push_list.Add(c.t.regs[first_set]); to_push.unset(first_set); } return(push_list); }
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 int GetVTableOffset(metadata.TypeSpec ts, metadata.MethodSpec ms, Target t) { var vtbl = GetVirtualMethodDeclarations(ts); var search_meth_name = ms.m.GetIntEntry(MetadataStream.tid_MethodDef, ms.mdrow, 3); // find the requested method, match on name, signature and declaring type for (int i = 0; i < vtbl.Count; i++) { var test = vtbl[i]; var mdecl = test.unimpl_meth; if (mdecl.type.Equals(ts)) { // Check on name var mname = mdecl.m.GetIntEntry(MetadataStream.tid_MethodDef, mdecl.mdrow, 3); if (MetadataStream.CompareString(mdecl.m, mname, ms.m, search_meth_name)) { // Check on signature if (MetadataStream.CompareSignature(mdecl.m, mdecl.msig, mdecl.gtparams, mdecl.gmparams, ms.m, ms.msig, ms.gtparams, ms.gmparams)) { if (ts.IsInterface == false) { i += (6 + t.ExtraVTableFieldsPointerLength); } return(i); } } } } throw new Exception("Requested virtual method slot not found"); }
public static int GetVTableOffset(metadata.MethodSpec ms, Target t) { return(GetVTableOffset(ms.type, ms, t)); }
private static List <MCInst> handle_call(CilNode.IRNode n, Code c, bool is_calli, Target t, string target = null, metadata.MethodSpec call_ms = null, ir.Param[] p = null, Reg dest = null, bool want_return = true) { List <MCInst> r = new List <MCInst>(); if (call_ms == null) { call_ms = n.imm_ms; } if (target == null && is_calli == false) { target = call_ms.m.MangleMethod(call_ms); } Reg act_dest = null; metadata.TypeSpec rt; int rct; var push_list = get_push_list(n, c, call_ms, out rt, ref dest, out rct, want_return); // Store the current index, we will insert instructions // to save clobbered registers here int push_list_index = r.Count; /* Push arguments */ int push_length = 0; int vt_push_length = 0; bool vt_dest_adjust = false; if (rct == ir.Opcode.ct_vt) { if (dest is ContentsReg) { act_dest = dest; } else { throw new NotImplementedException(); } } var sig_idx = call_ms.msig; var pcount = call_ms.m.GetMethodDefSigParamCountIncludeThis(sig_idx); sig_idx = call_ms.m.GetMethodDefSigRetTypeIndex(sig_idx); var rt2 = call_ms.m.GetTypeSpec(ref sig_idx, call_ms.gtparams == null ? c.ms.gtparams : call_ms.gtparams, c.ms.gmparams); int calli_adjust = is_calli ? 1 : 0; metadata.TypeSpec[] push_tss = new metadata.TypeSpec[pcount]; for (int i = 0; i < pcount; i++) { if (i == 0 && call_ms.m.GetMethodDefSigHasNonExplicitThis(call_ms.msig)) { push_tss[i] = call_ms.type; } else { push_tss[i] = call_ms.m.GetTypeSpec(ref sig_idx, call_ms.gtparams, call_ms.gmparams); } } /* Push value type address if required */ metadata.TypeSpec hidden_loc_type = null; if (rct == ir.Opcode.ct_vt) { var act_dest_cr = act_dest as ContentsReg; if (act_dest_cr == null) { throw new NotImplementedException(); } if (vt_dest_adjust) { throw new NotImplementedException(); } //r.Add(inst(x86_lea_r32, r_eax, act_dest, n)); //r.Add(inst(x86_push_r32, r_eax, n)); hidden_loc_type = call_ms.m.SystemIntPtr; } // Build list of source and destination registers for parameters int cstack_loc = 0; var cc = t.cc_map[call_ms.CallingConvention]; var cc_class = t.cc_classmap[call_ms.CallingConvention]; int[] la_sizes; metadata.TypeSpec[] la_types; var to_locs = t.GetRegLocs(new ir.Param { m = call_ms.m, v2 = call_ms.msig, ms = call_ms }, ref cstack_loc, cc, cc_class, call_ms.CallingConvention, out la_sizes, out la_types, hidden_loc_type ); Reg calli_reg = null; if (is_calli) { calli_reg = r_r10; // Add the target register to those we want to pass Reg[] new_to_locs = new Reg[to_locs.Length + calli_adjust]; for (int i = 0; i < to_locs.Length; i++) { new_to_locs[i] = to_locs[i]; } new_to_locs[to_locs.Length] = calli_reg; to_locs = new_to_locs; } // Append the register arguments to the push list foreach (var arg in to_locs) { if (arg.type == rt_gpr || arg.type == rt_float) { if (!push_list.Contains(arg)) { push_list.Add(arg); } } } List <MCInst> r2 = new List <MCInst>(); // Insert the push instructions at the start of the stream int x = 0; foreach (var push_reg in push_list) { handle_push(push_reg, ref x, r2, n, c); } foreach (var r2inst in r2) { r.Insert(push_list_index++, r2inst); } // Get from locs ir.Param[] from_locs; int hidden_adjust = hidden_loc_type == null ? 0 : 1; if (p == null) { from_locs = new ir.Param[pcount + hidden_adjust + calli_adjust]; for (int i = 0; i < pcount; i++) { var stack_loc = pcount - i - 1; if (n.arg_list != null) { stack_loc = n.arg_list[i]; } from_locs[i + hidden_adjust] = n.stack_before.Peek(stack_loc + calli_adjust).reg; } if (is_calli) { from_locs[pcount + hidden_adjust] = n.stack_before.Peek(0).reg; } } else { from_locs = p; // adjust any rsp relative registers dependent on how many registers we have saved foreach (var l in from_locs) { if (l != null && l.t == ir.Opcode.vl_mreg && l.mreg is ContentsReg) { var l2 = l.mreg as ContentsReg; if (l2.basereg.Equals(r_sp)) { l2.disp += x; } } } } // Reserve any required stack space if (cstack_loc != 0) { push_length += cstack_loc; r.Add(inst(n, arm_sub_sp_imm, imm: cstack_loc)); } // Move from the from list to the to list such that // we never overwrite a from loc that hasn't been // transfered yet pcount += hidden_adjust; pcount += calli_adjust; var to_do = pcount; bool[] done = new bool[pcount]; if (hidden_adjust != 0) { // load up the address of the return value throw new NotImplementedException(); /* * var ret_to = to_locs[0]; * if (!(ret_to is ContentsReg)) * r.Add(inst(t.psize == 4 ? x86_lea_r32 : x86_lea_r64, ret_to, act_dest, n)); * else * { * r.Add(inst(t.psize == 4 ? x86_lea_r32 : x86_lea_r64, r_eax, act_dest, n)); * handle_move(ret_to, r_eax, r, n, c); * * } * * to_do--; * done[0] = true;*/ } while (to_do > 0) { int done_this_iter = 0; for (int to_i = 0; to_i < pcount; to_i++) { if (!done[to_i]) { var to_reg = to_locs[to_i]; if (to_reg.type == rt_stack) { to_reg = new ContentsReg { basereg = r_sp, disp = to_reg.stack_loc, size = to_reg.size }; } bool possible = true; // determine if this to register is the source of a from for (int from_i = 0; from_i < pcount; from_i++) { if (to_i == from_i) { continue; } if (!done[from_i] && from_locs[from_i].mreg != null && from_locs[from_i].mreg.Equals(to_reg)) { possible = false; break; } } if (possible) { var from_reg = from_locs[to_i]; switch (from_reg.t) { case ir.Opcode.vl_mreg: if (from_reg.want_address) { throw new NotImplementedException(); /* * Reg lea_to = to_reg; * if (to_reg is ContentsReg) * lea_to = r_eax; * r.Add(inst(t.psize == 4 ? x86_lea_r32 : x86_lea_r64, * lea_to, from_reg.mreg, n)); * handle_move(to_reg, lea_to, r, n, c); */ } else { handle_move(to_reg, from_reg.mreg, r, n, c); } break; case ir.Opcode.vl_c: case ir.Opcode.vl_c32: case ir.Opcode.vl_c64: if (from_reg.v > int.MaxValue || from_reg.v < int.MinValue) { throw new NotImplementedException(); } else { handle_const(to_reg, from_reg.v, r, n, c); } break; default: throw new NotSupportedException(); } to_do--; done_this_iter++; done[to_i] = true; } } } if (done_this_iter == 0) { // find two gprs/xmms we can swap to put them both // in the correct locations for (int i = 0; i < pcount; i++) { if (done[i]) { continue; } var from_i = from_locs[i].mreg; var to_i = to_locs[i]; if (from_i == null) { continue; } if (from_i.type != rt_gpr && from_i.type != rt_float) { continue; } if (to_i.type != rt_gpr && to_i.type != rt_float) { continue; } for (int j = 0; j < pcount; j++) { if (j == i) { continue; } if (done[j]) { continue; } var from_j = from_locs[j].mreg; if (from_j == null) { continue; } var to_j = to_locs[j]; if (from_i.Equals(to_j) && from_j.Equals(to_i)) { // we can swap these if (from_i.type == rt_gpr || from_i.type == rt_float) { handle_swap(to_i, to_j, r, n, c); } else if (from_i.type == rt_float) { throw new NotImplementedException(); } done_this_iter += 2; to_do -= 2; done[i] = true; done[j] = true; break; } } } } if (done_this_iter == 0) { // find two unassigned gprs/xmms we can swap, which // may not necessarily put them in the correct place bool shift_found = false; // try with gprs first int a = -1; int b = -1; for (int i = 0; i < pcount; i++) { if (done[i] == false && from_locs[i].mreg != null && from_locs[i].mreg.type == rt_gpr) { if (a == -1) { a = i; } else { b = i; shift_found = true; } } } if (shift_found) { handle_swap(from_locs[a].mreg, from_locs[b].mreg, r, n, c); var tmp = from_locs[a]; from_locs[a] = from_locs[b]; from_locs[b] = from_locs[a]; } else { a = -1; b = -1; for (int i = 0; i < pcount; i++) { if (done[i] == false && from_locs[i].mreg != null && from_locs[i].mreg.type == rt_float) { if (a == -1) { a = i; } else { b = i; shift_found = true; } } } if (shift_found) { handle_swap(from_locs[a].mreg, from_locs[b].mreg, r, n, c); var tmp = from_locs[a]; from_locs[a] = from_locs[b]; from_locs[b] = from_locs[a]; } } if (!shift_found) { throw new NotImplementedException(); } } } // Do the call if (is_calli) { // Thumb mode requires LSB set to 1 r.Add(inst(n, arm_orr_imm, Rd: calli_reg, Rn: calli_reg, imm: 1)); r.Add(inst(n, arm_blx, Rm: calli_reg)); } else { r.Add(inst(n, arm_bl, Rm: new ir.Param { t = ir.Opcode.vl_call_target, str = target })); } // Restore stack if (push_length != 0) { r.Add(inst(n, arm_add_sp_imm, imm: push_length)); } // Get vt return value if (rct == ir.Opcode.ct_vt && !act_dest.Equals(dest)) { handle_move(dest, act_dest, r, n, c); } // Restore saved registers for (int i = push_list.Count - 1; i >= 0; i--) { handle_pop(push_list[i], ref x, r, n, c); } // Get other return value if (rt != null && rct != ir.Opcode.ct_vt && rct != ir.Opcode.ct_unknown) { var rt_size = c.t.GetSize(rt); if (rct == ir.Opcode.ct_float) { handle_move(dest, r_s0, r, n, c); } else if (rt_size <= 4) { handle_move(dest, r_r0, r, n, c); } else if (rt_size == 8) { throw new NotImplementedException(); /* * if (t.psize == 4) * { * var drd = dest as DoubleReg; * r.Add(inst(x86_mov_rm32_r32, drd.a, r_eax, n)); * r.Add(inst(x86_mov_rm32_r32, drd.b, r_edx, n)); * } * else * { * r.Add(inst(x86_mov_rm64_r64, dest, r_eax, n)); * } */ } else { throw new NotImplementedException(); } } return(r); }
public static int GetFieldOffset(metadata.TypeSpec ts, metadata.MethodSpec fs, target.Target t, out bool is_tls, bool is_static = false) { int align = 1; is_tls = false; if (ts.SimpleType == 0 || ts.SimpleType == 0xe) // class or string { align = GetTypeAlignment(ts, t, is_static); } /* Iterate through methods looking for requested * one */ var first_fdef = ts.m.GetIntEntry(MetadataStream.tid_TypeDef, ts.tdrow, 4); var last_fdef = ts.m.GetLastFieldDef(ts.tdrow); uint search_field_name = 0; if (fs != null) { search_field_name = fs.m.GetIntEntry(MetadataStream.tid_Field, fs.mdrow, 1); } int cur_offset = 0; int cur_tl_offset = 0; if (is_static == false && !ts.IsValueType) { if (ts.GetExtends() == null) { // Add a vtable entry cur_offset += t.GetCTSize(ir.Opcode.ct_object); cur_offset = util.util.align(cur_offset, align); // Add a mutex lock entry cur_offset += t.GetCTSize(ir.Opcode.ct_int64); cur_offset = util.util.align(cur_offset, align); } else { cur_offset = GetFieldOffset(ts.GetExtends(), (string)null, t, out is_tls); cur_offset = util.util.align(cur_offset, align); } } else if (is_static) { // Add an is_initalized field cur_offset += t.GetCTSize(ir.Opcode.ct_intptr); cur_offset = util.util.align(cur_offset, align); } for (uint fdef_row = first_fdef; fdef_row < last_fdef; fdef_row++) { // Ensure field is static if requested var flags = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 0); if (((flags & 0x10) == 0x10 && is_static == true) || ((flags & 0x10) == 0 && is_static == false)) { // Check on name if we are looking for a particular field bool f_is_tls = ts.m.thread_local_fields[fdef_row]; if (search_field_name != 0) { var fname = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 1); if (MetadataStream.CompareString(ts.m, fname, fs.m, search_field_name)) { if (f_is_tls) { is_tls = true; return(cur_tl_offset); } else { is_tls = false; return(cur_offset); } } } // Increment by type size var fsig = (int)ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 2); var ft = ts.m.GetFieldType(ref fsig, ts.gtparams, null); var ft_size = t.GetSize(ft); if (f_is_tls) { cur_tl_offset += ft_size; cur_tl_offset = util.util.align(cur_tl_offset, align); } else { cur_offset += ft_size; cur_offset = util.util.align(cur_offset, align); } } } // Shouldn't get here if looking for a specific field if (search_field_name != 0) { throw new MissingFieldException(); } // Else return size of complete type return(cur_offset); }
private static metadata.ExceptionHeader ParseExceptionHeader(metadata.DataInterface di, ref int ehdr_offset, bool is_fat, metadata.MethodSpec ms) { metadata.ExceptionHeader ehdr = new metadata.ExceptionHeader(); int flags = 0; if (is_fat) { flags = di.ReadInt(ehdr_offset); ehdr.TryILOffset = di.ReadInt(ehdr_offset + 4); ehdr.TryLength = di.ReadInt(ehdr_offset + 8); ehdr.HandlerILOffset = di.ReadInt(ehdr_offset + 12); ehdr.HandlerLength = di.ReadInt(ehdr_offset + 16); } else { flags = di.ReadShort(ehdr_offset); ehdr.TryILOffset = di.ReadShort(ehdr_offset + 2); ehdr.TryLength = di.ReadByte(ehdr_offset + 4); ehdr.HandlerILOffset = di.ReadShort(ehdr_offset + 5); ehdr.HandlerLength = di.ReadByte(ehdr_offset + 7); } switch (flags) { case 0: ehdr.EType = metadata.ExceptionHeader.ExceptionHeaderType.Catch; uint mtoken; if (is_fat) { mtoken = di.ReadUInt(ehdr_offset + 20); } else { mtoken = di.ReadUInt(ehdr_offset + 8); } int table_id, row; ms.m.InterpretToken(mtoken, out table_id, out row); ehdr.ClassToken = ms.m.GetTypeSpec(table_id, row, ms.gtparams, ms.gmparams); break; case 1: ehdr.EType = metadata.ExceptionHeader.ExceptionHeaderType.Filter; if (is_fat) { ehdr.FilterOffset = di.ReadInt(ehdr_offset + 20); } else { ehdr.FilterOffset = di.ReadInt(ehdr_offset + 8); } break; case 2: ehdr.EType = metadata.ExceptionHeader.ExceptionHeaderType.Finally; break; case 4: ehdr.EType = metadata.ExceptionHeader.ExceptionHeaderType.Fault; break; default: throw new Exception("Invalid exception type: " + flags.ToString()); } if (is_fat) { ehdr_offset += 24; } else { ehdr_offset += 12; } return(ehdr); }
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); }
public string MangleMethodSpec(MethodSpec m) { return(MangleMethod(m, true)); }
public string MangleMethod(MethodSpec m) { return(MangleMethod(m, false)); }