From 3dfb92f254ed4f94e3c98a789c171a1cd9c2563d Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 21 Sep 2016 18:53:31 -0400 Subject: [PATCH] cmd/compile: ensure args are live in tail calls for LR machines On link-register machines we uses RET (sym), instead of JMP (sym), for tail call (so the assembler knows and may rewrite it to restore link register if necessary). Add RET to the analysis. Fixes #17186. Fixes #16016 on link-register machines. Change-Id: I8690ac57dd9d49beeea76a5f291988e9a1d3afe5 Reviewed-on: https://go-review.googlesource.com/29570 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/plive.go | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 651ba42044..26e2ce9239 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -549,6 +549,22 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini bvresetall(varkill) bvresetall(avarinit) + // A return instruction with a p.to is a tail return, which brings + // the stack pointer back up (if it ever went down) and then jumps + // to a new function entirely. That form of instruction must read + // all the parameters for correctness, and similarly it must not + // read the out arguments - they won't be set until the new + // function runs. + if (prog.As == obj.AJMP || prog.As == obj.ARET) && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN { + // This is a tail call. Ensure the arguments are still alive. + // See issue 16016. + for i, node := range vars { + if node.Class == PPARAM { + bvset(uevar, int32(i)) + } + } + } + if prog.As == obj.ARET { // Return instructions read all of the out arguments. for i, node := range vars { @@ -569,21 +585,6 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini return } - // A return instruction with a p.to is a tail return, which brings - // the stack pointer back up (if it ever went down) and then jumps - // to a new function entirely. That form of instruction must read - // all the parameters for correctness, and similarly it must not - // read the out arguments - they won't be set until the new - // function runs. - if prog.As == obj.AJMP && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN { - // This is a tail call. Ensure the arguments are still alive. - // See issue 16016. - for i, node := range vars { - if node.Class == PPARAM { - bvset(uevar, int32(i)) - } - } - } if prog.As == obj.ATEXT { // A text instruction marks the entry point to a function and