summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Clements <aclements@csail.mit.edu>2009-07-29 11:57:46 -0700
committerAustin Clements <aclements@csail.mit.edu>2009-07-29 11:57:46 -0700
commit6a1530c6ecdc3610889367b75ca275d84604b1c5 (patch)
treeeea7019f7e07a3a6e3f801510489ef285050a586
parent261d6437b8a7a1e7c85f9c83dd4a72446a9234a5 (diff)
downloadgolang-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
-rw-r--r--usr/austin/eval/compiler.go17
-rw-r--r--usr/austin/eval/decls.go63
-rw-r--r--usr/austin/eval/expr.go68
-rw-r--r--usr/austin/eval/func.go16
-rw-r--r--usr/austin/eval/scope.go161
-rw-r--r--usr/austin/eval/stmt.go83
-rw-r--r--usr/austin/eval/type.go2
-rw-r--r--usr/austin/eval/typec.go14
8 files changed, 218 insertions, 206 deletions
diff --git a/usr/austin/eval/compiler.go b/usr/austin/eval/compiler.go
index 6dd6437e1..641e6a293 100644
--- a/usr/austin/eval/compiler.go
+++ b/usr/austin/eval/compiler.go
@@ -32,16 +32,16 @@ func (a *compiler) diagAt(pos positioned, format string, args ...) {
}
type FuncDecl struct
-func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func)
+func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func)
type exprCompiler struct
-func (a *compiler) compileExpr(scope *Scope, expr ast.Expr, constant bool) *exprCompiler
+func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler
type assignCompiler struct
func (a *compiler) checkAssign(pos token.Position, rs []*exprCompiler, errOp, errPosName string) (*assignCompiler, bool)
func (a *compiler) compileAssign(pos token.Position, lt Type, rs []*exprCompiler, errOp, errPosName string) (func(lv Value, f *Frame))
-func (a *compiler) compileType(scope *Scope, typ ast.Expr) Type
-func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl
+func (a *compiler) compileType(b *block, typ ast.Expr) Type
+func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl
-func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool)
+func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool)
type codeBuf struct
@@ -63,7 +63,7 @@ type funcCompiler struct {
// of a single block within a function.
type blockCompiler struct {
*funcCompiler;
- scope *Scope;
+ block *block;
returned bool;
// The PC break statements should jump to, or nil if a break
// statement is invalid.
@@ -74,9 +74,6 @@ type blockCompiler struct {
// The blockCompiler for the block enclosing this one, or nil
// for a function-level block.
parent *blockCompiler;
- // The blockCompiler for the nested block currently being
- // compiled, or nil if compilation is not in a nested block.
- child *blockCompiler;
}
func (a *blockCompiler) compileStmt(s ast.Stmt)
@@ -92,6 +89,6 @@ func (a *blockCompiler) exit()
// this to exprCompiler.
type exprContext struct {
*compiler;
- scope *Scope;
+ block *block;
constant bool;
}
diff --git a/usr/austin/eval/decls.go b/usr/austin/eval/decls.go
index 08dc1c148..2f71f11f3 100644
--- a/usr/austin/eval/decls.go
+++ b/usr/austin/eval/decls.go
@@ -140,23 +140,59 @@ type Constant struct {
// A definition can be a *Variable, *Constant, or Type.
type Def interface {}
-type Scope struct {
- outer *Scope;
+type Scope struct
+
+// A block represents a definition block in which a name may not be
+// defined more than once.
+type block struct {
+ // The block enclosing this one, including blocks in other
+ // scopes.
+ outer *block;
+ // The nested block currently being compiled, or nil.
+ inner *block;
+ // The Scope containing this block.
+ scope *Scope;
+ // The Variables, Constants, and Types defined in this block.
defs map[string] Def;
- temps map[int] *Variable;
+ // The index of the first variable defined in this block.
+ // This must be greater than the index of any variable defined
+ // in any parent of this block within the same Scope at the
+ // time this block is entered.
+ offset int;
+ // The number of Variables defined in this block.
numVars int;
- varTypes []Type;
}
-func (s *Scope) Fork() *Scope
-func (s *Scope) DefineVar(name string, t Type) *Variable
-func (s *Scope) DefineTemp(t Type) *Variable
-func (s *Scope) DefineConst(name string, t Type, v Value) *Constant
-func (s *Scope) DefineType(name string, t Type) Type
-func (s *Scope) Lookup(name string) (Def, *Scope)
+// A Scope is the compile-time analogue of a Frame, which captures
+// some subtree of blocks.
+type Scope struct {
+ // The root block of this scope.
+ *block;
+ // The maximum number of variables required at any point in
+ // this Scope. This determines the number of slots needed in
+ // Frame's created from this Scope at run-time.
+ maxVars int;
+}
+
+func (b *block) enterChild() *block
+func (b *block) exit()
+func (b *block) ChildScope() *Scope
+func (b *block) DefineVar(name string, t Type) *Variable
+func (b *block) DefineTemp(t Type) *Variable
+func (b *block) DefineConst(name string, t Type, v Value) *Constant
+func (b *block) DefineType(name string, t Type) Type
+func (b *block) Lookup(name string) (level int, def Def)
// The universal scope
-var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variable)};
+func newUniverse() *Scope {
+ sc := &Scope{nil, 0};
+ sc.block = &block{
+ scope: sc,
+ defs: make(map[string] Def)
+ };
+ return sc;
+}
+var universe *Scope = newUniverse();
/*
* Frames
@@ -164,12 +200,11 @@ var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variabl
type Frame struct {
Outer *Frame;
- Scope *Scope;
Vars []Value;
}
-func (f *Frame) Get(s *Scope, index int) Value
-func (f *Frame) String() string
+func (f *Frame) Get(level int, index int) Value
+func (f *Frame) child(numVars int) *Frame
func (s *Scope) NewFrame(outer *Frame) *Frame
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);
}
diff --git a/usr/austin/eval/func.go b/usr/austin/eval/func.go
index cc790452b..3fc5e71af 100644
--- a/usr/austin/eval/func.go
+++ b/usr/austin/eval/func.go
@@ -15,19 +15,15 @@ import (
type vm struct {
pc uint;
- // The current execution frame. If execution is within a
- // block, this may be a child of the original function
- // activation frame.
+ // The execution frame of this function. This remains the
+ // same throughout a function invocation.
f *Frame;
- // The original function activation frame. This is used to
- // access function out args.
- activation *Frame;
}
type code []func(*vm)
func (i code) exec(fr *Frame) {
- v := vm{0, fr, fr};
+ v := vm{0, fr};
l := uint(len(i));
for v.pc < l {
@@ -80,13 +76,13 @@ func (b *codeBuf) get() code {
*/
type evalFunc struct {
- sc *Scope;
- fr *Frame;
+ outer *Frame;
+ frameSize int;
code code;
}
func (f *evalFunc) NewFrame() *Frame {
- return f.sc.NewFrame(f.fr);
+ return f.outer.child(f.frameSize);
}
func (f *evalFunc) Call(fr *Frame) {
diff --git a/usr/austin/eval/scope.go b/usr/austin/eval/scope.go
index 8c9177b41..6d89d00d7 100644
--- a/usr/austin/eval/scope.go
+++ b/usr/austin/eval/scope.go
@@ -7,130 +7,117 @@ package eval
import (
"eval";
"fmt";
+ "log";
)
-func (s *Scope) Fork() *Scope {
- return &Scope{
- outer: s,
+func (b *block) enterChild() *block {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before entering another child");
+ }
+ sub := &block{
+ outer: b,
+ scope: b.scope,
defs: make(map[string] Def),
- temps: make(map[int] *Variable)
+ offset: b.offset+b.numVars,
};
+ b.inner = sub;
+ return sub;
+}
+
+func (b *block) exit() {
+ if b.outer == nil {
+ log.Crash("Cannot exit top-level block");
+ }
+ if b.outer.inner != b {
+ log.Crash("Already exited block");
+ }
+ if b.inner != nil {
+ log.Crash("Exit of parent block without exit of child block");
+ }
+ b.outer.inner = nil;
}
-func (s *Scope) DefineVar(name string, t Type) *Variable {
- if _, ok := s.defs[name]; ok {
+func (b *block) ChildScope() *Scope {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before entering a child scope");
+ }
+ sub := b.enterChild();
+ sub.offset = 0;
+ sub.scope = &Scope{sub, 0};
+ return sub.scope;
+}
+
+func (b *block) DefineVar(name string, t Type) *Variable {
+ if _, ok := b.defs[name]; ok {
return nil;
}
- v := &Variable{s.numVars, t};
- s.defs[name] = v;
- s.numVars++;
+ v := b.DefineTemp(t);
+ if v != nil {
+ b.defs[name] = v;
+ }
return v;
}
-func (s *Scope) DefineTemp(t Type) *Variable {
- v := &Variable{s.numVars, t};
- s.temps[s.numVars] = v;
- s.numVars++;
+func (b *block) DefineTemp(t Type) *Variable {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before defining variable");
+ }
+ index := b.offset+b.numVars;
+ v := &Variable{index, t};
+ b.numVars++;
+ if index+1 > b.scope.maxVars {
+ b.scope.maxVars = index+1;
+ }
return v;
}
-func (s *Scope) DefineConst(name string, t Type, v Value) *Constant {
- if _, ok := s.defs[name]; ok {
+func (b *block) DefineConst(name string, t Type, v Value) *Constant {
+ if _, ok := b.defs[name]; ok {
return nil;
}
c := &Constant{t, v};
- s.defs[name] = c;
+ b.defs[name] = c;
return c;
}
-func (s *Scope) DefineType(name string, t Type) Type {
- if _, ok := s.defs[name]; ok {
+func (b *block) DefineType(name string, t Type) Type {
+ if _, ok := b.defs[name]; ok {
return nil;
}
// We take the representative type of t because multiple
// levels of naming are useless.
- nt := &NamedType{s, name, t.rep()};
- s.defs[name] = nt;
+ nt := &NamedType{name, t.rep()};
+ b.defs[name] = nt;
return nt;
}
-func (s *Scope) Lookup(name string) (Def, *Scope) {
- for s != nil {
- if d, ok := s.defs[name]; ok {
- return d, s;
+func (b *block) Lookup(name string) (level int, def Def) {
+ for b != nil {
+ if d, ok := b.defs[name]; ok {
+ return level, d;
}
- s = s.outer;
+ if b.outer != nil && b.scope != b.outer.scope {
+ level++;
+ }
+ b = b.outer;
}
- return nil, nil;
+ return 0, nil;
}
func (s *Scope) NewFrame(outer *Frame) *Frame {
- if s.varTypes == nil {
- // First creation of a frame from this scope. Compute
- // and memoize the types of all variables.
- ts := make([]Type, s.numVars);
- for _, d := range s.defs {
- if v, ok := d.(*Variable); ok {
- // Record the representative type to
- // avoid indirecting through named
- // types every time we drop a frame.
- ts[v.Index] = v.Type.rep();
- }
- }
- for _, v := range s.temps {
- ts[v.Index] = v.Type.rep();
- }
- s.varTypes = ts;
- }
-
- // Create frame
- //
- // TODO(austin) This is probably rather expensive. All values
- // require heap allocation and the Zero method typically
- // requires some computation.
- vars := make([]Value, s.numVars);
- for i, t := range s.varTypes {
- vars[i] = t.Zero();
- }
- return &Frame{outer, s, vars};
+ return outer.child(s.maxVars);
}
-func (f *Frame) Get(s *Scope, index int) Value {
- for f.Scope != s {
+func (f *Frame) Get(level int, index int) Value {
+ for ; level > 0; level-- {
f = f.Outer;
}
return f.Vars[index];
}
-func stringFrame(f *Frame) (string, string) {
- res := "";
- indent := "";
- if f.Outer != nil {
- res, indent = stringFrame(f.Outer);
- }
-
- names := make([]string, f.Scope.numVars);
- types := make([]Type, f.Scope.numVars);
- for name, def := range f.Scope.defs {
- def, ok := def.(*Variable);
- if !ok {
- continue;
- }
- names[def.Index] = name;
- types[def.Index] = def.Type;
- }
- for _, def := range f.Scope.temps {
- names[def.Index] = "(temp)";
- types[def.Index] = def.Type;
- }
-
- for i, val := range f.Vars {
- res += fmt.Sprintf("%s%-10s %-10s %s\n", indent, names[i], types[i], val);
- }
- return res, indent + " ";
-}
-
-func (f *Frame) String() string {
- res, _ := stringFrame(f);
- return res;
+func (f *Frame) child(numVars int) *Frame {
+ // TODO(austin) This is probably rather expensive. All values
+ // require heap allocation and zeroing them when we execute a
+ // definition typically requires some computation.
+ return &Frame{f, make([]Value, numVars)};
}
diff --git a/usr/austin/eval/stmt.go b/usr/austin/eval/stmt.go
index f769d29a2..65d97ac3e 100644
--- a/usr/austin/eval/stmt.go
+++ b/usr/austin/eval/stmt.go
@@ -55,7 +55,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
}
func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
- e := a.compileExpr(a.scope, s.X, false);
+ e := a.compileExpr(a.block, s.X, false);
if e == nil {
return;
}
@@ -73,7 +73,7 @@ func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
}
func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
- l := a.compileExpr(a.scope, s.X, false);
+ l := a.compileExpr(a.block, s.X, false);
if l == nil {
return;
}
@@ -132,7 +132,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// made on the left side.
rs := make([]*exprCompiler, len(s.Rhs));
for i, re := range s.Rhs {
- rs[i] = a.compileExpr(a.scope, re, false);
+ rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil {
bad = true;
continue;
@@ -172,7 +172,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
}
// Is this simply an assignment?
- if _, ok := a.scope.defs[ident.Value]; ok {
+ if _, ok := a.block.defs[ident.Value]; ok {
goto assignment;
}
nDefs++;
@@ -213,14 +213,19 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
}
// Define identifier
- v := a.scope.DefineVar(ident.Value, lt);
+ v := a.block.DefineVar(ident.Value, lt);
if v == nil {
log.Crashf("Failed to define %s", ident.Value);
}
+ // Initialize the variable
+ index := v.Index;
+ a.push(func(v *vm) {
+ v.f.Vars[index] = lt.Zero();
+ });
}
assignment:
- ls[i] = a.compileExpr(a.scope, le, false);
+ ls[i] = a.compileExpr(a.block, le, false);
if ls[i] == nil {
bad = true;
continue;
@@ -325,8 +330,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
return;
}
- l := a.compileExpr(a.scope, s.Lhs[0], false);
- r := a.compileExpr(a.scope, s.Rhs[0], false);
+ l := a.compileExpr(a.block, s.Lhs[0], false);
+ r := a.compileExpr(a.block, s.Rhs[0], false);
if l == nil || r == nil {
return;
}
@@ -397,7 +402,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
bad := false;
rs := make([]*exprCompiler, len(s.Results));
for i, re := range s.Results {
- rs[i] = a.compileExpr(a.scope, re, false);
+ rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil {
bad = true;
}
@@ -425,7 +430,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
start := len(a.fnType.In);
nout := len(a.fnType.Out);
a.push(func(v *vm) {
- assign(multiV(v.activation.Vars[start:start+nout]), v.f);
+ assign(multiV(v.f.Vars[start:start+nout]), v.f);
v.pc = ^uint(0);
});
a.err = false;
@@ -496,8 +501,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// says when there's a non-block else clause, because that
// else claus has to execute in a scope that is *not* the
// surrounding scope.
- bc := a.blockCompiler;
- bc = bc.enterChild();
+ bc := a.enterChild();
defer bc.exit();
// Compile init statement, if any
@@ -511,7 +515,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// fall through to the body.
bad := false;
if s.Cond != nil {
- e := bc.compileExpr(bc.scope, s.Cond, false);
+ e := bc.compileExpr(bc.block, s.Cond, false);
switch {
case e == nil:
bad = true;
@@ -580,11 +584,12 @@ func (a *stmtCompiler) DoSelectStmt(s *ast.SelectStmt) {
}
func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
+ // Wrap the entire for in a block.
+ bc := a.enterChild();
+ defer bc.exit();
+
// Compile init statement, if any
- bc := a.blockCompiler;
if s.Init != nil {
- bc = bc.enterChild();
- defer bc.exit();
bc.compileStmt(s.Init);
}
@@ -617,7 +622,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
// If the condition is absent, it is equivalent to true.
a.push(func(v *vm) { v.pc = bodyPC });
} else {
- e := bc.compileExpr(bc.scope, s.Cond, false);
+ e := bc.compileExpr(bc.block, s.Cond, false);
switch {
case e == nil:
bad = true;
@@ -650,12 +655,12 @@ func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) {
*/
func (a *blockCompiler) compileStmt(s ast.Stmt) {
- if a.child != nil {
+ if a.block.inner != nil {
log.Crash("Child scope still entered");
}
sc := &stmtCompiler{a, s.Pos(), true};
s.Visit(sc);
- if a.child != nil {
+ if a.block.inner != nil {
log.Crash("Forgot to exit child scope");
}
a.err = a.err || sc.err;
@@ -668,49 +673,30 @@ func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
}
func (a *blockCompiler) enterChild() *blockCompiler {
- if a.child != nil {
- log.Crash("Failed to exit child block before entering another child");
- }
- blockScope := a.scope.Fork();
- bc := &blockCompiler{
+ block := a.block.enterChild();
+ return &blockCompiler{
funcCompiler: a.funcCompiler,
- scope: blockScope,
+ block: block,
returned: false,
parent: a,
};
- a.child = bc;
- a.push(func(v *vm) {
- v.f = blockScope.NewFrame(v.f);
- });
- return bc;
}
func (a *blockCompiler) exit() {
- if a.parent == nil {
- log.Crash("Cannot exit top-level block");
- }
- if a.parent.child != a {
- log.Crash("Double exit of block");
- }
- if a.child != nil {
- log.Crash("Exit of parent block without exit of child block");
- }
- a.push(func(v *vm) {
- v.f = v.f.Outer;
- });
- a.parent.child = nil;
+ a.block.exit();
}
/*
* Function compiler
*/
-func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func) {
+func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func) {
// Create body scope
//
// The scope of a parameter or result is the body of the
// corresponding function.
- bodyScope := scope.Fork();
+ bodyScope := b.ChildScope();
+ defer bodyScope.exit();
for i, t := range decl.Type.In {
if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, t);
@@ -734,7 +720,7 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
}
bc := &blockCompiler{
funcCompiler: fc,
- scope: bodyScope,
+ block: bodyScope.block,
returned: false,
};
@@ -756,7 +742,8 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
}
code := fc.get();
- return func(f *Frame) Func { return &evalFunc{bodyScope, f, code} };
+ maxVars := bodyScope.maxVars;
+ return func(f *Frame) Func { return &evalFunc{f, maxVars, code} };
}
/*
@@ -777,7 +764,7 @@ func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
fc := &funcCompiler{cc, nil, false, newCodeBuf(), false};
bc := &blockCompiler{
funcCompiler: fc,
- scope: scope,
+ block: scope.block,
returned: false
};
out := make([]*Stmt, len(stmts));
diff --git a/usr/austin/eval/type.go b/usr/austin/eval/type.go
index cc107115a..b189b5379 100644
--- a/usr/austin/eval/type.go
+++ b/usr/austin/eval/type.go
@@ -672,8 +672,6 @@ type ChanType struct {
*/
type NamedType struct {
- // Declaration scope
- scope *Scope;
name string;
// Underlying type
def Type;
diff --git a/usr/austin/eval/typec.go b/usr/austin/eval/typec.go
index d9357271a..3d672c4aa 100644
--- a/usr/austin/eval/typec.go
+++ b/usr/austin/eval/typec.go
@@ -23,13 +23,13 @@ type exprCompiler struct
type typeCompiler struct {
*compiler;
- scope *Scope;
+ block *block;
}
func (a *typeCompiler) compileType(x ast.Expr) Type
func (a *typeCompiler) compileIdent(x *ast.Ident) Type {
- def, dscope := a.scope.Lookup(x.Value);
+ _, def := a.block.Lookup(x.Value);
if def == nil {
a.diagAt(x, "%s: undefined", x.Value);
return nil;
@@ -58,7 +58,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
a.diagAt(x.Len, "... array initailizers not implemented");
return nil;
}
- l, ok := a.compileArrayLen(a.scope, x.Len);
+ l, ok := a.compileArrayLen(a.block, x.Len);
// Compile element type
elem := a.compileType(x.Elt);
@@ -191,12 +191,12 @@ notimpl:
* Type compiler interface
*/
-func (a *compiler) compileType(scope *Scope, typ ast.Expr) Type {
- tc := &typeCompiler{a, scope};
+func (a *compiler) compileType(b *block, typ ast.Expr) Type {
+ tc := &typeCompiler{a, b};
return tc.compileType(typ);
}
-func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl {
- tc := &typeCompiler{a, scope};
+func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
+ tc := &typeCompiler{a, b};
return tc.compileFuncType(typ);
}