@@ -37,7 +37,7 @@ import (
3737const debug = false // TODO(adonovan): use a bitmap of options; and regexp to match files
3838
3939// Increment this to force recompilation of saved bytecode files.
40- const Version = 5
40+ const Version = 6
4141
4242type Opcode uint8
4343
@@ -80,9 +80,10 @@ const (
8080
8181 IN
8282
83- // unary operators
83+ // unary operators (order of +/-/* must match Token)
8484 UPLUS // x UPLUS x
8585 UMINUS // x UMINUS -x
86+ USTAR // x USTAR *x
8687 TILDE // x TILDE ~x
8788
8889 NONE // - NONE None
@@ -94,13 +95,16 @@ const (
9495 NOT // value NOT bool
9596 RETURN // value RETURN -
9697 SETINDEX // a i new SETINDEX -
97- INDEX // a i INDEX elem
98+ INDEX // a i INDEX elem elem = a[i]
9899 SETDICT // dict key value SETDICT -
99100 SETDICTUNIQ // dict key value SETDICTUNIQ -
100101 APPEND // list elem APPEND -
101102 SLICE // x lo hi step SLICE slice
102- INPLACE_ADD // x y INPLACE_ADD z where z is x+y or x.extend(y)
103+ INPLACE_ADD // x y INPLACE_ADD z where z is x+y or x.extend(y)
103104 MAKEDICT // - MAKEDICT dict
105+ ADDRESS // var ADDRESS addr fails if not Variable [stargo only]
106+ VALUE // var VALUE value identity if not Variable [stargo only]
107+ SETVALUE // var x SETVALUE - fails if not Variable [stargo only]
104108
105109 // --- opcodes with an argument must go below this line ---
106110
@@ -139,6 +143,7 @@ const (
139143// TODO(adonovan): add dynamic checks for missing opcodes in the tables below.
140144
141145var opcodeNames = [... ]string {
146+ ADDRESS : "address" ,
142147 AMP : "amp" ,
143148 APPEND : "append" ,
144149 ATTR : "attr" ,
@@ -186,12 +191,14 @@ var opcodeNames = [...]string{
186191 POP : "pop" ,
187192 PREDECLARED : "predeclared" ,
188193 RETURN : "return" ,
194+ VALUE : "value" ,
189195 SETDICT : "setdict" ,
190196 SETDICTUNIQ : "setdictuniq" ,
191197 SETFIELD : "setfield" ,
192198 SETGLOBAL : "setglobal" ,
193199 SETINDEX : "setindex" ,
194200 SETLOCAL : "setlocal" ,
201+ SETVALUE : "setvalue" ,
195202 SLASH : "slash" ,
196203 SLASHSLASH : "slashslash" ,
197204 SLICE : "slice" ,
@@ -202,13 +209,15 @@ var opcodeNames = [...]string{
202209 UNIVERSAL : "universal" ,
203210 UNPACK : "unpack" ,
204211 UPLUS : "uplus" ,
212+ USTAR : "ustar" ,
205213}
206214
207215const variableStackEffect = 0x7f
208216
209217// stackEffect records the effect on the size of the operand stack of
210218// each kind of instruction. For some instructions this requires computation.
211219var stackEffect = [... ]int8 {
220+ ADDRESS : 0 ,
212221 AMP : - 1 ,
213222 APPEND : - 2 ,
214223 ATTR : 0 ,
@@ -261,6 +270,7 @@ var stackEffect = [...]int8{
261270 SETGLOBAL : - 1 ,
262271 SETINDEX : - 3 ,
263272 SETLOCAL : - 1 ,
273+ SETVALUE : - 2 ,
264274 SLASH : - 1 ,
265275 SLASHSLASH : - 1 ,
266276 SLICE : - 3 ,
@@ -270,6 +280,8 @@ var stackEffect = [...]int8{
270280 UNIVERSAL : + 1 ,
271281 UNPACK : variableStackEffect ,
272282 UPLUS : 0 ,
283+ USTAR : 0 ,
284+ VALUE : 0 ,
273285}
274286
275287func (op Opcode ) String () string {
@@ -1005,25 +1017,41 @@ func (fcomp *fcomp) stmt(stmt syntax.Stmt) {
10051017 fcomp .set (lhs )
10061018 }
10071019
1020+ case * syntax.UnaryExpr :
1021+ // *x = ...
1022+ fcomp .expr (lhs .X )
1023+ fcomp .emit (DUP )
1024+ fcomp .emit (VALUE )
1025+ set = func () {
1026+ fcomp .setPos (lhs .OpPos ) // op == STAR
1027+ fcomp .emit (SETVALUE )
1028+ }
1029+
10081030 case * syntax.IndexExpr :
10091031 // x[y] = ...
1010- fcomp .expr (lhs .X )
1032+ fcomp .addr (lhs .X )
10111033 fcomp .expr (lhs .Y )
10121034 fcomp .emit (DUP2 )
10131035 fcomp .setPos (lhs .Lbrack )
10141036 fcomp .emit (INDEX )
1037+ if resolve .AllowAddressing {
1038+ fcomp .emit (VALUE )
1039+ }
10151040 set = func () {
10161041 fcomp .setPos (lhs .Lbrack )
10171042 fcomp .emit (SETINDEX )
10181043 }
10191044
10201045 case * syntax.DotExpr :
10211046 // x.f = ...
1022- fcomp .expr (lhs .X )
1047+ fcomp .addr (lhs .X )
10231048 fcomp .emit (DUP )
10241049 name := fcomp .pcomp .nameIndex (lhs .Name .Name )
10251050 fcomp .setPos (lhs .Dot )
10261051 fcomp .emit1 (ATTR , name )
1052+ if resolve .AllowAddressing {
1053+ fcomp .emit (VALUE )
1054+ }
10271055 set = func () {
10281056 fcomp .setPos (lhs .Dot )
10291057 fcomp .emit1 (SETFIELD , name )
@@ -1143,7 +1171,7 @@ func (fcomp *fcomp) assign(pos syntax.Position, lhs syntax.Expr) {
11431171
11441172 case * syntax.IndexExpr :
11451173 // x[y] = rhs
1146- fcomp .expr (lhs .X )
1174+ fcomp .addr (lhs .X )
11471175 fcomp .emit (EXCH )
11481176 fcomp .expr (lhs .Y )
11491177 fcomp .emit (EXCH )
@@ -1152,11 +1180,19 @@ func (fcomp *fcomp) assign(pos syntax.Position, lhs syntax.Expr) {
11521180
11531181 case * syntax.DotExpr :
11541182 // x.f = rhs
1155- fcomp .expr (lhs .X )
1183+ fcomp .addr (lhs .X )
11561184 fcomp .emit (EXCH )
11571185 fcomp .setPos (lhs .Dot )
11581186 fcomp .emit1 (SETFIELD , fcomp .pcomp .nameIndex (lhs .Name .Name ))
11591187
1188+ case * syntax.UnaryExpr :
1189+ // *x = rhs
1190+ fcomp .expr (lhs .X )
1191+ fcomp .emit (USTAR )
1192+ fcomp .emit (EXCH )
1193+ fcomp .setPos (lhs .OpPos ) // op == STAR
1194+ fcomp .emit (SETVALUE )
1195+
11601196 default :
11611197 panic (lhs )
11621198 }
@@ -1170,6 +1206,47 @@ func (fcomp *fcomp) assignSequence(pos syntax.Position, lhs []syntax.Expr) {
11701206 }
11711207}
11721208
1209+ // addr emits code for a chain of x.f and a[i] operations such as a.f[i].g[j].
1210+ //
1211+ // In Addressing mode, all nonrecursive calls to addr() (a chain of ATTR
1212+ // and INDEX ops) must be followed by one of ADDRESS, SETFIELD,
1213+ // SETINDEX, or VALUE:
1214+ //
1215+ // &(expr.f[i].g) expr ATTR<f> i INDEX ATTR<g> ADDRESS
1216+ // (expr.f[i].g).x = y expr ATTR<f> i INDEX ATTR<g> y SETFIELD<x>
1217+ // (expr.f[i].g)[j] = y expr ATTR<f> i INDEX ATTR<g> y j SETINDEX
1218+ // _ = expr.f[i].g expr ATTR<f> i INDEX ATTR<g> VALUE
1219+ //
1220+ // We could in principle extend this scheme to all variables (such as x
1221+ // in x.f)), not just the x[i] and x.f operations applied to them, but
1222+ // it would add a cost to every variable lookup, and in practice it is
1223+ // unnecessary as most starlark.Variables live in a module such as http
1224+ // for http.DefaultServeMux, so they are acccessed using a dot expression.
1225+ //
1226+ // See comments at starlark.Variable for background.
1227+ //
1228+ func (fcomp * fcomp ) addr (e syntax.Expr ) {
1229+ switch e := e .(type ) {
1230+ case * syntax.ParenExpr :
1231+ fcomp .addr (e .X )
1232+
1233+ case * syntax.DotExpr :
1234+ fcomp .addr (e .X )
1235+ fcomp .setPos (e .Dot )
1236+ fcomp .emit1 (ATTR , fcomp .pcomp .nameIndex (e .Name .Name ))
1237+
1238+ case * syntax.IndexExpr :
1239+ fcomp .addr (e .X )
1240+ fcomp .expr (e .Y )
1241+ fcomp .setPos (e .Lbrack )
1242+ fcomp .emit (INDEX )
1243+
1244+ default :
1245+ fcomp .expr (e )
1246+
1247+ }
1248+ }
1249+
11731250func (fcomp * fcomp ) expr (e syntax.Expr ) {
11741251 switch e := e .(type ) {
11751252 case * syntax.ParenExpr :
@@ -1207,10 +1284,10 @@ func (fcomp *fcomp) expr(e syntax.Expr) {
12071284 fcomp .block = done
12081285
12091286 case * syntax.IndexExpr :
1210- fcomp .expr ( e . X )
1211- fcomp . expr ( e . Y )
1212- fcomp .setPos ( e . Lbrack )
1213- fcomp . emit ( INDEX )
1287+ fcomp .addr ( e )
1288+ if resolve . AllowAddressing {
1289+ fcomp .emit ( VALUE )
1290+ }
12141291
12151292 case * syntax.SliceExpr :
12161293 fcomp .setPos (e .Lbrack )
@@ -1255,13 +1332,23 @@ func (fcomp *fcomp) expr(e syntax.Expr) {
12551332 }
12561333
12571334 case * syntax.UnaryExpr :
1258- fcomp .expr (e .X )
1335+ switch e .Op {
1336+ case syntax .AMP , syntax .STAR :
1337+ fcomp .addr (e .X )
1338+ default :
1339+ fcomp .expr (e .X )
1340+ }
12591341 fcomp .setPos (e .OpPos )
12601342 switch e .Op {
1343+ case syntax .AMP :
1344+ fcomp .emit (ADDRESS )
12611345 case syntax .MINUS :
12621346 fcomp .emit (UMINUS )
12631347 case syntax .PLUS :
12641348 fcomp .emit (UPLUS )
1349+ case syntax .STAR :
1350+ fcomp .emit (USTAR )
1351+ fcomp .emit (VALUE )
12651352 case syntax .NOT :
12661353 fcomp .emit (NOT )
12671354 case syntax .TILDE :
@@ -1317,9 +1404,10 @@ func (fcomp *fcomp) expr(e syntax.Expr) {
13171404 }
13181405
13191406 case * syntax.DotExpr :
1320- fcomp .expr (e .X )
1321- fcomp .setPos (e .Dot )
1322- fcomp .emit1 (ATTR , fcomp .pcomp .nameIndex (e .Name .Name ))
1407+ fcomp .addr (e )
1408+ if resolve .AllowAddressing {
1409+ fcomp .emit (VALUE )
1410+ }
13231411
13241412 case * syntax.CallExpr :
13251413 fcomp .call (e )
0 commit comments