go.tools/ssa: use correct word size for GOARCH during type checking, interpretation.

Also report an error for "cross-interpretation": not supported
due to the interpreter's assumption that host and target
{int,uint,uintptr} are the same.  (Too tedious and messy to fix.)

Tested manually:

% cat d.go
package main
const m = ^uintptr(0)
const w = m>>8&1 + m>>16&1 + m>>32&1
func main() { println(m, w) }

% ./ssadump -build=P -run d.go
package main:
  const m          m = 18446744073709551615:uintptr
  const w          w = 3:uintptr
18446744073709551615 3

% GOARCH=386 ./ssadump -build=P -run d.go
package main:
  const m          m = 4294967295:uintptr
  const w          w = 2:uintptr
Error: Cross-interpretation is not yet supported (target has GOARCH 386, interpreter has amd64).

Fixes golang/go#7080

R=gri
CC=golang-codereviews
https://golang.org/cl/49070043
This commit is contained in:
Alan Donovan 2014-01-08 14:46:17 -05:00
parent 893253274d
commit 5612f0615f
6 changed files with 33 additions and 38 deletions

View File

@ -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)
}
}

View File

@ -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":

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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.
//