Exemple #1
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);
        }
Exemple #2
0
        protected internal override Code AssembleBoxRetTypeMethod(MethodSpec ms, TysilaState s)
        {
            // Move all parameters up one - this will require knowledge of the param locs
            // if the return type is an object (to get the 'from' locations) and
            // knowledge of the param locs in the target method (the 'to' locations)
            // Allocate space on heap (boxed return object)

            var cc           = cc_map[ms.CallingConvention];
            var cc_class_map = cc_classmap[ms.CallingConvention];
            int stack_loc    = 0;
            var from_locs    = GetRegLocs(new ir.Param
            {
                m  = ms.m,
                ms = ms,
            }, ref stack_loc, cc, cc_class_map,
                                          ms.CallingConvention,
                                          out var from_sizes, out var from_types,
                                          null);

            stack_loc = 0;
            var to_locs = GetRegLocs(new ir.Param
            {
                m  = ms.m,
                ms = ms,
            }, ref stack_loc, cc, cc_class_map,
                                     ms.CallingConvention,
                                     out var to_sizes, out var to_types,
                                     ms.m.SystemIntPtr);

            // Generate code
            var c = new Code();

            c.mc = new List <MCInst>();
            c.s  = s;
            var n  = new cil.CilNode(ms, 0);
            var ir = new cil.CilNode.IRNode {
                parent = n, mc = c.mc
            };

            ir.opcode = Opcode.oc_nop;
            n.irnodes.Add(ir);
            c.starts = new List <cil.CilNode>();
            c.starts.Add(n);
            c.ms = ms;
            c.t  = this;

            // copy from[0:n] to to[1:n+1] in reverse order so
            //  we don't overwrite the previous registers
            ulong defined = 0;

            for (int i = from_locs.Length - 1; i >= 0; i--)
            {
                handle_move(to_locs[i + 1], from_locs[i], c.mc, ir, c, x86_64.x86_64_Assembler.r_rax, from_sizes[i]);
                defined |= to_locs[i + 1].mask;
            }

            // call gcmalloc with the size of the boxed version of the return
            //  type
            var ts          = ms.ReturnType;
            var tsize       = GetSize(ts);
            var sysobj_size = layout.Layout.GetTypeSize(c.ms.m.SystemObject, c.t);
            var boxed_size  = util.util.align(sysobj_size + tsize, psize);

            // decide on the registers we need to save around gcmalloc
            var caller_preserves = cc_caller_preserves_map[ms.CallingConvention];
            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);
            }
            int push_length = 0;

            foreach (var r in push_list)
            {
                handle_push(r, ref push_length, c.mc, ir, c);
            }
            c.mc.Add(inst(x86_call_rel32, new Param {
                t = Opcode.vl_call_target, str = "gcmalloc"
            },
                          new Param {
                t = Opcode.vl_c32, v = boxed_size
            }, ir));
            for (int i = push_list.Count - 1; i >= 0; i--)
            {
                handle_pop(push_list[i], ref push_length, c.mc, ir, c);
            }

            // put vtable pointer into gcmalloc result
            c.mc.Add(inst(x86_mov_rm32_lab, new ContentsReg {
                basereg = r_eax, size = 4
            },
                          new Param {
                t = Opcode.vl_str, str = ts.MangleType()
            }, ir));

            // put rax into to[0]
            handle_move(to_locs[0], r_eax, c.mc, ir, c);

            // unbox to[0] (i.e. increment pointer so it points to the inner data)
            c.mc.Add(inst(psize == 4 ? x86_add_rm32_imm8 : x86_add_rm64_imm8, to_locs[0], sysobj_size, ir));

            // call the actual function (see AssembleBoxedMethod below)
            var unboxed  = ms.Unbox;
            var act_meth = unboxed.MangleMethod();

            s.r.MethodRequestor.Request(unboxed);

            // Save rax around the call and return it
            // We do this because the actual method returns the address of a value type in rax
            //  and we want to return the address of the boxed object instead
            c.mc.Add(inst(x86_push_r32, r_eax, ir));
            c.mc.Add(inst(x86_call_rel32, new Param {
                t = Opcode.vl_str, str = act_meth
            }, ir));
            c.mc.Add(inst(x86_pop_r32, r_eax, ir));
            c.mc.Add(inst(x86_ret, ir));

            return(c);
        }