Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 91 additions & 2 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ type context struct {
rewrites map[string]string
embedMap goembed.VarMap
embedInits []embedInit

trackCallerFrames bool
callerFrameMark llssa.Expr
}

func (p *context) rewriteValue(name string) (string, bool) {
Expand All @@ -206,6 +209,63 @@ func (p *context) rewriteValue(name string) (string, bool) {
return val, ok
}

func filesUseRuntimeCaller(files []*ast.File) bool {
for _, file := range files {
runtimeNames := make(map[string]struct{})
var dotRuntime bool
for _, imp := range file.Imports {
path, err := strconv.Unquote(imp.Path.Value)
if err != nil || path != "runtime" {
continue
}
name := "runtime"
if imp.Name != nil {
switch imp.Name.Name {
case ".":
dotRuntime = true
continue
case "_":
continue
default:
name = imp.Name.Name
}
}
runtimeNames[name] = struct{}{}
}
if len(runtimeNames) == 0 && !dotRuntime {
continue
}
found := false
ast.Inspect(file, func(n ast.Node) bool {
if found {
return false
}
switch n := n.(type) {
case *ast.SelectorExpr:
if !isRuntimeCallerName(n.Sel.Name) {
return true
}
if ident, ok := n.X.(*ast.Ident); ok {
if _, ok := runtimeNames[ident.Name]; ok {
found = true
return false
}
}
case *ast.Ident:
if dotRuntime && isRuntimeCallerName(n.Name) {
found = true
return false
}
}
return true
})
if found {
return true
}
}
return false
}

// isStringPtrType checks if typ is a pointer to the basic string type (*string).
// This is used to validate that -ldflags -X can only rewrite variables of type *string,
// not derived string types like "type T string".
Expand Down Expand Up @@ -433,12 +493,13 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
dbgEnabled := enableDbg && (f == nil || f.Origin() == nil)
dbgSymsEnabled := enableDbgSyms && (f == nil || f.Origin() == nil)
p.inits = append(p.inits, func() {
oldFn, oldGoFn := p.fn, p.goFn
oldFn, oldGoFn, oldCallerFrameMark := p.fn, p.goFn, p.callerFrameMark
p.fn = fn
p.goFn = f
p.callerFrameMark = llssa.Nil
p.state = state // restore pkgState when compiling funcBody
defer func() {
p.fn, p.goFn = oldFn, oldGoFn
p.fn, p.goFn, p.callerFrameMark = oldFn, oldGoFn, oldCallerFrameMark
}()
p.phis = nil
if dbgSymsEnabled {
Expand Down Expand Up @@ -501,6 +562,18 @@ func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
return p.goProg.Fset.Position(f.Pos())
}

func (p *context) getFuncEndPos(f *ssa.Function) token.Position {
if syntax := f.Syntax(); syntax != nil && syntax.End().IsValid() {
return p.goProg.Fset.Position(syntax.End())
}
if f.Object() != nil {
if fn, ok := f.Object().(*types.Func); ok && fn.Scope() != nil && fn.Scope().End().IsValid() {
return p.goProg.Fset.Position(fn.Scope().End())
}
}
return p.getFuncBodyPos(f)
}

func isGlobal(v *types.Var) bool {
// TODO(lijie): better implementation
return strings.HasPrefix(v.Parent().String(), "package ")
Expand Down Expand Up @@ -559,6 +632,9 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
var instrs = block.Instrs[n:]
var ret = fn.Block(block.Index)
b.SetBlock(ret)
if block.Index == 0 && p.shouldTrackCallerFrames() {
p.pushCallerFrame(b, block.Parent())
}
if block.Index == 0 && enableCallTracing && !strings.HasPrefix(fn.Name(), "github.com/goplus/llgo/runtime/internal/runtime.Print") {
b.Printf("call " + fn.Name() + "\n\x00")
}
Expand Down Expand Up @@ -906,6 +982,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
if v.Op == token.ARROW {
ret = b.Recv(x, v.CommaOk)
} else {
p.setCallerLine(b, v.Pos())
ret = b.UnOp(v.Op, x)
}
case *ssa.ChangeType:
Expand All @@ -918,6 +995,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
ret = b.Convert(p.type_(t, llssa.InGo), x)
case *ssa.FieldAddr:
x := p.compileValue(b, v.X)
p.setCallerLine(b, v.Pos())
ret = b.FieldAddr(x, v.Field)
case *ssa.Alloc:
t := v.Type().(*types.Pointer)
Expand All @@ -933,10 +1011,12 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
}
x := p.compileValue(b, vx)
idx := p.compileValue(b, v.Index)
p.setCallerLine(b, v.Pos())
ret = b.IndexAddr(x, idx)
case *ssa.Index:
x := p.compileValue(b, v.X)
idx := p.compileValue(b, v.Index)
p.setCallerLine(b, v.Pos())
ret = b.Index(x, idx, func() (addr llssa.Expr, zero bool) {
switch n := v.X.(type) {
case *ssa.Const:
Expand Down Expand Up @@ -966,6 +1046,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
if v.Max != nil {
max = p.compileValue(b, v.Max)
}
p.setCallerLine(b, v.Pos())
ret = b.Slice(x, low, high, max)
ret.Type = p.type_(v.Type(), llssa.InGo)
case *ssa.MakeInterface:
Expand Down Expand Up @@ -1139,8 +1220,12 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
}
}
if p.returnNeedsImplicitRunDefers(v) {
p.setCallerLineNumber(b, p.getFuncEndPos(v.Parent()).Line)
b.RunDefers()
}
if p.shouldTrackCallerFrames() {
p.popCallerFrame(b)
}
b.Return(results...)
case *ssa.If:
fn := p.fn
Expand All @@ -1163,9 +1248,11 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
case *ssa.Go:
p.call(b, llssa.Go, &v.Call)
case *ssa.RunDefers:
p.setCallerLineNumber(b, p.getFuncEndPos(v.Parent()).Line)
b.RunDefers()
case *ssa.Panic:
arg := p.compileValue(b, v.X)
p.setCallerLine(b, v.Pos())
b.Panic(arg)
case *ssa.Send:
ch := p.compileValue(b, v.Chan)
Expand Down Expand Up @@ -1471,6 +1558,8 @@ func newPackageEx(prog llssa.Program, patches Patches, rewrites map[string]strin
},
cgoSymbols: make([]string, 0, 128),
rewrites: rewrites,

trackCallerFrames: filesUseRuntimeCaller(files) || packageUsesRuntimeCaller(pkg),
}
if embedMap != nil {
ctx.embedMap = *embedMap
Expand Down
Loading
Loading