diff options
author | alandonovan <adonovan@google.com> | 2018-04-02 13:08:46 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-02 13:08:46 -0400 |
commit | 8c4023ca890bad71d4936423cee71acfd0a93a8e (patch) | |
tree | a2dcb0f6d96bad3d2f7c4e143c4e8509e877e085 /internal/compile/compile.go | |
parent | 60e4b3d65da9be653c231e535f7e1e56d47ca617 (diff) | |
download | starlark-go-8c4023ca890bad71d4936423cee71acfd0a93a8e.tar.gz |
interp: materialize a Value for each constant prior to execution (#98)
This change makes the interpreter materialize compiled constants as
Values during module creation (Program.Init or Eval), rather than on
the fly as each constant is required. This avoids the need for the
unsafe speed hack.
Also, we serialize big.Ints using their gob-encoding, not as a string,
which is not only more efficient but allows us to handle all constants
in a uniform manner, with a single CONSTANT opcode instead of separate
ones for INT/BIGINT/FLOAT/STRING.
Also: sort opcode tables.
Diffstat (limited to 'internal/compile/compile.go')
-rw-r--r-- | internal/compile/compile.go | 64 |
1 files changed, 21 insertions, 43 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go index 01d33a1..6d86b4b 100644 --- a/internal/compile/compile.go +++ b/internal/compile/compile.go @@ -26,9 +26,9 @@ import ( "bytes" "fmt" "log" - "math/big" "os" "path/filepath" + "strconv" "github.com/google/skylark/resolve" "github.com/google/skylark/syntax" @@ -37,7 +37,7 @@ import ( const debug = false // TODO(adonovan): use a bitmap of options; and regexp to match files // Increment this to force recompilation of saved bytecode files. -const Version = 1 +const Version = 2 type Opcode uint8 @@ -106,10 +106,7 @@ const ( ITERJMP // - ITERJMP<addr> elem (and fall through) [acts on topmost iterator] // or: - ITERJMP<addr> - (and jump) - INT // - INT<constant> value - FLOAT // - FLOAT<constant> value - BIGINT // - BIGINT<constant> value - STRING // - STRING<constant> value + CONSTANT // - CONSTANT<constant> value MAKETUPLE // x1 ... xn MAKETUPLE<n> tuple MAKELIST // x1 ... xn MAKELIST<n> list MAKEFUNC // args kwargs MAKEFUNC<func> fn @@ -141,17 +138,16 @@ var opcodeNames = [...]string{ AMP: "amp", APPEND: "append", ATTR: "attr", - BIGINT: "bigint", CALL: "call", CALL_KW: "call_kw ", CALL_VAR: "call_var", CALL_VAR_KW: "call_var_kw", CJMP: "cjmp", - DUP: "dup", + CONSTANT: "constant", DUP2: "dup2", + DUP: "dup", EQL: "eql", FALSE: "false", - FLOAT: "float", FREE: "free", GE: "ge", GLOBAL: "global", @@ -159,7 +155,6 @@ var opcodeNames = [...]string{ IN: "in", INDEX: "index", INPLACE_ADD: "inplace_add", - INT: "int", ITERJMP: "iterjmp", ITERPOP: "iterpop", ITERPUSH: "iterpush", @@ -193,7 +188,6 @@ var opcodeNames = [...]string{ SLASHSLASH: "slashslash", SLICE: "slice", STAR: "star", - STRING: "string", TRUE: "true", UMINUS: "uminus", UNIVERSAL: "universal", @@ -209,17 +203,16 @@ var stackEffect = [...]int8{ AMP: -1, APPEND: -2, ATTR: 0, - BIGINT: +1, CALL: variableStackEffect, CALL_KW: variableStackEffect, CALL_VAR: variableStackEffect, CALL_VAR_KW: variableStackEffect, CJMP: -1, - DUP: +1, + CONSTANT: +1, DUP2: +2, + DUP: +1, EQL: -1, FALSE: +1, - FLOAT: +1, FREE: +1, GE: -1, GLOBAL: +1, @@ -227,10 +220,9 @@ var stackEffect = [...]int8{ IN: -1, INDEX: -1, INPLACE_ADD: -1, - INT: +1, ITERJMP: variableStackEffect, - ITERPUSH: -1, ITERPOP: 0, + ITERPUSH: -1, JMP: 0, LE: -1, LOAD: -1, @@ -246,10 +238,10 @@ var stackEffect = [...]int8{ NOP: 0, NOT: 0, PERCENT: -1, - PREDECLARED: +1, PIPE: -1, PLUS: -1, POP: -1, + PREDECLARED: +1, RETURN: -1, SETDICT: -3, SETDICTUNIQ: -3, @@ -261,10 +253,9 @@ var stackEffect = [...]int8{ SLASHSLASH: -1, SLICE: -3, STAR: -1, - STRING: +1, TRUE: +1, - UNPACK: variableStackEffect, UNIVERSAL: +1, + UNPACK: variableStackEffect, } func (op Opcode) String() string { @@ -281,7 +272,7 @@ func (op Opcode) String() string { type Program struct { Loads []Ident // name (really, string) and position of each load stmt Names []string // names of attributes and predeclared variables - Constants []interface{} // = string | int64 | float64 + Constants []interface{} // = string | int64 | float64 | *big.Int Functions []*Funcode Globals []Ident // for error messages and tracing Toplevel *Funcode // module initialization function @@ -741,10 +732,13 @@ func PrintOp(fn *Funcode, pc uint32, op Opcode, arg uint32) { var comment string switch op { - case INT, FLOAT, BIGINT: - comment = fmt.Sprint(fn.Prog.Constants[arg]) - case STRING: - comment = fmt.Sprintf("%q", fn.Prog.Constants[arg]) + case CONSTANT: + switch x := fn.Prog.Constants[arg].(type) { + case string: + comment = strconv.Quote(x) + default: + comment = fmt.Sprint(x) + } case MAKEFUNC: comment = fn.Prog.Functions[arg].Name case SETLOCAL, LOCAL: @@ -856,12 +850,7 @@ func (pcomp *pcomp) functionIndex(fn *Funcode) uint32 { // string emits code to push the specified string. func (fcomp *fcomp) string(s string) { - fcomp.emit1(STRING, fcomp.pcomp.constantIndex(s)) -} - -// int64 emits code to push the specified integer. -func (fcomp *fcomp) int64(i int64) { - fcomp.emit1(INT, fcomp.pcomp.constantIndex(i)) + fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(s)) } // setPos sets the current source position. @@ -1137,19 +1126,8 @@ func (fcomp *fcomp) expr(e syntax.Expr) { fcomp.lookup(e) case *syntax.Literal: - switch e.Token { - case syntax.INT: - switch e.Value.(type) { - case int64: - fcomp.int64(e.Value.(int64)) - case *big.Int: - fcomp.emit1(BIGINT, fcomp.pcomp.constantIndex(e.Value.(*big.Int).String())) - } - case syntax.FLOAT: - fcomp.emit1(FLOAT, fcomp.pcomp.constantIndex(e.Value.(float64))) - case syntax.STRING: - fcomp.string(e.Value.(string)) - } + // e.Value is int64, float64, *bigInt, or string. + fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(e.Value)) case *syntax.ListExpr: for _, x := range e.List { |