Beispiel #1
0
// setGlobal sets the value of a system-initialized global variable.
func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
	if g, ok := i.globals[pkg.Var(name)]; ok {
		*g = v
		return
	}
	panic("no global variable: " + pkg.Object.Path() + "." + name)
}
Beispiel #2
0
func (c *compiler) buildPackageInitData(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) gccgoimporter.InitData {
	var inits []gccgoimporter.PackageInit
	for _, imp := range mainPkg.Object.Imports() {
		inits = append(inits, initmap[imp].Inits...)
	}
	sort.Sort(byPriorityThenFunc(inits))

	// Deduplicate init entries. We want to preserve the entry with the highest priority.
	// Normally a package's priorities will be consistent among its dependencies, but it is
	// possible for them to be different. For example, if a standard library test augments a
	// package which is a dependency of 'regexp' (which is imported by every test main package)
	// with additional dependencies, those dependencies may cause the package under test to
	// receive a higher priority than indicated by its init clause in 'regexp'.
	uniqinits := make([]gccgoimporter.PackageInit, len(inits))
	uniqinitpos := len(inits)
	uniqinitnames := make(map[string]struct{})
	for i, _ := range inits {
		init := inits[len(inits)-1-i]
		if _, ok := uniqinitnames[init.InitFunc]; !ok {
			uniqinitnames[init.InitFunc] = struct{}{}
			uniqinitpos--
			uniqinits[uniqinitpos] = init
		}
	}
	uniqinits = uniqinits[uniqinitpos:]

	ourprio := 1
	if len(uniqinits) != 0 {
		ourprio = uniqinits[len(uniqinits)-1].Priority + 1
	}

	if imp := mainPkg.Func("init"); imp != nil {
		impname := c.types.mc.mangleFunctionName(imp)
		uniqinits = append(uniqinits, gccgoimporter.PackageInit{mainPkg.Object.Name(), impname, ourprio})
	}

	return gccgoimporter.InitData{ourprio, uniqinits}
}
Beispiel #3
0
// Interpret interprets the Go program whose main package is mainpkg.
// mode specifies various interpreter options.  filename and args are
// the initial values of os.Args for the target program.  sizes is the
// effective type-sizing function for this program.
//
// Interpret returns the exit code of the program: 2 for panic (like
// gc does), or the argument to os.Exit for normal termination.
//
// The SSA program must include the "runtime" package.
//
func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
	i := &interpreter{
		prog:    mainpkg.Prog,
		globals: make(map[ssa.Value]*value),
		mode:    mode,
		sizes:   sizes,
	}
	runtimePkg := i.prog.ImportedPackage("runtime")
	if runtimePkg == nil {
		panic("ssa.Program doesn't include runtime package")
	}
	i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()

	initReflect(i)

	i.osArgs = append(i.osArgs, filename)
	for _, arg := range args {
		i.osArgs = append(i.osArgs, arg)
	}

	for _, pkg := range i.prog.AllPackages() {
		// Initialize global storage.
		for _, m := range pkg.Members {
			switch v := m.(type) {
			case *ssa.Global:
				cell := zero(deref(v.Type()))
				i.globals[v] = &cell
			}
		}

		// Ad-hoc initialization for magic system variables.
		switch pkg.Object.Path() {
		case "syscall":
			setGlobal(i, pkg, "envs", environ)

		case "runtime":
			sz := sizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type())
			setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))

			// Delete the bodies of almost all "runtime" functions since they're magic.
			// A missing intrinsic leads to a very clear error.
			for _, mem := range pkg.Members {
				if fn, ok := mem.(*ssa.Function); ok {
					switch fn.Name() {
					case "GOROOT", "gogetenv":
						// keep
					default:
						fn.Blocks = nil
					}
				}
			}
		}
	}

	// Top-level error handler.
	exitCode = 2
	defer func() {
		if exitCode != 2 || i.mode&DisableRecover != 0 {
			return
		}
		switch p := recover().(type) {
		case exitPanic:
			exitCode = int(p)
			return
		case targetPanic:
			fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
		case runtime.Error:
			fmt.Fprintln(os.Stderr, "panic:", p.Error())
		case string:
			fmt.Fprintln(os.Stderr, "panic:", p)
		default:
			fmt.Fprintf(os.Stderr, "panic: unexpected type: %T\n", p)
		}

		// TODO(adonovan): dump panicking interpreter goroutine?
		// buf := make([]byte, 0x10000)
		// runtime.Stack(buf, false)
		// fmt.Fprintln(os.Stderr, string(buf))
		// (Or dump panicking target goroutine?)
	}()

	// Run!
	call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
	if mainFn := mainpkg.Func("main"); mainFn != nil {
		call(i, nil, token.NoPos, mainFn, nil)
		exitCode = 0
	} else {
		fmt.Fprintln(os.Stderr, "No main function.")
		exitCode = 1
	}
	return
}
Beispiel #4
0
func doMain() error {
	flag.Parse()
	args := flag.Args()

	conf := loader.Config{Build: &build.Default}

	// Choose types.Sizes from conf.Build.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		wordSize = 4
	}
	conf.TypeChecker.Sizes = &types.StdSizes{
		MaxAlign: 8,
		WordSize: wordSize,
	}

	var interpMode interp.Mode
	for _, c := range *interpFlag {
		switch c {
		case 'T':
			interpMode |= interp.EnableTracing
		case 'R':
			interpMode |= interp.DisableRecover
		default:
			return fmt.Errorf("unknown -interp option: '%c'", c)
		}
	}

	if len(args) == 0 {
		fmt.Fprint(os.Stderr, usage)
		os.Exit(1)
	}

	// Profiling support.
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Use the initial packages from the command line.
	args, err := conf.FromArgs(args, *testFlag)
	if err != nil {
		return err
	}

	// The interpreter needs the runtime package.
	if *runFlag {
		conf.Import("runtime")
	}

	// Load, parse and type-check the whole program.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Create and build SSA-form program representation.
	prog := ssautil.CreateProgram(iprog, *modeFlag)

	// Build and display only the initial packages
	// (and synthetic wrappers), unless -run is specified.
	for _, info := range iprog.InitialPackages() {
		prog.Package(info.Pkg).Build()
	}

	// Run the interpreter.
	if *runFlag {
		prog.Build()

		var main *ssa.Package
		pkgs := prog.AllPackages()
		if *testFlag {
			// If -test, run all packages' tests.
			if len(pkgs) > 0 {
				main = prog.CreateTestMainPackage(pkgs...)
			}
			if main == nil {
				return fmt.Errorf("no tests")
			}
		} else {
			// Otherwise, run main.main.
			for _, pkg := range pkgs {
				if pkg.Pkg.Name() == "main" {
					main = pkg
					if main.Func("main") == nil {
						return fmt.Errorf("no func main() in main package")
					}
					break
				}
			}
			if main == nil {
				return fmt.Errorf("no main package")
			}
		}

		if runtime.GOARCH != build.Default.GOARCH {
			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
				build.Default.GOARCH, runtime.GOARCH)
		}

		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Pkg.Path(), args)
	}
	return nil
}
Beispiel #5
0
func doMain() error {
	flag.Parse()
	args := flag.Args()

	conf := loader.Config{
		Build:         &build.Default,
		SourceImports: true,
	}
	// TODO(adonovan): make go/types choose its default Sizes from
	// build.Default or a specified *build.Context.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		wordSize = 4
	}
	conf.TypeChecker.Sizes = &types.StdSizes{
		MaxAlign: 8,
		WordSize: wordSize,
	}

	var mode ssa.BuilderMode
	for _, c := range *buildFlag {
		switch c {
		case 'D':
			mode |= ssa.GlobalDebug
		case 'P':
			mode |= ssa.PrintPackages
		case 'F':
			mode |= ssa.PrintFunctions
		case 'S':
			mode |= ssa.LogSource | ssa.BuildSerially
		case 'C':
			mode |= ssa.SanityCheckFunctions
		case 'N':
			mode |= ssa.NaiveForm
		case 'G':
			conf.SourceImports = false
		case 'L':
			mode |= ssa.BuildSerially
		case 'I':
			mode |= ssa.BareInits
		default:
			return fmt.Errorf("unknown -build option: '%c'", c)
		}
	}

	var interpMode interp.Mode
	for _, c := range *interpFlag {
		switch c {
		case 'T':
			interpMode |= interp.EnableTracing
		case 'R':
			interpMode |= interp.DisableRecover
		default:
			return fmt.Errorf("unknown -interp option: '%c'", c)
		}
	}

	if len(args) == 0 {
		fmt.Fprint(os.Stderr, usage)
		os.Exit(1)
	}

	// Profiling support.
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Use the initial packages from the command line.
	args, err := conf.FromArgs(args, *testFlag)
	if err != nil {
		return err
	}

	// The interpreter needs the runtime package.
	if *runFlag {
		conf.Import("runtime")
	}

	// Load, parse and type-check the whole program.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Create and build SSA-form program representation.
	prog := ssa.Create(iprog, mode)
	prog.BuildAll()

	// Run the interpreter.
	if *runFlag {
		var main *ssa.Package
		pkgs := prog.AllPackages()
		if *testFlag {
			// If -test, run all packages' tests.
			if len(pkgs) > 0 {
				main = prog.CreateTestMainPackage(pkgs...)
			}
			if main == nil {
				return fmt.Errorf("no tests")
			}
		} else {
			// Otherwise, run main.main.
			for _, pkg := range pkgs {
				if pkg.Object.Name() == "main" {
					main = pkg
					if main.Func("main") == nil {
						return fmt.Errorf("no func main() in main package")
					}
					break
				}
			}
			if main == nil {
				return fmt.Errorf("no main package")
			}
		}

		if runtime.GOARCH != build.Default.GOARCH {
			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
				build.Default.GOARCH, runtime.GOARCH)
		}

		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Object.Path(), args)
	}
	return nil
}
Beispiel #6
0
func doCallgraph(ctxt *build.Context, algo, format string, tests bool, args []string) error {
	conf := loader.Config{
		Build:         ctxt,
		SourceImports: true,
	}

	if len(args) == 0 {
		fmt.Fprintln(os.Stderr, Usage)
		return nil
	}

	// Use the initial packages from the command line.
	args, err := conf.FromArgs(args, tests)
	if err != nil {
		return err
	}

	// Load, parse and type-check the whole program.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Create and build SSA-form program representation.
	prog := ssa.Create(iprog, 0)
	prog.BuildAll()

	// Determine the main package.
	// TODO(adonovan): allow independent control over tests, mains
	// and libraries.
	// TODO(adonovan): put this logic in a library; we keep reinventing it.
	var main *ssa.Package
	pkgs := prog.AllPackages()
	if tests {
		// If -test, use all packages' tests.
		if len(pkgs) > 0 {
			main = prog.CreateTestMainPackage(pkgs...)
		}
		if main == nil {
			return fmt.Errorf("no tests")
		}
	} else {
		// Otherwise, use main.main.
		for _, pkg := range pkgs {
			if pkg.Object.Name() == "main" {
				main = pkg
				if main.Func("main") == nil {
					return fmt.Errorf("no func main() in main package")
				}
				break
			}
		}
		if main == nil {
			return fmt.Errorf("no main package")
		}
	}

	// Invariant: main package has a main() function.

	// -- call graph construction ------------------------------------------

	var cg *callgraph.Graph

	switch algo {
	case "pta":
		config := &pointer.Config{
			Mains:          []*ssa.Package{main},
			BuildCallGraph: true,
		}
		ptares, err := pointer.Analyze(config)
		if err != nil {
			return err // internal error in pointer analysis
		}
		cg = ptares.CallGraph

	case "rta":
		roots := []*ssa.Function{
			main.Func("init"),
			main.Func("main"),
		}
		rtares := rta.Analyze(roots, true)
		cg = rtares.CallGraph

		// NB: RTA gives us Reachable and RuntimeTypes too.

	default:
		return fmt.Errorf("unknown algorithm: %s", algo)
	}

	cg.DeleteSyntheticNodes()

	// -- output------------------------------------------------------------

	var before, after string

	// Pre-canned formats.
	switch format {
	case "digraph":
		format = `{{printf "%q %q" .Caller .Callee}}`

	case "graphviz":
		before = "digraph callgraph {\n"
		after = "}\n"
		format = `  {{printf "%q" .Caller}} -> {{printf "%q" .Callee}}"`
	}

	tmpl, err := template.New("-format").Parse(format)
	if err != nil {
		return fmt.Errorf("invalid -format template: %v", err)
	}

	// Allocate these once, outside the traversal.
	var buf bytes.Buffer
	data := Edge{fset: prog.Fset}

	fmt.Fprint(stdout, before)
	if err := callgraph.GraphVisitEdges(cg, func(edge *callgraph.Edge) error {
		data.position.Offset = -1
		data.edge = edge
		data.Caller = edge.Caller.Func
		data.Callee = edge.Callee.Func

		buf.Reset()
		if err := tmpl.Execute(&buf, &data); err != nil {
			return err
		}
		stdout.Write(buf.Bytes())
		if len := buf.Len(); len == 0 || buf.Bytes()[len-1] != '\n' {
			fmt.Fprintln(stdout)
		}
		return nil
	}); err != nil {
		return err
	}
	fmt.Fprint(stdout, after)
	return nil
}
Beispiel #7
0
func doTestable(args []string) error {

	conf := loader.Config{
		Build: &build.Default,
	}

	// TODO(adonovan): make go/types choose its default Sizes from
	// build.Default or a specified *build.Context.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		wordSize = 4
	}

	//if !(*runFlag) {
	wordSize = 4               // TARDIS Go addition to force default int size to 32 bits
	conf.Build.GOARCH = "haxe" // TARDIS Go addition - 32-bit int
	conf.Build.GOOS = "nacl"   // or haxe? TARDIS Go addition - simplest OS-specific code to emulate?
	//}

	conf.Build.BuildTags = strings.Split(*buidTags, " ")

	conf.TypeChecker.Sizes = &types.StdSizes{ // must equal haxe.haxeStdSizes when (!*runFlag)
		MaxAlign: 8,
		WordSize: wordSize,
	}

	var mode ssa.BuilderMode
	/*
		for _, c := range *buildFlag {
			switch c {
			case 'D':
				mode |= ssa.GlobalDebug
			case 'P':
				mode |= ssa.PrintPackages
			case 'F':
				mode |= ssa.PrintFunctions
			case 'S':
				mode |= ssa.LogSource | ssa.BuildSerially
			case 'C':
				mode |= ssa.SanityCheckFunctions
			case 'N':
				mode |= ssa.NaiveForm
			case 'L':
				mode |= ssa.BuildSerially
			case 'I':
				mode |= ssa.BareInits
			default:
				return fmt.Errorf("unknown -build option: '%c'", c)
			}
		}
	*/

	// TARDIS go addition
	if *debugFlag {
		mode |= ssa.GlobalDebug
	}

	var interpMode interp.Mode
	for _, c := range *interpFlag {
		switch c {
		case 'T':
			interpMode |= interp.EnableTracing
		case 'R':
			interpMode |= interp.DisableRecover
		default:
			log.Fatalf("Unknown -interp option: '%c'.", c)
		}
	}

	if len(args) == 0 {
		//fmt.Fprint(os.Stderr, usage)
		return fmt.Errorf("%v", usage)
	}

	// Profiling support.
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			return err
		}
		err = pprof.StartCPUProfile(f)
		if err != nil {
			return err
		}
		defer pprof.StopCPUProfile()
	}

	// TODO Eventually this might be better as an environment variable
	//if !(*runFlag) {
	if *tgoroot == "" {
		if conf.Build.GOPATH == "" {
			return fmt.Errorf("GOPATH must be set")
		}
		conf.Build.GOROOT = strings.Split(conf.Build.GOPATH, ":")[0] + "/src/github.com/tardisgo/tardisgo/goroot/haxe/go1.4"
	} else {
		conf.Build.GOROOT = *tgoroot
	}
	//}
	//fmt.Println("DEBUG GOPATH", conf.Build.GOPATH)
	//fmt.Println("DEBUG GOROOT", conf.Build.GOROOT)

	if *testFlag {
		conf.ImportWithTests(args[0]) // assumes you give the full cannonical name of the package to test
		args = args[1:]
	}

	// Use the initial packages from the command line.
	_, err := conf.FromArgs(args, *testFlag)
	if err != nil {
		return err
	}

	// The interpreter needs the runtime package.
	//if *runFlag {
	conf.Import("runtime")
	//} else {
	// TARDIS GO additional line to add the language specific go runtime code
	conf.Import(pogo.LanguageList[pogo.TargetLang].Goruntime) // TODO add code to set pogo.TargetLang when more than one of them
	//}

	// Load, parse and type-check the whole program, including the type definitions.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Create and build SSA-form program representation.
	*modeFlag |= mode | ssa.SanityCheckFunctions
	prog := ssautil.CreateProgram(iprog, *modeFlag)

	prog.BuildAll()

	// Run the interpreter.
	if *runFlag {
		var main *ssa.Package
		pkgs := prog.AllPackages()
		if *testFlag {
			// If -test, run all packages' tests.
			if len(pkgs) > 0 {
				main = prog.CreateTestMainPackage(pkgs...)
			}
			if main == nil {
				return fmt.Errorf("no tests")
			}
		} else {
			// Otherwise, run main.main.
			for _, pkg := range pkgs {
				if pkg.Object.Name() == "main" {
					main = pkg
					if main.Func("main") == nil {
						return fmt.Errorf("no func main() in main package")
					}
					break
				}
			}
			if main == nil {
				return fmt.Errorf("no main package")
			}
		}

		// NOTE TARDIS Go removal of this test required if we alter the GOARCH to stop architecture-specific code
		//if runtime.GOARCH != build.Default.GOARCH {
		//	return fmt.Errorf("cross-interpretation is not yet supported (target has GOARCH %s, interpreter has %s)",
		//		build.Default.GOARCH, runtime.GOARCH)
		//}

		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Object.Path(), args)
	} else {
		// if not interpreting...
		// TARDIS Go additions: copy run interpreter code above, but call pogo class
		var main *ssa.Package
		pkgs := prog.AllPackages()
		//fmt.Println("DEBUG pkgs:", pkgs)

		if *testFlag {
			// If -test, run all packages' tests.
			if len(pkgs) > 0 {
				main = prog.CreateTestMainPackage(pkgs...)
			}
			if main == nil {
				return fmt.Errorf("no tests")
			}
			fd, err := os.Open(TestFS)
			fd.Close()
			if err == nil {
				LoadTestZipFS = true
				for l := range pogo.LanguageList {
					pogo.LanguageList[l].TestFS = TestFS
				}
			}
		} else {
			// Otherwise, run main.main.
			for _, pkg := range pkgs {
				if pkg.Object.Name() == "main" {
					main = pkg
					if main.Func("main") == nil {
						return fmt.Errorf("no func main() in main package")
					}
					break
				}
			}
			if main == nil {
				return fmt.Errorf("no main package")
			}
		}
		/*
			if runtime.GOARCH != build.Default.GOARCH {
				return fmt.Errorf("cross-interpretation is not yet supported (target has GOARCH %s, interpreter has %s)",
					build.Default.GOARCH, runtime.GOARCH)
			}

			interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Object.Path(), args)
		*/
		pogo.DebugFlag = *debugFlag
		pogo.TraceFlag = *traceFlag
		err = pogo.EntryPoint(main) // TARDIS Go entry point, returns an error
		if err != nil {
			return err
		}
		results := make(chan resChan)
		switch *allFlag {
		case "": // NoOp
		case "all", "bench":
			//for _, dir := range dirs {
			//	err := os.RemoveAll(dir)
			//	if err != nil {
			//		fmt.Println("Error deleting existing '" + dir + "' directory: " + err.Error())
			//	}
			//}

			var targets [][][]string
			if *allFlag == "bench" {
				targets = allBenchmark // fast execution time
			} else {
				targets = allCompile // fast compile time
			}
			for _, cmd := range targets {
				go doTarget(cmd, results)
			}
			for _ = range targets {
				r := <-results
				fmt.Println(r.output)
				if (r.err != nil || len(strings.TrimSpace(r.output)) == 0) && *allFlag != "bench" {
					os.Exit(1) // exit with an error if the test fails, but not for benchmarking
				}
				r.backChan <- true
			}

		case "math": // which is faster for the test with correct math processing, cpp or js?
			//err := os.RemoveAll("tardis/cpp")
			//if err != nil {
			//	fmt.Println("Error deleting existing '" + "tardis/cpp" + "' directory: " + err.Error())
			//}
			mathCmds := [][][]string{
				[][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-cpp", "tardis/cpp"},
					[]string{"echo", `"CPP:"`},
					[]string{"time", "./tardis/cpp/Go"},
				},
				[][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-D", "fullunsafe", "-js", "tardis/go-fu.js"},
					[]string{"echo", `"Node/JS using fullunsafe memory mode (js dataview):"`},
					[]string{"time", "node", "tardis/go-fu.js"},
				},
			}
			for _, cmd := range mathCmds {
				go doTarget(cmd, results)
			}
			for _ = range mathCmds {
				r := <-results
				fmt.Println(r.output)
				if r.err != nil {
					os.Exit(1) // exit with an error if the test fails
				}
				r.backChan <- true
			}

		case "interp", "cpp", "cs", "js", "jsfu", "java": // for running tests
			switch *allFlag {
			case "interp":
				go doTarget([][]string{
					[]string{"echo", ``}, // Output from this line is ignored
					[]string{"echo", `"Neko (haxe --interp):"`},
					[]string{"time", "haxe", "-main", "tardis.Go", "-cp", "tardis", "--interp"},
				}, results)
			case "cpp":
				go doTarget([][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-cpp", "tardis/cpp"},
					[]string{"echo", `"CPP:"`},
					[]string{"time", "./tardis/cpp/Go"},
				}, results)
			case "cs":
				go doTarget([][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-cs", "tardis/cs"},
					[]string{"echo", `"CS:"`},
					[]string{"time", "mono", "./tardis/cs/bin/Go.exe"},
				}, results)
			case "js":
				go doTarget([][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-D", "uselocalfunctions", "-js", "tardis/go.js"},
					[]string{"echo", `"Node/JS:"`},
					[]string{"time", "node", "tardis/go.js"},
				}, results)
			case "jsfu":
				go doTarget([][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-D", "uselocalfunctions", "-D", "fullunsafe", "-js", "tardis/go-fu.js"},
					[]string{"echo", `"Node/JS using fullunsafe memory mode (js dataview):"`},
					[]string{"time", "node", "tardis/go-fu.js"},
				}, results)
			case "java":
				go doTarget([][]string{
					[]string{"haxe", "-main", "tardis.Go", "-cp", "tardis", "-dce", "full", "-D", "inlinepointers", "-java", "tardis/java"},
					[]string{"echo", `"Java:"`},
					[]string{"time", "java", "-jar", "tardis/java/Go.jar"},
				}, results)
			}
			r := <-results
			fmt.Println(r.output)
			if r.err != nil {
				os.Exit(1) // exit with an error if the test fails
			}
			r.backChan <- true

		default:
			panic("invalid value for -haxe flag: " + *allFlag)
		}
	}
	return nil
}
Beispiel #8
0
func doTestable(args []string) error {

	conf := loader.Config{
		Build: &build.Default,
	}

	// TARDISgo addition
	langName := *targetFlag
	langEntry, e := pogo.FindTargetLang(langName)
	if e != nil {
		return e
	}

	// TODO(adonovan): make go/types choose its default Sizes from
	// build.Default or a specified *build.Context.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		wordSize = 4
	}

	if *runFlag {
		// nothing here at the moment
	} else {
		wordSize = 4                 // TARDIS Go addition to force default int size to 32 bits
		conf.Build.GOOS = "nacl"     // TARDIS Go addition - simplest OS-specific code to emulate?
		conf.Build.GOARCH = langName // TARDIS Go addition
	}

	conf.Build.BuildTags = strings.Split(*buidTags, " ")

	conf.TypeChecker.Sizes = &types.StdSizes{ // must equal haxe.haxeStdSizes when (!*runFlag)
		MaxAlign: 8,
		WordSize: wordSize,
	}

	var mode ssa.BuilderMode
	/*
		for _, c := range *buildFlag {
			switch c {
			case 'D':
				mode |= ssa.GlobalDebug
			case 'P':
				mode |= ssa.PrintPackages
			case 'F':
				mode |= ssa.PrintFunctions
			case 'S':
				mode |= ssa.LogSource | ssa.BuildSerially
			case 'C':
				mode |= ssa.SanityCheckFunctions
			case 'N':
				mode |= ssa.NaiveForm
			case 'L':
				mode |= ssa.BuildSerially
			case 'I':
				mode |= ssa.BareInits
			default:
				return fmt.Errorf("unknown -build option: '%c'", c)
			}
		}
	*/

	// TARDIS go addition
	if *debugFlag {
		mode |= ssa.GlobalDebug
	}

	var interpMode interp.Mode
	for _, c := range *interpFlag {
		switch c {
		case 'T':
			interpMode |= interp.EnableTracing
		case 'R':
			interpMode |= interp.DisableRecover
		default:
			log.Fatalf("Unknown -interp option: '%c'.", c)
		}
	}

	if len(args) == 0 {
		//fmt.Fprint(os.Stderr, usage)
		return fmt.Errorf("%v", usage)
	}

	// Profiling support.
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			return err
		}
		err = pprof.StartCPUProfile(f)
		if err != nil {
			return err
		}
		defer pprof.StopCPUProfile()
	}

	if !(*runFlag) {
		if *tgoroot == "" {
			if conf.Build.GOPATH == "" {
				return fmt.Errorf("GOPATH must be set")
			}
			langGOROOT := pogo.LanguageList[langEntry].GOROOT
			if langGOROOT != "" {
				conf.Build.GOROOT = strings.Split(conf.Build.GOPATH, ":")[0] + langGOROOT
			} else {
				if conf.Build.GOROOT == "" {
					return fmt.Errorf("GOROOT must be set (hint: use -tgoroot flag)")
				}
			}
		} else {
			conf.Build.GOROOT = *tgoroot
		}
	}
	//fmt.Println("DEBUG GOPATH", conf.Build.GOPATH)
	//fmt.Println("DEBUG GOROOT", conf.Build.GOROOT)

	if *testFlag {
		conf.ImportWithTests(args[0]) // assumes you give the full cannonical name of the package to test
		args = args[1:]
	}

	// Use the initial packages from the command line.
	_, err := conf.FromArgs(args, *testFlag)
	if err != nil {
		return err
	}

	// The interpreter needs the runtime package.
	if *runFlag {
		conf.Import("runtime")
	} else {
		// TARDIS GO additional line to add the language specific go runtime code
		rt := pogo.LanguageList[langEntry].Goruntime
		if rt != "" {
			conf.Import(rt)
		}
	}

	// Load, parse and type-check the whole program.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Create and build SSA-form program representation.
	*modeFlag |= mode | ssa.SanityCheckFunctions
	prog := ssautil.CreateProgram(iprog, *modeFlag)

	prog.Build()

	var main *ssa.Package
	pkgs := prog.AllPackages()
	//fmt.Println("DEBUG pkgs:", pkgs)

	testFSname := ""
	if *testFlag {
		// If -test, run all packages' tests.
		if len(pkgs) > 0 {
			main = prog.CreateTestMainPackage(pkgs...)
		}
		if main == nil {
			return fmt.Errorf("no tests")
		}
		fd, openErr := os.Open(testFS)
		closeErr := fd.Close()
		if openErr == nil && closeErr == nil {
			loadTestZipFS = true
			testFSname = testFS
		}
	} else {
		// Otherwise, run main.main.
		for _, pkg := range pkgs {
			if pkg.Pkg.Name() == "main" {
				main = pkg
				if main.Func("main") == nil {
					return fmt.Errorf("no func main() in main package")
				}
				break
			}
		}
		if main == nil {
			return fmt.Errorf("no main package")
		}
	}

	if *runFlag { // Run the golang.org/x/tools/go/ssa/interp interpreter.
		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Pkg.Path(), args)
	} else {
		comp, err := pogo.Compile(main, *debugFlag, *traceFlag, langName, testFSname) // TARDIS Go entry point, returns an error
		if err != nil {
			return err
		}
		comp.Recycle()

		switch langName {
		case "haxe":
			haxe.RunHaxe(allFlag, loadTestZipFS, testFSname)
		}
	}
	return nil
}