summaryrefslogtreecommitdiff
path: root/src/pkg/exp/ogle/rvalue.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/ogle/rvalue.go')
-rw-r--r--src/pkg/exp/ogle/rvalue.go579
1 files changed, 579 insertions, 0 deletions
diff --git a/src/pkg/exp/ogle/rvalue.go b/src/pkg/exp/ogle/rvalue.go
new file mode 100644
index 000000000..9077e238b
--- /dev/null
+++ b/src/pkg/exp/ogle/rvalue.go
@@ -0,0 +1,579 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+ "debug/proc";
+ "exp/eval";
+ "fmt";
+)
+
+// A RemoteMismatchError occurs when an operation that requires two
+// identical remote processes is given different process. For
+// example, this occurs when trying to set a pointer in one process to
+// point to something in another process.
+type RemoteMismatchError string
+
+func (e RemoteMismatchError) String() string {
+ return string(e);
+}
+
+// A ReadOnlyError occurs when attempting to set or assign to a
+// read-only value.
+type ReadOnlyError string
+
+func (e ReadOnlyError) String() string {
+ return string(e);
+}
+
+// A maker is a function that converts a remote address into an
+// interpreter Value.
+type maker func(remote) eval.Value
+
+type remoteValue interface {
+ addr() remote;
+}
+
+// remote represents an address in a remote process.
+type remote struct {
+ base proc.Word;
+ p *Process;
+}
+
+func (v remote) Get(a aborter, size int) uint64 {
+ // TODO(austin) This variable might temporarily be in a
+ // register. We could trace the assembly back from the
+ // current PC, looking for the beginning of the function or a
+ // call (both of which guarantee that the variable is in
+ // memory), or an instruction that loads the variable into a
+ // register.
+ //
+ // TODO(austin) If this is a local variable, it might not be
+ // live at this PC. In fact, because the compiler reuses
+ // slots, there might even be a different local variable at
+ // this location right now. A simple solution to both
+ // problems is to include the range of PC's over which a local
+ // variable is live in the symbol table.
+ //
+ // TODO(austin) We need to prevent the remote garbage
+ // collector from collecting objects out from under us.
+ var arr [8]byte;
+ buf := arr[0:size];
+ _, err := v.p.Peek(v.base, buf);
+ if err != nil {
+ a.Abort(err);
+ }
+ return uint64(v.p.ToWord(buf));
+}
+
+func (v remote) Set(a aborter, size int, x uint64) {
+ var arr [8]byte;
+ buf := arr[0:size];
+ v.p.FromWord(proc.Word(x), buf);
+ _, err := v.p.Poke(v.base, buf);
+ if err != nil {
+ a.Abort(err);
+ }
+}
+
+func (v remote) plus(x proc.Word) remote {
+ return remote{v.base + x, v.p};
+}
+
+func tryRVString(f func(a aborter) string) string {
+ var s string;
+ err := try(func(a aborter) { s = f(a) });
+ if err != nil {
+ return fmt.Sprintf("<error: %v>", err);
+ }
+ return s;
+}
+
+/*
+ * Bool
+ */
+
+type remoteBool struct {
+ r remote;
+}
+
+func (v remoteBool) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
+}
+
+func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.BoolValue).Get(t));
+}
+
+func (v remoteBool) Get(t *eval.Thread) bool {
+ return v.aGet(t);
+}
+
+func (v remoteBool) aGet(a aborter) bool {
+ return v.r.Get(a, 1) != 0;
+}
+
+func (v remoteBool) Set(t *eval.Thread, x bool) {
+ v.aSet(t, x);
+}
+
+func (v remoteBool) aSet(a aborter, x bool) {
+ if x {
+ v.r.Set(a, 1, 1);
+ } else {
+ v.r.Set(a, 1, 0);
+ }
+}
+
+func (v remoteBool) addr() remote {
+ return v.r;
+}
+
+func mkBool(r remote) eval.Value {
+ return remoteBool{r};
+}
+
+/*
+ * Uint
+ */
+
+type remoteUint struct {
+ r remote;
+ size int;
+}
+
+func (v remoteUint) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
+}
+
+func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.UintValue).Get(t));
+}
+
+func (v remoteUint) Get(t *eval.Thread) uint64 {
+ return v.aGet(t);
+}
+
+func (v remoteUint) aGet(a aborter) uint64 {
+ return v.r.Get(a, v.size);
+}
+
+func (v remoteUint) Set(t *eval.Thread, x uint64) {
+ v.aSet(t, x);
+}
+
+func (v remoteUint) aSet(a aborter, x uint64) {
+ v.r.Set(a, v.size, x);
+}
+
+func (v remoteUint) addr() remote {
+ return v.r;
+}
+
+func mkUint8(r remote) eval.Value {
+ return remoteUint{r, 1};
+}
+
+func mkUint16(r remote) eval.Value {
+ return remoteUint{r, 2};
+}
+
+func mkUint32(r remote) eval.Value {
+ return remoteUint{r, 4};
+}
+
+func mkUint64(r remote) eval.Value {
+ return remoteUint{r, 8};
+}
+
+func mkUint(r remote) eval.Value {
+ return remoteUint{r, r.p.IntSize()};
+}
+
+func mkUintptr(r remote) eval.Value {
+ return remoteUint{r, r.p.PtrSize()};
+}
+
+/*
+ * Int
+ */
+
+type remoteInt struct {
+ r remote;
+ size int;
+}
+
+func (v remoteInt) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
+}
+
+func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.IntValue).Get(t));
+}
+
+func (v remoteInt) Get(t *eval.Thread) int64 {
+ return v.aGet(t);
+}
+
+func (v remoteInt) aGet(a aborter) int64 {
+ return int64(v.r.Get(a, v.size));
+}
+
+func (v remoteInt) Set(t *eval.Thread, x int64) {
+ v.aSet(t, x);
+}
+
+func (v remoteInt) aSet(a aborter, x int64) {
+ v.r.Set(a, v.size, uint64(x));
+}
+
+func (v remoteInt) addr() remote {
+ return v.r;
+}
+
+func mkInt8(r remote) eval.Value {
+ return remoteInt{r, 1};
+}
+
+func mkInt16(r remote) eval.Value {
+ return remoteInt{r, 2};
+}
+
+func mkInt32(r remote) eval.Value {
+ return remoteInt{r, 4};
+}
+
+func mkInt64(r remote) eval.Value {
+ return remoteInt{r, 8};
+}
+
+func mkInt(r remote) eval.Value {
+ return remoteInt{r, r.p.IntSize()};
+}
+
+/*
+ * Float
+ */
+
+type remoteFloat struct {
+ r remote;
+ size int;
+}
+
+func (v remoteFloat) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
+}
+
+func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.FloatValue).Get(t));
+}
+
+func (v remoteFloat) Get(t *eval.Thread) float64 {
+ return v.aGet(t);
+}
+
+func (v remoteFloat) aGet(a aborter) float64 {
+ bits := v.r.Get(a, v.size);
+ switch v.size {
+ case 4:
+ return float64(v.r.p.ToFloat32(uint32(bits)));
+ case 8:
+ return v.r.p.ToFloat64(bits);
+ }
+ panic("Unexpected float size ", v.size);
+}
+
+func (v remoteFloat) Set(t *eval.Thread, x float64) {
+ v.aSet(t, x);
+}
+
+func (v remoteFloat) aSet(a aborter, x float64) {
+ var bits uint64;
+ switch v.size{
+ case 4:
+ bits = uint64(v.r.p.FromFloat32(float32(x)));
+ case 8:
+ bits = v.r.p.FromFloat64(x);
+ default:
+ panic("Unexpected float size ", v.size);
+ }
+ v.r.Set(a, v.size, bits);
+}
+
+func (v remoteFloat) addr() remote {
+ return v.r;
+}
+
+func mkFloat32(r remote) eval.Value {
+ return remoteFloat{r, 4};
+}
+
+func mkFloat64(r remote) eval.Value {
+ return remoteFloat{r, 8};
+}
+
+func mkFloat(r remote) eval.Value {
+ return remoteFloat{r, r.p.FloatSize()};
+}
+
+/*
+ * String
+ */
+
+type remoteString struct {
+ r remote;
+}
+
+func (v remoteString) String() string {
+ return tryRVString(func(a aborter) string { return v.aGet(a) });
+}
+
+func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.StringValue).Get(t));
+}
+
+func (v remoteString) Get(t *eval.Thread) string {
+ return v.aGet(t);
+}
+
+func (v remoteString) aGet(a aborter) string {
+ rs := v.r.p.runtime.String.mk(v.r).(remoteStruct);
+ str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a));
+ len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a);
+
+ bytes := make([]uint8, len);
+ _, err := v.r.p.Peek(str, bytes);
+ if err != nil {
+ a.Abort(err);
+ }
+ return string(bytes);
+}
+
+func (v remoteString) Set(t *eval.Thread, x string) {
+ v.aSet(t, x);
+}
+
+func (v remoteString) aSet(a aborter, x string) {
+ // TODO(austin) This isn't generally possible without the
+ // ability to allocate remote memory.
+ a.Abort(ReadOnlyError("remote strings cannot be assigned to"));
+}
+
+func mkString(r remote) eval.Value {
+ return remoteString{r};
+}
+
+/*
+ * Array
+ */
+
+type remoteArray struct {
+ r remote;
+ len int64;
+ elemType *remoteType;
+}
+
+func (v remoteArray) String() string {
+ res := "{";
+ for i := int64(0); i < v.len; i++ {
+ if i > 0 {
+ res += ", ";
+ }
+ res += v.elem(i).String();
+ }
+ return res + "}";
+}
+
+func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
+ // TODO(austin) Could do a bigger memcpy if o is a
+ // remoteArray in the same Process.
+ oa := o.(eval.ArrayValue);
+ for i := int64(0); i < v.len; i++ {
+ v.Elem(t, i).Assign(t, oa.Elem(t, i));
+ }
+}
+
+func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
+ return v;
+}
+
+func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
+ return v.elem(i);
+}
+
+func (v remoteArray) elem(i int64) eval.Value {
+ return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i)));
+}
+
+func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
+ return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType};
+}
+
+/*
+ * Struct
+ */
+
+type remoteStruct struct {
+ r remote;
+ layout []remoteStructField;
+}
+
+type remoteStructField struct {
+ offset int;
+ fieldType *remoteType;
+}
+
+func (v remoteStruct) String() string {
+ res := "{";
+ for i := range v.layout {
+ if i > 0 {
+ res += ", ";
+ }
+ res += v.field(i).String();
+ }
+ return res + "}";
+}
+
+func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
+ // TODO(austin) Could do a bigger memcpy.
+ oa := o.(eval.StructValue);
+ l := len(v.layout);
+ for i := 0; i < l; i++ {
+ v.Field(t, i).Assign(t, oa.Field(t, i));
+ }
+}
+
+func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
+ return v;
+}
+
+func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
+ return v.field(i);
+}
+
+func (v remoteStruct) field(i int) eval.Value {
+ f := &v.layout[i];
+ return f.fieldType.mk(v.r.plus(proc.Word(f.offset)));
+}
+
+func (v remoteStruct) addr() remote {
+ return v.r;
+}
+
+/*
+ * Pointer
+ */
+
+// TODO(austin) Comparing two remote pointers for equality in the
+// interpreter will crash it because the Value's returned from
+// remotePtr.Get() will be structs.
+
+type remotePtr struct {
+ r remote;
+ elemType *remoteType;
+}
+
+func (v remotePtr) String() string {
+ return tryRVString(func(a aborter) string {
+ e := v.aGet(a);
+ if e == nil {
+ return "<nil>";
+ }
+ return "&" + e.String();
+ });
+}
+
+func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.PtrValue).Get(t));
+}
+
+func (v remotePtr) Get(t *eval.Thread) eval.Value {
+ return v.aGet(t);
+}
+
+func (v remotePtr) aGet(a aborter) eval.Value {
+ addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()));
+ if addr == 0 {
+ return nil;
+ }
+ return v.elemType.mk(remote{addr, v.r.p});
+}
+
+func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
+ v.aSet(t, x);
+}
+
+func (v remotePtr) aSet(a aborter, x eval.Value) {
+ if x == nil {
+ v.r.Set(a, v.r.p.PtrSize(), 0);
+ return;
+ }
+ xr, ok := x.(remoteValue);
+ if !ok || v.r.p != xr.addr().p {
+ a.Abort(RemoteMismatchError("remote pointer must point within the same process"));
+ }
+ v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base));
+}
+
+func (v remotePtr) addr() remote {
+ return v.r;
+}
+
+/*
+ * Slice
+ */
+
+type remoteSlice struct {
+ r remote;
+ elemType *remoteType;
+}
+
+func (v remoteSlice) String() string {
+ return tryRVString(func(a aborter) string {
+ b := v.aGet(a).Base;
+ if b == nil {
+ return "<nil>";
+ }
+ return b.String();
+ });
+}
+
+func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.SliceValue).Get(t));
+}
+
+func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
+ return v.aGet(t);
+}
+
+func (v remoteSlice) aGet(a aborter) eval.Slice {
+ rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
+ base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a));
+ nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a);
+ cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a);
+ if base == 0 {
+ return eval.Slice{nil, nel, cap};
+ }
+ return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap};
+}
+
+func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
+ v.aSet(t, x);
+}
+
+func (v remoteSlice) aSet(a aborter, x eval.Slice) {
+ rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
+ if x.Base == nil {
+ rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0);
+ } else {
+ ar, ok := x.Base.(remoteArray);
+ if !ok || v.r.p != ar.r.p {
+ a.Abort(RemoteMismatchError("remote slice must point within the same process"));
+ }
+ rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base));
+ }
+ rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len);
+ rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap);
+}