Esempio n. 1
0
        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));
        }
Esempio n. 2
0
            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();
            }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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");
        }
Esempio n. 6
0
 public static int GetVTableOffset(metadata.MethodSpec ms, Target t)
 {
     return(GetVTableOffset(ms.type, ms, t));
 }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
 public string MangleMethodSpec(MethodSpec m)
 {
     return(MangleMethod(m, true));
 }
Esempio n. 12
0
 public string MangleMethod(MethodSpec m)
 {
     return(MangleMethod(m, false));
 }