github.com/k14s/starlark-go@v0.0.0-20200720175618-3a5c849cc368/starlark/interp.go (about) 1 package starlark 2 3 // This file defines the bytecode interpreter. 4 5 import ( 6 "fmt" 7 "os" 8 9 "github.com/k14s/starlark-go/internal/compile" 10 "github.com/k14s/starlark-go/internal/spell" 11 "github.com/k14s/starlark-go/resolve" 12 "github.com/k14s/starlark-go/syntax" 13 ) 14 15 const vmdebug = false // TODO(adonovan): use a bitfield of specific kinds of error. 16 17 // TODO(adonovan): 18 // - optimize position table. 19 // - opt: record MaxIterStack during compilation and preallocate the stack. 20 21 func (fn *Function) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { 22 if !resolve.AllowRecursion { 23 // detect recursion 24 for _, fr := range thread.stack[:len(thread.stack)-1] { 25 // We look for the same function code, 26 // not function value, otherwise the user could 27 // defeat the check by writing the Y combinator. 28 if frfn, ok := fr.Callable().(*Function); ok && frfn.funcode == fn.funcode { 29 return nil, fmt.Errorf("function %s called recursively", fn.Name()) 30 } 31 } 32 } 33 34 f := fn.funcode 35 fr := thread.frameAt(0) 36 37 // Allocate space for stack and locals. 38 // Logically these do not escape from this frame 39 // (See https://github.com/golang/go/issues/20533.) 40 // 41 // This heap allocation looks expensive, but I was unable to get 42 // more than 1% real time improvement in a large alloc-heavy 43 // benchmark (in which this alloc was 8% of alloc-bytes) 44 // by allocating space for 8 Values in each frame, or 45 // by allocating stack by slicing an array held by the Thread 46 // that is expanded in chunks of min(k, nspace), for k=256 or 1024. 47 nlocals := len(f.Locals) 48 nspace := nlocals + f.MaxStack 49 space := make([]Value, nspace) 50 locals := space[:nlocals:nlocals] // local variables, starting with parameters 51 stack := space[nlocals:] // operand stack 52 53 // Digest arguments and set parameters. 54 err := setArgs(locals, fn, args, kwargs) 55 if err != nil { 56 return nil, thread.evalError(err) 57 } 58 59 fr.locals = locals 60 61 if vmdebug { 62 fmt.Printf("Entering %s @ %s\n", f.Name, f.Position(0)) 63 fmt.Printf("%d stack, %d locals\n", len(stack), len(locals)) 64 defer fmt.Println("Leaving ", f.Name) 65 } 66 67 // Spill indicated locals to cells. 68 // Each cell is a separate alloc to avoid spurious liveness. 69 for _, index := range f.Cells { 70 locals[index] = &cell{locals[index]} 71 } 72 73 // TODO(adonovan): add static check that beneath this point 74 // - there is exactly one return statement 75 // - there is no redefinition of 'err'. 76 77 var iterstack []Iterator // stack of active iterators 78 79 sp := 0 80 var pc uint32 81 var result Value 82 code := f.Code 83 loop: 84 for { 85 fr.pc = pc 86 87 op := compile.Opcode(code[pc]) 88 pc++ 89 var arg uint32 90 if op >= compile.OpcodeArgMin { 91 // TODO(adonovan): opt: profile this. 92 // Perhaps compiling big endian would be less work to decode? 93 for s := uint(0); ; s += 7 { 94 b := code[pc] 95 pc++ 96 arg |= uint32(b&0x7f) << s 97 if b < 0x80 { 98 break 99 } 100 } 101 } 102 if vmdebug { 103 fmt.Fprintln(os.Stderr, stack[:sp]) // very verbose! 104 compile.PrintOp(f, fr.pc, op, arg) 105 } 106 107 switch op { 108 case compile.NOP: 109 // nop 110 111 case compile.DUP: 112 stack[sp] = stack[sp-1] 113 sp++ 114 115 case compile.DUP2: 116 stack[sp] = stack[sp-2] 117 stack[sp+1] = stack[sp-1] 118 sp += 2 119 120 case compile.POP: 121 sp-- 122 123 case compile.EXCH: 124 stack[sp-2], stack[sp-1] = stack[sp-1], stack[sp-2] 125 126 case compile.EQL, compile.NEQ, compile.GT, compile.LT, compile.LE, compile.GE: 127 op := syntax.Token(op-compile.EQL) + syntax.EQL 128 y := stack[sp-1] 129 x := stack[sp-2] 130 sp -= 2 131 ok, err2 := Compare(op, x, y) 132 if err2 != nil { 133 err = err2 134 break loop 135 } 136 stack[sp] = Bool(ok) 137 sp++ 138 139 case compile.PLUS, 140 compile.MINUS, 141 compile.STAR, 142 compile.SLASH, 143 compile.SLASHSLASH, 144 compile.PERCENT, 145 compile.AMP, 146 compile.PIPE, 147 compile.CIRCUMFLEX, 148 compile.LTLT, 149 compile.GTGT, 150 compile.IN: 151 binop := syntax.Token(op-compile.PLUS) + syntax.PLUS 152 if op == compile.IN { 153 binop = syntax.IN // IN token is out of order 154 } 155 y := stack[sp-1] 156 x := stack[sp-2] 157 sp -= 2 158 z, err2 := Binary(binop, x, y) 159 if err2 != nil { 160 err = err2 161 break loop 162 } 163 stack[sp] = z 164 sp++ 165 166 case compile.UPLUS, compile.UMINUS, compile.TILDE: 167 var unop syntax.Token 168 if op == compile.TILDE { 169 unop = syntax.TILDE 170 } else { 171 unop = syntax.Token(op-compile.UPLUS) + syntax.PLUS 172 } 173 x := stack[sp-1] 174 y, err2 := Unary(unop, x) 175 if err2 != nil { 176 err = err2 177 break loop 178 } 179 stack[sp-1] = y 180 181 case compile.INPLACE_ADD: 182 y := stack[sp-1] 183 x := stack[sp-2] 184 sp -= 2 185 186 // It's possible that y is not Iterable but 187 // nonetheless defines x+y, in which case we 188 // should fall back to the general case. 189 var z Value 190 if xlist, ok := x.(*List); ok { 191 if yiter, ok := y.(Iterable); ok { 192 if err = xlist.checkMutable("apply += to"); err != nil { 193 break loop 194 } 195 listExtend(xlist, yiter) 196 z = xlist 197 } 198 } 199 if z == nil { 200 z, err = Binary(syntax.PLUS, x, y) 201 if err != nil { 202 break loop 203 } 204 } 205 206 stack[sp] = z 207 sp++ 208 209 case compile.NONE: 210 stack[sp] = None 211 sp++ 212 213 case compile.TRUE: 214 stack[sp] = True 215 sp++ 216 217 case compile.FALSE: 218 stack[sp] = False 219 sp++ 220 221 case compile.MANDATORY: 222 stack[sp] = mandatory{} 223 sp++ 224 225 case compile.JMP: 226 pc = arg 227 228 case compile.CALL, compile.CALL_VAR, compile.CALL_KW, compile.CALL_VAR_KW: 229 var kwargs Value 230 if op == compile.CALL_KW || op == compile.CALL_VAR_KW { 231 kwargs = stack[sp-1] 232 sp-- 233 } 234 235 var args Value 236 if op == compile.CALL_VAR || op == compile.CALL_VAR_KW { 237 args = stack[sp-1] 238 sp-- 239 } 240 241 // named args (pairs) 242 var kvpairs []Tuple 243 if nkvpairs := int(arg & 0xff); nkvpairs > 0 { 244 kvpairs = make([]Tuple, 0, nkvpairs) 245 kvpairsAlloc := make(Tuple, 2*nkvpairs) // allocate a single backing array 246 sp -= 2 * nkvpairs 247 for i := 0; i < nkvpairs; i++ { 248 pair := kvpairsAlloc[:2:2] 249 kvpairsAlloc = kvpairsAlloc[2:] 250 pair[0] = stack[sp+2*i] // name 251 pair[1] = stack[sp+2*i+1] // value 252 kvpairs = append(kvpairs, pair) 253 } 254 } 255 if kwargs != nil { 256 // Add key/value items from **kwargs dictionary. 257 dict, ok := kwargs.(IterableMapping) 258 if !ok { 259 err = fmt.Errorf("argument after ** must be a mapping, not %s", kwargs.Type()) 260 break loop 261 } 262 items := dict.Items() 263 for _, item := range items { 264 if _, ok := item[0].(String); !ok { 265 err = fmt.Errorf("keywords must be strings, not %s", item[0].Type()) 266 break loop 267 } 268 } 269 if len(kvpairs) == 0 { 270 kvpairs = items 271 } else { 272 kvpairs = append(kvpairs, items...) 273 } 274 } 275 276 // positional args 277 var positional Tuple 278 if npos := int(arg >> 8); npos > 0 { 279 positional = make(Tuple, npos) 280 sp -= npos 281 copy(positional, stack[sp:]) 282 } 283 if args != nil { 284 // Add elements from *args sequence. 285 iter := Iterate(args) 286 if iter == nil { 287 err = fmt.Errorf("argument after * must be iterable, not %s", args.Type()) 288 break loop 289 } 290 var elem Value 291 for iter.Next(&elem) { 292 positional = append(positional, elem) 293 } 294 iter.Done() 295 } 296 297 function := stack[sp-1] 298 299 if vmdebug { 300 fmt.Printf("VM call %s args=%s kwargs=%s @%s\n", 301 function, positional, kvpairs, f.Position(fr.pc)) 302 } 303 304 thread.endProfSpan() 305 z, err2 := Call(thread, function, positional, kvpairs) 306 thread.beginProfSpan() 307 if err2 != nil { 308 err = err2 309 break loop 310 } 311 if vmdebug { 312 fmt.Printf("Resuming %s @ %s\n", f.Name, f.Position(0)) 313 } 314 stack[sp-1] = z 315 316 case compile.ITERPUSH: 317 x := stack[sp-1] 318 sp-- 319 iter := Iterate(x) 320 if iter == nil { 321 err = fmt.Errorf("%s value is not iterable", x.Type()) 322 break loop 323 } 324 iterstack = append(iterstack, iter) 325 326 case compile.ITERJMP: 327 iter := iterstack[len(iterstack)-1] 328 if iter.Next(&stack[sp]) { 329 sp++ 330 } else { 331 pc = arg 332 } 333 334 case compile.ITERPOP: 335 n := len(iterstack) - 1 336 iterstack[n].Done() 337 iterstack = iterstack[:n] 338 339 case compile.NOT: 340 stack[sp-1] = !stack[sp-1].Truth() 341 342 case compile.RETURN: 343 result = stack[sp-1] 344 break loop 345 346 case compile.SETINDEX: 347 z := stack[sp-1] 348 y := stack[sp-2] 349 x := stack[sp-3] 350 sp -= 3 351 err = setIndex(x, y, z) 352 if err != nil { 353 break loop 354 } 355 356 case compile.INDEX: 357 y := stack[sp-1] 358 x := stack[sp-2] 359 sp -= 2 360 z, err2 := getIndex(x, y) 361 if err2 != nil { 362 err = err2 363 break loop 364 } 365 stack[sp] = z 366 sp++ 367 368 case compile.ATTR: 369 x := stack[sp-1] 370 name := f.Prog.Names[arg] 371 y, err2 := getAttr(x, name) 372 if err2 != nil { 373 err = err2 374 break loop 375 } 376 stack[sp-1] = y 377 378 case compile.SETFIELD: 379 y := stack[sp-1] 380 x := stack[sp-2] 381 sp -= 2 382 name := f.Prog.Names[arg] 383 if err2 := setField(x, name, y); err2 != nil { 384 err = err2 385 break loop 386 } 387 388 case compile.MAKEDICT: 389 stack[sp] = new(Dict) 390 sp++ 391 392 case compile.SETDICT, compile.SETDICTUNIQ: 393 dict := stack[sp-3].(*Dict) 394 k := stack[sp-2] 395 v := stack[sp-1] 396 sp -= 3 397 oldlen := dict.Len() 398 if err2 := dict.SetKey(k, v); err2 != nil { 399 err = err2 400 break loop 401 } 402 if op == compile.SETDICTUNIQ && dict.Len() == oldlen { 403 err = fmt.Errorf("duplicate key: %v", k) 404 break loop 405 } 406 407 case compile.APPEND: 408 elem := stack[sp-1] 409 list := stack[sp-2].(*List) 410 sp -= 2 411 list.elems = append(list.elems, elem) 412 413 case compile.SLICE: 414 x := stack[sp-4] 415 lo := stack[sp-3] 416 hi := stack[sp-2] 417 step := stack[sp-1] 418 sp -= 4 419 res, err2 := slice(x, lo, hi, step) 420 if err2 != nil { 421 err = err2 422 break loop 423 } 424 stack[sp] = res 425 sp++ 426 427 case compile.UNPACK: 428 n := int(arg) 429 iterable := stack[sp-1] 430 sp-- 431 iter := Iterate(iterable) 432 if iter == nil { 433 err = fmt.Errorf("got %s in sequence assignment", iterable.Type()) 434 break loop 435 } 436 i := 0 437 sp += n 438 for i < n && iter.Next(&stack[sp-1-i]) { 439 i++ 440 } 441 var dummy Value 442 if iter.Next(&dummy) { 443 // NB: Len may return -1 here in obscure cases. 444 err = fmt.Errorf("too many values to unpack (got %d, want %d)", Len(iterable), n) 445 break loop 446 } 447 iter.Done() 448 if i < n { 449 err = fmt.Errorf("too few values to unpack (got %d, want %d)", i, n) 450 break loop 451 } 452 453 case compile.CJMP: 454 if stack[sp-1].Truth() { 455 pc = arg 456 } 457 sp-- 458 459 case compile.CONSTANT: 460 stack[sp] = fn.module.constants[arg] 461 sp++ 462 463 case compile.MAKETUPLE: 464 n := int(arg) 465 tuple := make(Tuple, n) 466 sp -= n 467 copy(tuple, stack[sp:]) 468 stack[sp] = tuple 469 sp++ 470 471 case compile.MAKELIST: 472 n := int(arg) 473 elems := make([]Value, n) 474 sp -= n 475 copy(elems, stack[sp:]) 476 stack[sp] = NewList(elems) 477 sp++ 478 479 case compile.MAKEFUNC: 480 funcode := f.Prog.Functions[arg] 481 tuple := stack[sp-1].(Tuple) 482 n := len(tuple) - len(funcode.Freevars) 483 defaults := tuple[:n:n] 484 freevars := tuple[n:] 485 stack[sp-1] = &Function{ 486 funcode: funcode, 487 module: fn.module, 488 defaults: defaults, 489 freevars: freevars, 490 } 491 492 case compile.LOAD: 493 n := int(arg) 494 module := string(stack[sp-1].(String)) 495 sp-- 496 497 if thread.Load == nil { 498 err = fmt.Errorf("load not implemented by this application") 499 break loop 500 } 501 502 thread.endProfSpan() 503 dict, err2 := thread.Load(thread, module) 504 thread.beginProfSpan() 505 if err2 != nil { 506 err = fmt.Errorf("cannot load %s: %v", module, err2) 507 break loop 508 } 509 510 for i := 0; i < n; i++ { 511 from := string(stack[sp-1-i].(String)) 512 v, ok := dict[from] 513 if !ok { 514 err = fmt.Errorf("load: name %s not found in module %s", from, module) 515 if n := spell.Nearest(from, dict.Keys()); n != "" { 516 err = fmt.Errorf("%s (did you mean %s?)", err, n) 517 } 518 break loop 519 } 520 stack[sp-1-i] = v 521 } 522 523 case compile.SETLOCAL: 524 locals[arg] = stack[sp-1] 525 sp-- 526 527 case compile.SETCELL: 528 x := stack[sp-2] 529 y := stack[sp-1] 530 sp -= 2 531 y.(*cell).v = x 532 533 case compile.SETGLOBAL: 534 fn.module.globals[arg] = stack[sp-1] 535 sp-- 536 537 case compile.LOCAL: 538 x := locals[arg] 539 if x == nil { 540 err = fmt.Errorf("local variable %s referenced before assignment", f.Locals[arg].Name) 541 break loop 542 } 543 stack[sp] = x 544 sp++ 545 546 case compile.FREE: 547 stack[sp] = fn.freevars[arg] 548 sp++ 549 550 case compile.CELL: 551 x := stack[sp-1] 552 stack[sp-1] = x.(*cell).v 553 554 case compile.GLOBAL: 555 x := fn.module.globals[arg] 556 if x == nil { 557 err = fmt.Errorf("global variable %s referenced before assignment", f.Prog.Globals[arg].Name) 558 break loop 559 } 560 stack[sp] = x 561 sp++ 562 563 case compile.PREDECLARED: 564 name := f.Prog.Names[arg] 565 x := fn.module.predeclared[name] 566 if x == nil { 567 err = fmt.Errorf("internal error: predeclared variable %s is uninitialized", name) 568 break loop 569 } 570 stack[sp] = x 571 sp++ 572 573 case compile.UNIVERSAL: 574 stack[sp] = Universe[f.Prog.Names[arg]] 575 sp++ 576 577 default: 578 err = fmt.Errorf("unimplemented: %s", op) 579 break loop 580 } 581 } 582 583 // ITERPOP the rest of the iterator stack. 584 for _, iter := range iterstack { 585 iter.Done() 586 } 587 588 fr.locals = nil 589 590 return result, err 591 } 592 593 // mandatory is a sentinel value used in a function's defaults tuple 594 // to indicate that a (keyword-only) parameter is mandatory. 595 type mandatory struct{} 596 597 func (mandatory) String() string { return "mandatory" } 598 func (mandatory) Type() string { return "mandatory" } 599 func (mandatory) Freeze() {} // immutable 600 func (mandatory) Truth() Bool { return False } 601 func (mandatory) Hash() (uint32, error) { return 0, nil } 602 603 // A cell is a box containing a Value. 604 // Local variables marked as cells hold their value indirectly 605 // so that they may be shared by outer and inner nested functions. 606 // Cells are always accessed using indirect CELL/SETCELL instructions. 607 // The FreeVars tuple contains only cells. 608 // The FREE instruction always yields a cell. 609 type cell struct{ v Value } 610 611 func (c *cell) String() string { return "cell" } 612 func (c *cell) Type() string { return "cell" } 613 func (c *cell) Freeze() { 614 if c.v != nil { 615 c.v.Freeze() 616 } 617 } 618 func (c *cell) Truth() Bool { panic("unreachable") } 619 func (c *cell) Hash() (uint32, error) { panic("unreachable") }