// For every function, maybe emit the code... func emitFunctions() { //fnMap := ssautil.AllFunctions(rootProgram) //fmt.Println("DEBUG Tardisgotypes:",Tardisgotypes) dceList := []*ssa.Package{ mainPackage, rootProgram.ImportedPackage(LanguageList[TargetLang].Goruntime), Tardisgotypes} dceExceptions := []string{} if LanguageList[TargetLang].TestFS != "" { // need to load file system dceExceptions = append(dceExceptions, "syscall") // so that we keep UnzipFS() } dceExceptions = append(dceExceptions, LibListNoDCE...) for _, ex := range dceExceptions { exip := rootProgram.ImportedPackage(ex) if exip != nil { dceList = append(dceList, exip) } else { //fmt.Println("DEBUG exip nil for package: ",ex) } } fnMap, grMap = tgossa.VisitedFunctions(rootProgram, dceList, IsOverloaded) /* fmt.Println("DEBUG funcs not requiring goroutines:") for df, db := range grMap { if !db { fmt.Println(df) } } */ /* fmt.Println("DEBUG functions removed by Dead Code Eliminaiton:") for _,pkg := range rootProgram.AllPackages() { for _,mem := range pkg.Members { fn,ok := mem.(*ssa.Function) if ok { _,found := fnMap[fn] if !found { println(fn.String()) } } } } */ var dupCheck = make(map[string]*ssa.Function) for f := range fnMap { p, n := GetFnNameParts(f) first, exists := dupCheck[p+"."+n] if exists { panic(fmt.Sprintf( "duplicate function name: %s.%s\nparent orig %v new %v\n", p, n, uintptr(unsafe.Pointer(first)), uintptr(unsafe.Pointer(f)))) } dupCheck[p+"."+n] = f } for _, f := range fnMapSorted() { if !IsOverloaded(f) { if err := tgossa.CheckNames(f); err != nil { panic(err) } emitFunc(f) } } }
// For every function, maybe emit the code... func (comp *Compilation) emitFunctions() { dceList := []*ssa.Package{ comp.mainPackage, comp.rootProgram.ImportedPackage(LanguageList[comp.TargetLang].Goruntime), } dceExceptions := []string{} if LanguageList[comp.TargetLang].TestFS != "" { // need to load file system dceExceptions = append(dceExceptions, "syscall") // so that we keep UnzipFS() } dceExceptions = append(dceExceptions, comp.LibListNoDCE...) for _, ex := range dceExceptions { exip := comp.rootProgram.ImportedPackage(ex) if exip != nil { dceList = append(dceList, exip) } else { //fmt.Println("DEBUG exip nil for package: ",ex) } } comp.fnMap, comp.grMap = tgossa.VisitedFunctions(comp.rootProgram, dceList, comp.IsOverloaded) /* NOTE non-working code below attempts to improve Dead Code Elimination, // but is unreliable so far, in part because the target lang runtime may use "unsafe" pointers // and in any case, every program of any consequence uses "reflect" // but pointer analysis only fully works when the "reflect" and "unsafe" packages are not used canPointerAnalyse := len(dceExceptions) == 0 // and with no DCE exceptions for _, pkg := range rootProgram.AllPackages() { switch pkg.Object.Name() { case "reflect", "unsafe": canPointerAnalyse = false } } if canPointerAnalyse { println("DEBUG can use pointer analysis") roots := []*ssa.Function{} for _, pkg := range rootProgram.AllPackages() { if pkg != nil { for _, mem := range pkg.Members { fn, ok := mem.(*ssa.Function) if ok { // TODO - not hard-coded values, more descrimination if (pkg.Object.Name() == "main" && fn.Name() == "main") || strings.HasPrefix(fn.Name(), "init") { //(pkg.Object.Name() == LanguageList[TargetLang].Goruntime && fn.Name() == "main") || //pkg.Object.Name() == "reflect" || //(pkg.Object.Name() == "syscall" && fn.Name() == "UnzipFS") { roots = append(roots, fn) //fmt.Println("DEBUG root added:",fn.String()) } } } } } config := &pointer.Config{ Mains: []*ssa.Package{mainPackage}, BuildCallGraph: true, Reflection: true, } ptrResult, err := pointer.Analyze(config) if err != nil { panic(err) } for _, pkg := range rootProgram.AllPackages() { funcs := []*ssa.Function{} for _, mem := range pkg.Members { fn, ok := mem.(*ssa.Function) if ok { funcs = append(funcs, fn) } typ, ok := mem.(*ssa.Type) if ok { mset := rootProgram.MethodSets.MethodSet(typ.Type()) for i, n := 0, mset.Len(); i < n; i++ { mf := rootProgram.Method(mset.At(i)) funcs = append(funcs, mf) //fmt.Printf("DEBUG method %v\n", mf) } } } for _, fn := range funcs { notRoot := true for _, r := range roots { if r == fn { notRoot = false break } } if notRoot { _, found := fnMap[fn] hasPath := false if fn != nil { for _, r := range roots { if r != nil { nod, ok := ptrResult.CallGraph.Nodes[r] if ok { pth := callgraph.PathSearch(nod, func(n *callgraph.Node) bool { if n == nil { return false } return n.Func == fn }) if pth != nil { //fmt.Printf("DEBUG path from %v to %v = %v\n", // r, fn, pth) hasPath = true break } } } } } if found != hasPath { if found { // we found it when we should not have println("DEBUG DCE function not called: ", fn.String()) delete(fnMap, fn) delete(grMap, fn) } else { panic("function not found in DCE cross-check: " + fn.String()) } } } } } } */ /* fmt.Println("DEBUG funcs not requiring goroutines:") for df, db := range grMap { if !db { fmt.Println(df) } } */ // Remove virtual functions for _, pkg := range comp.rootProgram.AllPackages() { for _, vf := range LanguageList[comp.TargetLang].PseudoPkgPaths { if pkg.Object.Path() == vf { for _, mem := range pkg.Members { fn, ok := mem.(*ssa.Function) if ok { //println("DEBUG DCE virtual function: ", fn.String()) delete(comp.fnMap, fn) delete(comp.grMap, fn) } } } } } var dupCheck = make(map[string]*ssa.Function) for f := range comp.fnMap { p, n := comp.GetFnNameParts(f) first, exists := dupCheck[p+"."+n] if exists { panic(fmt.Sprintf( "duplicate function name: %s.%s\nparent orig %v new %v\n", p, n, uintptr(unsafe.Pointer(first)), uintptr(unsafe.Pointer(f)))) } dupCheck[p+"."+n] = f } for _, f := range comp.fnMapSorted() { if !comp.IsOverloaded(f) { if err := tgossa.CheckNames(f); err != nil { panic(err) } comp.emitFunc(f) } } }