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:
parent
a03764aa50
commit
dd7b583179
@ -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 {}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
|
@ -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) {
|
||||||
|
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user