diff --git a/cmd/ssadump/main.go b/cmd/ssadump/main.go index 3a135b02..def7215b 100644 --- a/cmd/ssadump/main.go +++ b/cmd/ssadump/main.go @@ -14,6 +14,7 @@ import ( "runtime" "runtime/pprof" + "code.google.com/p/go.tools/go/types" "code.google.com/p/go.tools/importer" "code.google.com/p/go.tools/ssa" "code.google.com/p/go.tools/ssa/interp" @@ -73,6 +74,17 @@ func main() { args := flag.Args() impctx := importer.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 impctx.Build.GOARCH { + case "386", "arm": + wordSize = 4 + } + impctx.TypeChecker.Sizes = &types.StdSizes{ + MaxAlign: 8, + WordSize: wordSize, + } var debugMode bool var mode ssa.BuilderMode @@ -173,6 +185,12 @@ func main() { if main == nil { log.Fatal("No main package and no tests") } - interp.Interpret(main, interpMode, main.Object.Path(), args) + + if runtime.GOARCH != impctx.Build.GOARCH { + log.Fatalf("Cross-interpretation is not yet supported (target has GOARCH %s, interpreter has %s).", + impctx.Build.GOARCH, runtime.GOARCH) + } + + interp.Interpret(main, interpMode, impctx.TypeChecker.Sizes, main.Object.Path(), args) } } diff --git a/ssa/interp/interp.go b/ssa/interp/interp.go index b9be370b..82ed0e03 100644 --- a/ssa/interp/interp.go +++ b/ssa/interp/interp.go @@ -622,18 +622,22 @@ func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) { panic("no global variable: " + pkg.Object.Path() + "." + name) } -var stdSizes = types.StdSizes{WordSize: 8, MaxAlign: 8} +// _sizes is the effective type-sizing function. +// TODO(adonovan): avoid global state. +var _sizes types.Sizes // 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. +// 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, filename string, args []string) (exitCode int) { +func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) { + _sizes = sizes i := &interpreter{ prog: mainpkg.Prog, globals: make(map[ssa.Value]*value), @@ -669,8 +673,7 @@ func Interpret(mainpkg *ssa.Package, mode Mode, filename string, args []string) setGlobal(i, pkg, "envs", envs) case "runtime": - // (Assumes no custom Sizeof used during SSA construction.) - sz := stdSizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type()) + sz := sizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type()) setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz)) case "os": diff --git a/ssa/interp/interp_test.go b/ssa/interp/interp_test.go index 9587dbe8..ceacbbe6 100644 --- a/ssa/interp/interp_test.go +++ b/ssa/interp/interp_test.go @@ -16,6 +16,7 @@ import ( "testing" "time" + "code.google.com/p/go.tools/go/types" "code.google.com/p/go.tools/importer" "code.google.com/p/go.tools/ssa" "code.google.com/p/go.tools/ssa/interp" @@ -222,7 +223,7 @@ func run(t *testing.T, dir, input string, success successPredicate) bool { interp.CapturedOutput = &out hint = fmt.Sprintf("To trace execution, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input) - exitCode := interp.Interpret(mainPkg, 0, inputs[0], []string{}) + exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{8, 8}, inputs[0], []string{}) // The definition of success varies with each file. if err := success(exitCode, out.String()); err != nil { diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index e32bdf9c..2b9fea9e 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -108,7 +108,7 @@ func constValue(c *ssa.Const) value { } } - panic(fmt.Sprintf("constValue: Value.(type)=%T Type()=%s", c.Value, c.Type())) + panic(fmt.Sprintf("constValue: %s", c)) } // asInt converts x, which must be an integer, to an int suitable for diff --git a/ssa/interp/reflect.go b/ssa/interp/reflect.go index 5735cc92..556d8036 100644 --- a/ssa/interp/reflect.go +++ b/ssa/interp/reflect.go @@ -81,33 +81,7 @@ func ext۰reflect۰rtype۰Bits(fn *ssa.Function, args []value) value { if !ok { panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt)) } - switch basic.Kind() { - case types.Int8, types.Uint8: - return 8 - case types.Int16, types.Uint16: - return 16 - case types.Int, types.UntypedInt: - // Assume sizeof(int) is same on host and target; ditto uint. - return reflect.TypeOf(int(0)).Bits() - case types.Uintptr: - // Assume sizeof(uintptr) is same on host and target. - return reflect.TypeOf(uintptr(0)).Bits() - case types.Int32, types.Uint32: - return 32 - case types.Int64, types.Uint64: - return 64 - case types.Float32: - return 32 - case types.Float64, types.UntypedFloat: - return 64 - case types.Complex64: - return 64 - case types.Complex128, types.UntypedComplex: - return 128 - default: - panic(fmt.Sprintf("reflect.Type.Bits(%s)", basic)) - } - return nil + return _sizes.Sizeof(basic) * 8 } func ext۰reflect۰rtype۰Elem(fn *ssa.Function, args []value) value { @@ -161,8 +135,7 @@ func ext۰reflect۰rtype۰Out(fn *ssa.Function, args []value) value { func ext۰reflect۰rtype۰Size(fn *ssa.Function, args []value) value { // Signature: func (t reflect.rtype) uintptr - // (Assumes no custom Sizeof used during SSA construction.) - return uintptr(stdSizes.Sizeof(args[0].(rtype).t)) + return uint64(_sizes.Sizeof(args[0].(rtype).t)) } func ext۰reflect۰rtype۰String(fn *ssa.Function, args []value) value { diff --git a/ssa/util.go b/ssa/util.go index a2bd9a76..3c661c36 100644 --- a/ssa/util.go +++ b/ssa/util.go @@ -62,7 +62,7 @@ func deref(typ types.Type) types.Type { // it returns the incoming type for all other types. The default type // for untyped nil is untyped nil. // -// Exported to exp/ssa/interp. +// Exported to ssa/interp. // // TODO(gri): this is a copy of go/types.defaultType; export that function. //