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:
parent
893253274d
commit
5612f0615f
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue