diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index e3a71a9f3f..9d87f38ea1 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -583,6 +583,14 @@ func (s *state) stmt(n *Node) { b.Kind = ssa.BlockRet b.Control = m b.AddEdgeTo(s.exit) + case ORETJMP: + s.stmtList(n.List) + m := s.mem() + b := s.endBlock() + b.Kind = ssa.BlockRetJmp + b.Aux = n.Left.Sym + b.Control = m + b.AddEdgeTo(s.exit) case OCONTINUE, OBREAK: var op string @@ -2054,6 +2062,11 @@ func canSSA(n *Node) bool { case PEXTERN, PPARAMOUT, PPARAMREF: return false } + if n.Class == PPARAM && n.String() == ".this" { + // wrappers generated by genwrapper need to update + // the .this pointer in place. + return false + } return canSSAType(n.Type) // TODO: try to make more variables SSAable? } @@ -3475,6 +3488,11 @@ func (s *genState) genBlock(b, next *ssa.Block) { s.deferReturn() } Prog(obj.ARET) + case ssa.BlockRetJmp: + p := Prog(obj.AJMP) + p.To.Type = obj.TYPE_MEM + p.To.Name = obj.NAME_EXTERN + p.To.Sym = Linksym(b.Aux.(*Sym)) case ssa.BlockCall: if b.Succs[0] != next { p := Prog(obj.AJMP) diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index 1d5e617c55..5fb93cd5a7 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -30,6 +30,9 @@ type Block struct { // has a memory control value. Control *Value + // Auxiliary info for the block. Its value depends on the Kind. + Aux interface{} + // The unordered set of Values that define the operation of this block. // The list must include the control value, if any. (TODO: need this last condition?) // After the scheduling pass, this list is ordered. @@ -65,6 +68,9 @@ func (b *Block) String() string { // long form print func (b *Block) LongString() string { s := b.Kind.String() + if b.Aux != nil { + s += fmt.Sprintf(" %s", b.Aux) + } if b.Control != nil { s += fmt.Sprintf(" %s", b.Control) } diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index b860f633ef..9747585f4a 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -72,6 +72,22 @@ func checkFunc(f *Func) { if b.Succs[0].Kind != BlockExit { f.Fatalf("ret block %s has successor %s, not Exit", b, b.Succs[0].Kind) } + case BlockRetJmp: + if len(b.Succs) != 1 { + f.Fatalf("retjmp block %s len(Succs)==%d, want 1", b, len(b.Succs)) + } + if b.Control == nil { + f.Fatalf("retjmp block %s has nil control %s", b) + } + if !b.Control.Type.IsMemory() { + f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString()) + } + if b.Succs[0].Kind != BlockExit { + f.Fatalf("retjmp block %s has successor %s, not Exit", b, b.Succs[0].Kind) + } + if b.Aux == nil { + f.Fatalf("retjmp block %s has nil Aux field", b) + } case BlockDead: if len(b.Succs) != 0 { f.Fatalf("dead block %s has successors", b) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 9bc77909b5..1c26946781 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -376,13 +376,14 @@ var genericOps = []opData{ // First nil [always,never] var genericBlocks = []blockData{ - {name: "Exit"}, // no successors. There should only be 1 of these. - {name: "Dead"}, // no successors; determined to be dead but not yet removed - {name: "Plain"}, // a single successor - {name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1] - {name: "Call"}, // 2 successors, normal return and panic - {name: "First"}, // 2 successors, always takes the first one (second is dead) - {name: "Ret"}, // 1 successor, branches to exit + {name: "Exit"}, // no successors. There should only be 1 of these. + {name: "Dead"}, // no successors; determined to be dead but not yet removed + {name: "Plain"}, // a single successor + {name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1] + {name: "Call"}, // 2 successors, normal return and panic + {name: "First"}, // 2 successors, always takes the first one (second is dead) + {name: "Ret"}, // 1 successor, branches to exit + {name: "RetJmp"}, // 1 successor, branches to exit. Jumps to b.Aux.(*gc.Sym) } func init() { diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index c84dccf793..68a432c676 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -384,6 +384,9 @@ func (b *Block) HTML() string { func (b *Block) LongHTML() string { // TODO: improve this for HTML? s := fmt.Sprintf("%s", html.EscapeString(b.String()), html.EscapeString(b.Kind.String())) + if b.Aux != nil { + s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux)) + } if b.Control != nil { s += fmt.Sprintf(" %s", b.Control.HTML()) } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 0d7343c8aa..bca6654158 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -29,6 +29,7 @@ const ( BlockCall BlockFirst BlockRet + BlockRetJmp ) var blockString = [...]string{ @@ -49,13 +50,14 @@ var blockString = [...]string{ BlockAMD64ORD: "ORD", BlockAMD64NAN: "NAN", - BlockExit: "Exit", - BlockDead: "Dead", - BlockPlain: "Plain", - BlockIf: "If", - BlockCall: "Call", - BlockFirst: "First", - BlockRet: "Ret", + BlockExit: "Exit", + BlockDead: "Dead", + BlockPlain: "Plain", + BlockIf: "If", + BlockCall: "Call", + BlockFirst: "First", + BlockRet: "Ret", + BlockRetJmp: "RetJmp", } func (k BlockKind) String() string { return blockString[k] }