1
0
mirror of https://github.com/golang/go synced 2024-11-22 00:24:41 -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";
)
// 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 {}

View File

@ -967,7 +967,7 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
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);
});
@ -978,10 +978,10 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
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);
});
@ -994,7 +994,7 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
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]);
}
@ -1006,11 +1006,11 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
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;
});
@ -1228,13 +1228,13 @@ func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *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
@ -1293,7 +1293,7 @@ func (a *exprInfo) compileStarExpr(v *expr) *expr {
expr.genValue(func(t *Thread) Value {
v := vf(t);
if v == nil {
Abort(NilPointerError{});
t.Abort(NilPointerError{});
}
return v;
});
@ -1863,7 +1863,7 @@ func (expr *Expr) Eval(f *Frame) (Value, os.Error) {
}
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;
}

View File

@ -379,11 +379,11 @@ func (a *expr) genBinOpQuo(l, r *expr) {
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()();
@ -392,7 +392,7 @@ func (a *expr) genBinOpQuo(l, r *expr) {
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()();
@ -408,11 +408,11 @@ func (a *expr) genBinOpRem(l, r *expr) {
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()();

View File

@ -4,11 +4,14 @@
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.
@ -18,13 +21,15 @@ type Thread struct {
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;
}
/*

View File

@ -91,12 +91,12 @@ var binOps = []Op{
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,
},

View File

@ -1281,7 +1281,7 @@ type Stmt struct {
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) {

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 { *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),