Ejemplo n.º 1
0
// 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)
		}
	}
}
Ejemplo n.º 2
0
// 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)
		}
	}
}