reuse Thread in function calls.
R=austin
DELTA=59 (8 added, 7 deleted, 44 changed)
OCL=34266
CL=34266
"runtime";
)
-// TODO(austin) This is not thread-safe. We could include the abort
-// channel in the Frame structure, but then the Value methods need to
-// take the Frame. However, passing something to the Value methods
-// might be necessary to generate back traces.
-var abortChan = make(chan os.Error)
-
-// Abort aborts the current computation. If this is called within the
-// extent of a Try call, this immediately returns to the Try with the
-// given error. If not, then this panic's.
-func Abort(e os.Error) {
- if abortChan == nil {
- panic("Abort: " + e.String());
+// Abort aborts the thread's current computation,
+// causing the innermost Try to return err.
+func (t *Thread) Abort(err os.Error) {
+ if t.abort == nil {
+ panicln("abort:", err.String());
}
- abortChan <- e;
+ t.abort <- err;
runtime.Goexit();
}
-// Try executes a computation with the ability to Abort.
-func Try(f func()) os.Error {
- abortChan = make(chan os.Error);
+// Try executes a computation; if the computation
+// Aborts, Try returns the error passed to abort.
+func (t *Thread) Try(f func(t *Thread)) os.Error {
+ oc := t.abort;
+ c := make(chan os.Error);
+ t.abort = c;
go func() {
- f();
- abortChan <- nil;
+ f(t);
+ c <- nil;
}();
- res := <-abortChan;
- abortChan = nil;
- return res;
+ err := <-c;
+ t.abort = oc;
+ return err;
}
type DivByZeroError struct {}
expr.genValue(func(t *Thread) Value {
l, r := lf(t), rf(t);
if r < 0 || r >= bound {
- Abort(IndexError{r, bound});
+ t.Abort(IndexError{r, bound});
}
return l.Elem(r);
});
expr.genValue(func(t *Thread) Value {
l, r := lf(t), rf(t);
if l.Base == nil {
- Abort(NilPointerError{});
+ t.Abort(NilPointerError{});
}
if r < 0 || r >= l.Len {
- Abort(IndexError{r, l.Len});
+ t.Abort(IndexError{r, l.Len});
}
return l.Base.Elem(r);
});
expr.eval = func(t *Thread) uint64 {
l, r := lf(t), rf(t);
if r < 0 || r >= int64(len(l)) {
- Abort(IndexError{r, int64(len(l))});
+ t.Abort(IndexError{r, int64(len(l))});
}
return uint64(l[r]);
}
m := lf(t);
k := rf(t);
if m == nil {
- Abort(NilPointerError{});
+ t.Abort(NilPointerError{});
}
e := m.Elem(k);
if e == nil {
- Abort(KeyError{k});
+ t.Abort(KeyError{k});
}
return e;
});
// XXX(Spec) What if len or cap is
// negative? The runtime panics.
if l < 0 {
- Abort(NegativeLengthError{l});
+ t.Abort(NegativeLengthError{l});
}
c := l;
if capf != nil {
c = capf(t);
if c < 0 {
- Abort(NegativeCapacityError{c});
+ t.Abort(NegativeCapacityError{c});
}
// XXX(Spec) What happens if
// len > cap? The runtime
expr.genValue(func(t *Thread) Value {
v := vf(t);
if v == nil {
- Abort(NilPointerError{});
+ t.Abort(NilPointerError{});
}
return v;
});
}
v := expr.e.t.Zero();
eval := genAssign(expr.e.t, expr.e);
- err := Try(func() {eval(v, t)});
+ err := t.Try(func(t *Thread){eval(v, t)});
return v, err;
}
case *uintType:
lf := l.asUint();
rf := r.asUint();
- a.eval = func(t *Thread) uint64 { l, r := lf(t), rf(t); if r == 0 { Abort(DivByZeroError{}) } return l / r }
+ a.eval = func(t *Thread) uint64 { l, r := lf(t), rf(t); if r == 0 { t.Abort(DivByZeroError{}) } return l / r }
case *intType:
lf := l.asInt();
rf := r.asInt();
- a.eval = func(t *Thread) int64 { l, r := lf(t), rf(t); if r == 0 { Abort(DivByZeroError{}) } return l / r }
+ a.eval = func(t *Thread) int64 { l, r := lf(t), rf(t); if r == 0 { t.Abort(DivByZeroError{}) } return l / r }
case *idealIntType:
l := l.asIdealInt()();
r := r.asIdealInt()();
case *floatType:
lf := l.asFloat();
rf := r.asFloat();
- a.eval = func(t *Thread) float64 { l, r := lf(t), rf(t); if r == 0 { Abort(DivByZeroError{}) } return l / r }
+ a.eval = func(t *Thread) float64 { l, r := lf(t), rf(t); if r == 0 { t.Abort(DivByZeroError{}) } return l / r }
case *idealFloatType:
l := l.asIdealFloat()();
r := r.asIdealFloat()();
case *uintType:
lf := l.asUint();
rf := r.asUint();
- a.eval = func(t *Thread) uint64 { l, r := lf(t), rf(t); if r == 0 { Abort(DivByZeroError{}) } return l % r }
+ a.eval = func(t *Thread) uint64 { l, r := lf(t), rf(t); if r == 0 { t.Abort(DivByZeroError{}) } return l % r }
case *intType:
lf := l.asInt();
rf := r.asInt();
- a.eval = func(t *Thread) int64 { l, r := lf(t), rf(t); if r == 0 { Abort(DivByZeroError{}) } return l % r }
+ a.eval = func(t *Thread) int64 { l, r := lf(t), rf(t); if r == 0 { t.Abort(DivByZeroError{}) } return l % r }
case *idealIntType:
l := l.asIdealInt()();
r := r.asIdealInt()();
package eval
+import "os"
+
/*
* Virtual machine
*/
type Thread struct {
+ abort chan os.Error;
pc uint;
// The execution frame of this function. This remains the
// same throughout a function invocation.
type code []func(*Thread)
func (i code) exec(t *Thread) {
- v := Thread{0, t.f}; // TODO: reuse t
+ opc := t.pc;
+ t.pc = 0;
l := uint(len(i));
- for v.pc < l {
- pc := v.pc;
- v.pc++;
- i[pc](&v);
+ for t.pc < l {
+ pc := t.pc;
+ t.pc++;
+ i[pc](t);
}
+ t.pc = opc;
}
/*
Op{ Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(r)", Types: numbers },
Op{ Name: "Mul", Expr: "l * r", ConstExpr: "l.Mul(r)", Types: numbers },
Op{ Name: "Quo",
- Body: "if r == 0 { Abort(DivByZeroError{}) } return l / r",
+ Body: "if r == 0 { t.Abort(DivByZeroError{}) } return l / r",
ConstExpr: "l.Quo(r)",
Types: numbers,
},
Op{ Name: "Rem",
- Body: "if r == 0 { Abort(DivByZeroError{}) } return l % r",
+ Body: "if r == 0 { t.Abort(DivByZeroError{}) } return l % r",
ConstExpr: "l.Rem(r)",
Types: integers,
},
func (s *Stmt) Exec(f *Frame) os.Error {
t := new(Thread);
t.f = f;
- return Try(func() {s.code.exec(t)});
+ return t.Try(func(t *Thread){s.code.exec(t)});
}
func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
SErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"),
SErr("type T struct { *T }; var x T; x.foo", "no field"),
- //Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 } return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 0),
+ Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 } return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946),
// Make slice
Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),