diff options
author | Austin Clements <aclements@csail.mit.edu> | 2009-07-29 11:57:46 -0700 |
---|---|---|
committer | Austin Clements <aclements@csail.mit.edu> | 2009-07-29 11:57:46 -0700 |
commit | 6a1530c6ecdc3610889367b75ca275d84604b1c5 (patch) | |
tree | eea7019f7e07a3a6e3f801510489ef285050a586 /usr/austin/eval/expr.go | |
parent | 261d6437b8a7a1e7c85f9c83dd4a72446a9234a5 (diff) | |
download | golang-6a1530c6ecdc3610889367b75ca275d84604b1c5.tar.gz |
Flatten the Frame tree. Now each function call produces a
single frame and non-overlapping variables reuse frame slots.
As a result, entering and exiting blocks no longer requires
code execution, which means jumps across block boundaries
should be doable now. Frame slot initialization happens at
definition time now, instead of at frame creation time. As an
added bonus, Scope's are now exclusively compile-time objects
and we no longer need to specially track the function
activation frame for access to out vars.
R=rsc
APPROVED=rsc
DELTA=313 (102 added, 90 deleted, 121 changed)
OCL=32416
CL=32420
Diffstat (limited to 'usr/austin/eval/expr.go')
-rw-r--r-- | usr/austin/eval/expr.go | 68 |
1 files changed, 40 insertions, 28 deletions
diff --git a/usr/austin/eval/expr.go b/usr/austin/eval/expr.go index 7aebedb48..fbd4b5ac4 100644 --- a/usr/austin/eval/expr.go +++ b/usr/austin/eval/expr.go @@ -61,7 +61,7 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler { // Operator generators // TODO(austin) Remove these forward declarations func (a *exprCompiler) genConstant(v Value) -func (a *exprCompiler) genIdentOp(s *Scope, index int) +func (a *exprCompiler) genIdentOp(level int, index int) func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) func (a *exprCompiler) genStarOp(v *exprCompiler) @@ -470,7 +470,7 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) { } func (a *exprCompiler) DoIdent(x *ast.Ident) { - def, dscope := a.scope.Lookup(x.Value); + level, def := a.block.Lookup(x.Value); if def == nil { a.diag("%s: undefined", x.Value); return; @@ -491,7 +491,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) { } a.t = def.Type; defidx := def.Index; - a.genIdentOp(dscope, defidx); + a.genIdentOp(level, defidx); a.desc = "variable"; case Type: a.diag("type %v used as expression", x.Value); @@ -566,14 +566,14 @@ func (a *exprCompiler) DoFuncLit(x *ast.FuncLit) { // TODO(austin) Closures capture their entire defining frame // instead of just the variables they use. - decl := a.compileFuncType(a.scope, x.Type); + decl := a.compileFuncType(a.block, x.Type); if decl == nil { // TODO(austin) Try compiling the body, perhaps with // dummy definitions for the arguments return; } - evalFunc := a.compileFunc(a.scope, decl, x.Body); + evalFunc := a.compileFunc(a.block, decl, x.Body); if evalFunc == nil { return; } @@ -728,13 +728,11 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { bad = true; } as := make([]*exprCompiler, len(x.Args)); - ats := make([]Type, len(as)); for i := 0; i < len(x.Args); i++ { as[i] = a.copyVisit(x.Args[i]); if as[i].t == nil { bad = true; } - ats[i] = as[i].t; } if bad { return; @@ -763,6 +761,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { // // XXX(Spec) The spec is wrong. It can also be a single // multi-valued expression. + nin := len(lt.In); assign := a.compileAssign(x.Pos(), NewMultiType(lt.In), as, "function call", "argument"); if assign == nil { return; @@ -778,12 +777,23 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { a.t = NewMultiType(lt.Out); } + // Gather argument and out types to initialize frame variables + vts := make([]Type, nin + nout); + for i, t := range lt.In { + vts[i] = t; + } + for i, t := range lt.Out { + vts[i+nin] = t; + } + // Compile lf := l.asFunc(); - nin := len(lt.In); call := func(f *Frame) []Value { fun := lf(f); fr := fun.NewFrame(); + for i, t := range vts { + fr.Vars[i] = t.Zero(); + } assign(multiV(fr.Vars[0:nin]), f); fun.Call(fr); return fr.Vars[nin:nin+nout]; @@ -1275,8 +1285,8 @@ func (a *exprCompiler) DoChanType(x *ast.ChanType) { // TODO(austin) This is a hack to eliminate a circular dependency // between type.go and expr.go -func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) { - lenExpr := a.compileExpr(scope, expr, true); +func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { + lenExpr := a.compileExpr(b, expr, true); if lenExpr == nil { return 0, false; } @@ -1302,8 +1312,8 @@ func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) { return 0, false; } -func (a *compiler) compileExpr(scope *Scope, expr ast.Expr, constant bool) *exprCompiler { - ec := newExprCompiler(&exprContext{a, scope, constant}, expr.Pos()); +func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler { + ec := newExprCompiler(&exprContext{a, b, constant}, expr.Pos()); expr.Visit(ec); if ec.t == nil { return nil; @@ -1325,10 +1335,11 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) { } // Create temporary - tempScope := a.scope; + tempBlock := a.block; tempType := NewPtrType(a.t); - // TODO(austin) These temporaries accumulate in the scope. - temp := tempScope.DefineTemp(tempType); + // TODO(austin) These temporaries accumulate in the scope. We + // could enter a temporary block, but the caller has to exit it. + temp := tempBlock.DefineTemp(tempType); tempIdx := temp.Index; // Generate "temp := &e" @@ -1342,14 +1353,15 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) { } effect := func(f *Frame) { - tempVal := f.Get(tempScope, tempIdx); + tempVal := tempType.Zero(); + f.Vars[tempIdx] = tempVal; assign(tempVal, f); }; // Generate "*temp" getTemp := a.copy(); getTemp.t = tempType; - getTemp.genIdentOp(tempScope, tempIdx); + getTemp.genIdentOp(0, tempIdx); deref := a.copy(); deref.t = a.t; @@ -1377,7 +1389,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) { errors := scanner.NewErrorVector(); cc := &compiler{errors}; - ec := cc.compileExpr(scope, expr, false); + ec := cc.compileExpr(scope.block, expr, false); if ec == nil { return nil, errors.GetError(scanner.Sorted); } @@ -1447,25 +1459,25 @@ func (a *exprCompiler) genConstant(v Value) { } } -func (a *exprCompiler) genIdentOp(s *Scope, index int) { - a.evalAddr = func(f *Frame) Value { return f.Get(s, index) }; +func (a *exprCompiler) genIdentOp(level int, index int) { + a.evalAddr = func(f *Frame) Value { return f.Get(level, index) }; switch _ := a.t.rep().(type) { case *boolType: - a.evalBool = func(f *Frame) bool { return f.Get(s, index).(BoolValue).Get() }; + a.evalBool = func(f *Frame) bool { return f.Get(level, index).(BoolValue).Get() }; case *uintType: - a.evalUint = func(f *Frame) uint64 { return f.Get(s, index).(UintValue).Get() }; + a.evalUint = func(f *Frame) uint64 { return f.Get(level, index).(UintValue).Get() }; case *intType: - a.evalInt = func(f *Frame) int64 { return f.Get(s, index).(IntValue).Get() }; + a.evalInt = func(f *Frame) int64 { return f.Get(level, index).(IntValue).Get() }; case *floatType: - a.evalFloat = func(f *Frame) float64 { return f.Get(s, index).(FloatValue).Get() }; + a.evalFloat = func(f *Frame) float64 { return f.Get(level, index).(FloatValue).Get() }; case *stringType: - a.evalString = func(f *Frame) string { return f.Get(s, index).(StringValue).Get() }; + a.evalString = func(f *Frame) string { return f.Get(level, index).(StringValue).Get() }; case *ArrayType: - a.evalArray = func(f *Frame) ArrayValue { return f.Get(s, index).(ArrayValue).Get() }; + a.evalArray = func(f *Frame) ArrayValue { return f.Get(level, index).(ArrayValue).Get() }; case *PtrType: - a.evalPtr = func(f *Frame) Value { return f.Get(s, index).(PtrValue).Get() }; + a.evalPtr = func(f *Frame) Value { return f.Get(level, index).(PtrValue).Get() }; case *FuncType: - a.evalFunc = func(f *Frame) Func { return f.Get(s, index).(FuncValue).Get() }; + a.evalFunc = func(f *Frame) Func { return f.Get(level, index).(FuncValue).Get() }; default: log.Crashf("unexpected identifier type %v at %v", a.t, a.pos); } |