1
0
mirror of https://github.com/golang/go synced 2024-11-22 05:54:40 -07:00

move abortChan into Thread.

reuse Thread in function calls.

R=austin
DELTA=59  (8 added, 7 deleted, 44 changed)
OCL=34266
CL=34266
This commit is contained in:
Russ Cox 2009-09-02 14:11:40 -07:00
parent a03764aa50
commit dd7b583179
7 changed files with 46 additions and 45 deletions

View File

@ -10,33 +10,29 @@ import (
"runtime"; "runtime";
) )
// TODO(austin) This is not thread-safe. We could include the abort // Abort aborts the thread's current computation,
// channel in the Frame structure, but then the Value methods need to // causing the innermost Try to return err.
// take the Frame. However, passing something to the Value methods func (t *Thread) Abort(err os.Error) {
// might be necessary to generate back traces. if t.abort == nil {
var abortChan = make(chan os.Error) panicln("abort:", err.String());
// 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());
} }
abortChan <- e; t.abort <- err;
runtime.Goexit(); runtime.Goexit();
} }
// Try executes a computation with the ability to Abort. // Try executes a computation; if the computation
func Try(f func()) os.Error { // Aborts, Try returns the error passed to abort.
abortChan = make(chan os.Error); func (t *Thread) Try(f func(t *Thread)) os.Error {
oc := t.abort;
c := make(chan os.Error);
t.abort = c;
go func() { go func() {
f(); f(t);
abortChan <- nil; c <- nil;
}(); }();
res := <-abortChan; err := <-c;
abortChan = nil; t.abort = oc;
return res; return err;
} }
type DivByZeroError struct {} type DivByZeroError struct {}

View File

@ -967,7 +967,7 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
expr.genValue(func(t *Thread) Value { expr.genValue(func(t *Thread) Value {
l, r := lf(t), rf(t); l, r := lf(t), rf(t);
if r < 0 || r >= bound { if r < 0 || r >= bound {
Abort(IndexError{r, bound}); t.Abort(IndexError{r, bound});
} }
return l.Elem(r); return l.Elem(r);
}); });
@ -978,10 +978,10 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
expr.genValue(func(t *Thread) Value { expr.genValue(func(t *Thread) Value {
l, r := lf(t), rf(t); l, r := lf(t), rf(t);
if l.Base == nil { if l.Base == nil {
Abort(NilPointerError{}); t.Abort(NilPointerError{});
} }
if r < 0 || r >= l.Len { if r < 0 || r >= l.Len {
Abort(IndexError{r, l.Len}); t.Abort(IndexError{r, l.Len});
} }
return l.Base.Elem(r); return l.Base.Elem(r);
}); });
@ -994,7 +994,7 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
expr.eval = func(t *Thread) uint64 { expr.eval = func(t *Thread) uint64 {
l, r := lf(t), rf(t); l, r := lf(t), rf(t);
if r < 0 || r >= int64(len(l)) { if r < 0 || r >= int64(len(l)) {
Abort(IndexError{r, int64(len(l))}); t.Abort(IndexError{r, int64(len(l))});
} }
return uint64(l[r]); return uint64(l[r]);
} }
@ -1006,11 +1006,11 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
m := lf(t); m := lf(t);
k := rf(t); k := rf(t);
if m == nil { if m == nil {
Abort(NilPointerError{}); t.Abort(NilPointerError{});
} }
e := m.Elem(k); e := m.Elem(k);
if e == nil { if e == nil {
Abort(KeyError{k}); t.Abort(KeyError{k});
} }
return e; return e;
}); });
@ -1228,13 +1228,13 @@ func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *e
// XXX(Spec) What if len or cap is // XXX(Spec) What if len or cap is
// negative? The runtime panics. // negative? The runtime panics.
if l < 0 { if l < 0 {
Abort(NegativeLengthError{l}); t.Abort(NegativeLengthError{l});
} }
c := l; c := l;
if capf != nil { if capf != nil {
c = capf(t); c = capf(t);
if c < 0 { if c < 0 {
Abort(NegativeCapacityError{c}); t.Abort(NegativeCapacityError{c});
} }
// XXX(Spec) What happens if // XXX(Spec) What happens if
// len > cap? The runtime // len > cap? The runtime
@ -1293,7 +1293,7 @@ func (a *exprInfo) compileStarExpr(v *expr) *expr {
expr.genValue(func(t *Thread) Value { expr.genValue(func(t *Thread) Value {
v := vf(t); v := vf(t);
if v == nil { if v == nil {
Abort(NilPointerError{}); t.Abort(NilPointerError{});
} }
return v; return v;
}); });
@ -1863,7 +1863,7 @@ func (expr *Expr) Eval(f *Frame) (Value, os.Error) {
} }
v := expr.e.t.Zero(); v := expr.e.t.Zero();
eval := genAssign(expr.e.t, expr.e); 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; return v, err;
} }

View File

@ -379,11 +379,11 @@ func (a *expr) genBinOpQuo(l, r *expr) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
rf := r.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: case *intType:
lf := l.asInt(); lf := l.asInt();
rf := r.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: case *idealIntType:
l := l.asIdealInt()(); l := l.asIdealInt()();
r := r.asIdealInt()(); r := r.asIdealInt()();
@ -392,7 +392,7 @@ func (a *expr) genBinOpQuo(l, r *expr) {
case *floatType: case *floatType:
lf := l.asFloat(); lf := l.asFloat();
rf := r.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: case *idealFloatType:
l := l.asIdealFloat()(); l := l.asIdealFloat()();
r := r.asIdealFloat()(); r := r.asIdealFloat()();
@ -408,11 +408,11 @@ func (a *expr) genBinOpRem(l, r *expr) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
rf := r.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: case *intType:
lf := l.asInt(); lf := l.asInt();
rf := r.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: case *idealIntType:
l := l.asIdealInt()(); l := l.asIdealInt()();
r := r.asIdealInt()(); r := r.asIdealInt()();

View File

@ -4,11 +4,14 @@
package eval package eval
import "os"
/* /*
* Virtual machine * Virtual machine
*/ */
type Thread struct { type Thread struct {
abort chan os.Error;
pc uint; pc uint;
// The execution frame of this function. This remains the // The execution frame of this function. This remains the
// same throughout a function invocation. // same throughout a function invocation.
@ -18,13 +21,15 @@ type Thread struct {
type code []func(*Thread) type code []func(*Thread)
func (i code) exec(t *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)); l := uint(len(i));
for v.pc < l { for t.pc < l {
pc := v.pc; pc := t.pc;
v.pc++; t.pc++;
i[pc](&v); i[pc](t);
} }
t.pc = opc;
} }
/* /*

View File

@ -91,12 +91,12 @@ var binOps = []Op{
Op{ Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(r)", Types: numbers }, 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: "Mul", Expr: "l * r", ConstExpr: "l.Mul(r)", Types: numbers },
Op{ Name: "Quo", 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)", ConstExpr: "l.Quo(r)",
Types: numbers, Types: numbers,
}, },
Op{ Name: "Rem", 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)", ConstExpr: "l.Rem(r)",
Types: integers, Types: integers,
}, },

View File

@ -1281,7 +1281,7 @@ type Stmt struct {
func (s *Stmt) Exec(f *Frame) os.Error { func (s *Stmt) Exec(f *Frame) os.Error {
t := new(Thread); t := new(Thread);
t.f = f; 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) { func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {

View File

@ -302,7 +302,7 @@ var stmtTests = []test {
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 { 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"), 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 // Make slice
Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0), Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),