1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2017-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * global.go 12 * 13 * Created on Apr 01, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 "fmt" 21 "go/ast" 22 "go/constant" 23 "go/token" 24 r "reflect" 25 "sort" 26 27 "github.com/cosmos72/gomacro/atomic" 28 . "github.com/cosmos72/gomacro/base" 29 "github.com/cosmos72/gomacro/base/output" 30 "github.com/cosmos72/gomacro/base/untyped" 31 "github.com/cosmos72/gomacro/jit" 32 xr "github.com/cosmos72/gomacro/xreflect" 33) 34 35type I = interface{} 36 37// ================================= Untyped ================================= 38 39type UntypedLit = untyped.Lit 40 41var untypedOne = UntypedLit{Kind: untyped.Int, Val: constant.MakeInt64(1)} 42 43// ================================= Lit ================================= 44 45// Lit represents a literal value, i.e. a typed or untyped constant 46type Lit struct { 47 48 // Type is nil for literal nils. 49 // For all other literals, Type is xr.TypeOf(Lit.Value) 50 // 51 // when Lit is embedded in other structs that represent non-constant expressions, 52 // Type is the first type returned by the expression (nil if returns no values) 53 Type xr.Type 54 55 // Value is one of: 56 // nil, bool, int, int8, int16, int32, int64, 57 // uint, uint8, uint16, uint32, uint64, uintptr, 58 // float32, float64, complex64, complex128, string, 59 // UntypedLit 60 // 61 // when Lit is embedded in other structs that represent non-constant expressions, 62 // Value is usually nil 63 // 64 // when Lit is embedded in a Bind with class == TemplateFuncBind, 65 // Value is the *TemplateFunc containing the function source code 66 // to be specialized and compiled upon instantiation. 67 Value I 68} 69 70// Untyped returns true if Lit is an untyped constant 71func (lit *Lit) Untyped() bool { 72 _, ok := lit.Value.(UntypedLit) 73 return ok 74} 75 76// UntypedKind returns the reflect.Kind of untyped constants, 77// i.e. their "default type" 78func (lit *Lit) UntypedKind() untyped.Kind { 79 if untyp, ok := lit.Value.(UntypedLit); ok { 80 return untyp.Kind 81 } else { 82 return untyped.None 83 } 84} 85 86func (lit *Lit) ConstValue() r.Value { 87 v := r.ValueOf(lit.Value) 88 if lit.Type != nil { 89 rtype := lit.Type.ReflectType() 90 if !v.IsValid() { 91 v = r.Zero(rtype) 92 } else if !lit.Untyped() && v.Type() != rtype { 93 v = convert(v, rtype) 94 } 95 } 96 return v 97} 98 99func (lit Lit) String() string { 100 switch val := lit.Value.(type) { 101 case string, nil: 102 return fmt.Sprintf("%#v", val) 103 default: 104 return fmt.Sprintf("%v", val) 105 } 106} 107 108// ================================= EFlags ================================= 109 110// EFlags represents the flags of an expression 111type EFlags uint32 112 113const ( 114 EIsNil EFlags = 1 << iota 115 EIsTypeAssert 116) 117 118func (f EFlags) IsNil() bool { 119 return f&EIsNil != 0 120} 121 122func MakeEFlag(flag bool, iftrue EFlags) EFlags { 123 if flag { 124 return iftrue 125 } 126 return 0 127} 128 129func EFlag4Value(value I) EFlags { 130 if value == nil { 131 return EIsNil 132 } 133 return 0 134} 135 136// ================================= Expr ================================= 137 138// Expr represents an expression in the "compiler" 139type Expr struct { 140 Lit 141 Types []xr.Type // in case the expression produces multiple values. if nil, use Lit.Type. 142 Fun I // function that evaluates the expression at runtime. 143 Sym *Symbol // in case the expression is a symbol 144 Jit jit.Expr // expression to jit-compile, or nil if not supported 145 EFlags 146} 147 148func (e *Expr) Const() bool { 149 return e.Value != nil || e.IsNil() 150} 151 152// NumOut returns the number of values that an expression will produce when evaluated 153func (e *Expr) NumOut() int { 154 if e.Types == nil { 155 return 1 156 } 157 return len(e.Types) 158} 159 160// Out returns the i-th type that an expression will produce when evaluated 161func (e *Expr) Out(i int) xr.Type { 162 if i == 0 && e.Types == nil { 163 return e.Type 164 } 165 return e.Types[i] 166} 167 168func (e *Expr) String() string { 169 if e == nil { 170 return "nil" 171 } 172 var str string 173 if e.Const() { 174 str = fmt.Sprintf("Expr{Type: %v, Value: %v}", e.Type, e.Lit.String()) 175 } else if e.NumOut() == 1 { 176 str = fmt.Sprintf("Expr{Type: %v, Fun: %#v}", e.Type, e.Fun) 177 } else { 178 str = fmt.Sprintf("Expr{Types: %v, Fun: %#v}", e.Types, e.Fun) 179 } 180 return str 181} 182 183// ================================= Stmt ================================= 184 185// Stmt represents a statement in the fast interpreter 186type Stmt func(*Env) (Stmt, *Env) 187 188// ================================= Builtin ================================= 189 190// Builtin represents a builtin function in the fast interpreter 191type Builtin struct { 192 // interpreted code should not access "compile": not exported. 193 // compile usually needs to modify Symbol: pass it by value. 194 Compile func(c *Comp, sym Symbol, node *ast.CallExpr) *Call 195 ArgMin uint16 196 ArgMax uint16 197} 198 199// ================================= Function ================================= 200 201// Function represents a function that accesses *Interp in the fast interpreter 202type Function struct { 203 Fun interface{} 204 Type xr.Type 205} 206 207// ================================= Macro ================================= 208 209// Macro represents a macro in the fast interpreter 210type Macro struct { 211 closure func(args []r.Value) (results []r.Value) 212 argNum int 213} 214 215// ================================= BindClass ================================= 216 217// BindDescriptor uses two bits to store the class. 218// use all remaining bits as unsigned => we lose only one bit 219// when representing non-negative ints 220type BindClass uint 221 222const ( 223 ConstBind BindClass = iota 224 FuncBind 225 VarBind 226 IntBind 227 TemplateFuncBind 228 TemplateTypeBind 229) 230 231func (class BindClass) String() string { 232 switch class { 233 case ConstBind: 234 return "const" 235 case FuncBind: 236 return "func" 237 case VarBind: 238 return "var" 239 case IntBind: 240 return "intvar" 241 case TemplateFuncBind: 242 return "template func" 243 case TemplateTypeBind: 244 return "template type" 245 default: 246 return fmt.Sprintf("unknown%d", uint(class)) 247 } 248} 249 250// ================================== BindDescriptor ================================= 251 252// the zero value of BindDescriptor is a valid descriptor for all constants, 253// and also for functions and variables named "_" 254type BindDescriptor BindClass 255 256const ( 257 bindClassMask = BindClass(0x7) 258 bindIndexShift = 3 259 260 NoIndex = int(-1) // index of functions, variables named "_" and of constants 261 ConstBindDescriptor = BindDescriptor(ConstBind) // bind descriptor for all constants 262) 263 264func (class BindClass) MakeDescriptor(index int) BindDescriptor { 265 class &= bindClassMask 266 return BindDescriptor((index+1)<<bindIndexShift | int(class)) 267} 268 269// IntBind returns true if BindIndex refers to a slot in Env.IntBinds (the default is a slot in Env.Binds) 270func (desc BindDescriptor) Class() BindClass { 271 return BindClass(desc) & bindClassMask 272} 273 274// Index returns the slice index to use in Env.Binds or Env.IntBinds to access a variable or function. 275// returns NoIndex for variables and functions named "_" 276func (desc BindDescriptor) Index() int { 277 index := int(desc>>bindIndexShift) - 1 278 // debugf("BindDescriptor=%v, class=%v, index=%v", desc, desc.Class(), index) 279 return index 280} 281 282func (desc BindDescriptor) Settable() bool { 283 class := desc.Class() 284 return class == IntBind || class == VarBind 285} 286 287func (desc BindDescriptor) String() string { 288 return fmt.Sprintf("%s index=%d", desc.Class(), desc.Index()) 289} 290 291// ================================== Bind ================================= 292 293// Bind represents a constant, variable, function or builtin in the "compiler" 294type Bind struct { 295 Lit 296 Desc BindDescriptor 297 Name string 298} 299 300func (bind *Bind) String() string { 301 return fmt.Sprintf("{%s name=%q value=%v type=<%v>}", bind.Desc, bind.Name, bind.Lit.Value, bind.Lit.Type) 302} 303 304func (bind *Bind) Const() bool { 305 return bind.Desc.Class() == ConstBind 306} 307 308// return bind value for constant binds. 309// if bind is untyped constant, returns UntypedLit wrapped in reflect.Value 310func (bind *Bind) ConstValue() r.Value { 311 if !bind.Const() { 312 return Nil 313 } 314 return bind.Lit.ConstValue() 315} 316 317// return bind value. 318// if bind is untyped constant, returns UntypedLit wrapped in reflect.Value 319func (bind *Bind) RuntimeValue(g *CompGlobals, env *Env) r.Value { 320 var v r.Value 321 switch bind.Desc.Class() { 322 case ConstBind: 323 v = bind.Lit.ConstValue() 324 case IntBind: 325 expr := bind.intExpr(g) 326 // no need for Interp.RunExpr(): expr is a local variable, 327 // not a statement or a function call that may be stopped by the debugger 328 v = expr.AsX1()(env) 329 case VarBind, FuncBind: 330 v = env.Vals[bind.Desc.Index()] 331 case TemplateFuncBind, TemplateTypeBind: 332 if GENERICS_V1 { 333 v = bind.Lit.ConstValue() 334 break 335 } 336 fallthrough 337 default: 338 output.Errorf("Symbol %q: unsupported class: %v", bind.Name, bind.Desc.Class()) 339 } 340 return v 341} 342 343func (bind *Bind) AsVar(upn int, opt PlaceOption) *Var { 344 class := bind.Desc.Class() 345 switch class { 346 case VarBind, IntBind: 347 return &Var{Upn: upn, Desc: bind.Desc, Type: bind.Type, Name: bind.Name} 348 default: 349 output.Errorf("%s a %s: %s <%v>", opt, class, bind.Name, bind.Type) 350 return nil 351 } 352} 353 354func (bind *Bind) AsSymbol(upn int) *Symbol { 355 return &Symbol{Bind: *bind, Upn: upn} 356} 357 358func (c *Comp) BindUntyped(kind untyped.Kind, value constant.Value) *Bind { 359 untypedlit := untyped.MakeLit(kind, value, &c.Universe.BasicTypes) 360 return &Bind{Lit: Lit{Type: c.TypeOfUntypedLit(), Value: untypedlit}, Desc: ConstBindDescriptor} 361} 362 363// ================================== Symbol, Var, Place ================================= 364 365// Symbol represents a resolved constant, function, variable or builtin 366type Symbol struct { 367 Bind 368 Upn int 369} 370 371func (sym *Symbol) AsVar(opt PlaceOption) *Var { 372 return sym.Bind.AsVar(sym.Upn, opt) 373} 374 375func (sym *Symbol) String() string { 376 return fmt.Sprintf("Symbol{%v %q %v idx=%v upn=%v}", sym.Desc.Class(), sym.Name, sym.Type, sym.Desc.Index(), sym.Upn) 377} 378 379// Var represents a settable variable 380type Var struct { 381 // when Var is embedded in other structs that represent non-identifiers, 382 // Upn and Desc are usually the zero values 383 Upn int 384 Desc BindDescriptor 385 Type xr.Type 386 Name string 387} 388 389func (va *Var) AsSymbol() *Symbol { 390 return &Symbol{ 391 Bind: Bind{ 392 Lit: Lit{Type: va.Type}, 393 Desc: va.Desc, 394 Name: va.Name, 395 }, 396 Upn: va.Upn, 397 } 398} 399 400func (va *Var) AsPlace() *Place { 401 return &Place{Var: *va} 402} 403 404func (va *Var) String() string { 405 return fmt.Sprintf("Var{%v %q %v idx=%v upn=%v}", va.Desc.Class(), va.Name, va.Type, va.Desc.Index(), va.Upn) 406} 407 408// Place represents a settable place or, equivalently, its address 409type Place struct { 410 Var 411 // Fun is nil for variables. 412 // For non-variables, returns a settable and addressable reflect.Value: the place itself. 413 // For map[key], Fun returns the map itself (which may NOT be settable). 414 // Call Fun only once, it may have side effects! 415 Fun func(*Env) r.Value 416 // Addr is nil for variables. 417 // For non-variables, it will return the address of the place. 418 // For map[key], it is nil since map[key] is not addressable 419 // Call Addr only once, it may have side effects! 420 Addr func(*Env) r.Value 421 // used only for map[key], returns key. call it only once, it may have side effects! 422 MapKey func(*Env) r.Value 423 MapType xr.Type 424} 425 426func (place *Place) IsVar() bool { 427 return place.Fun == nil 428} 429 430type PlaceOption bool // the reason why we want a place: either to write into it, or to take its address 431 432const ( 433 PlaceSettable PlaceOption = false 434 PlaceAddress PlaceOption = true 435) 436 437func (opt PlaceOption) String() string { 438 if opt == PlaceAddress { 439 return "cannot take the address of" 440 } else { 441 return "cannot assign to" 442 } 443} 444 445// ================================== Comp, Env ================================= 446 447type CompileOptions int 448 449const ( 450 COptKeepUntyped CompileOptions = 1 << iota // if set, Compile() on expressions will keep all untyped constants as such (in expressions where Go compiler would compute an untyped constant too) 451 COptDefaults CompileOptions = 0 452) 453 454type Code struct { 455 List []Stmt 456 DebugPos []token.Pos // for debugging interpreted code: position of each statement 457 WithDefers bool // true if code contains some defers 458} 459 460type LoopInfo struct { 461 Break *int 462 Continue *int 463 ThisLabels []string // sorted. for labeled "switch" and "for" 464} 465 466func (l *LoopInfo) HasLabel(label string) bool { 467 i := sort.SearchStrings(l.ThisLabels, label) 468 return i >= 0 && i < len(l.ThisLabels) && l.ThisLabels[i] == label 469} 470 471type FuncInfo struct { 472 Name string 473 Param []*Bind 474 Result []*Bind 475 NamedResults bool 476} 477 478const ( 479 poolCapacity = 32 480) 481 482type ExecFlags uint32 483 484const ( 485 EFStartDefer ExecFlags = 1 << iota // true next executed function body is a defer 486 EFDefer // function body being executed is a defer 487 EFDebug // function body is executed with debugging enabled 488) 489 490func (ef ExecFlags) StartDefer() bool { 491 return ef&EFStartDefer != 0 492} 493 494func (ef ExecFlags) IsDefer() bool { 495 return ef&EFDefer != 0 496} 497 498func (ef ExecFlags) IsDebug() bool { 499 return ef&EFDebug != 0 500} 501 502func (ef *ExecFlags) SetDefer(flag bool) { 503 if flag { 504 (*ef) |= EFDefer 505 } else { 506 (*ef) &^= EFDefer 507 } 508} 509 510func (ef *ExecFlags) SetStartDefer(flag bool) { 511 if flag { 512 (*ef) |= EFStartDefer 513 } else { 514 (*ef) &^= EFStartDefer 515 } 516} 517 518func (ef *ExecFlags) SetDebug(flag bool) { 519 if flag { 520 (*ef) |= EFDebug 521 } else { 522 (*ef) &^= EFDebug 523 } 524} 525 526type DebugOp struct { 527 // statements at env.CallDepth < Depth will be executed in single-stepping mode, 528 // i.e. invoking the debugger after every statement 529 Depth int 530 // nil = do not panic. 531 // otherwise, address of value to panic() in order to terminate execution 532 Panic *interface{} 533} 534 535var ( 536 // NEVER modify these! 537 DebugOpContinue = DebugOp{0, nil} 538 DebugOpStep = DebugOp{MaxInt, nil} 539) 540 541type Debugger interface { 542 Breakpoint(ir *Interp, env *Env) DebugOp 543 At(ir *Interp, env *Env) DebugOp 544} 545 546// IrGlobals contains interpreter configuration 547type IrGlobals struct { 548 gls map[uintptr]*Run 549 lock atomic.SpinLock 550 Globals 551} 552 553// Run contains per-goroutine interpreter runtime bookeeping information 554type Run struct { 555 *IrGlobals 556 goid uintptr // owner goroutine id 557 Interrupt Stmt 558 Signals Signals // set by defer, return, breakpoint, debugger and Run.interrupt(os.Signal) 559 ExecFlags ExecFlags 560 CurrEnv *Env // caller of current function. used ONLY at function entry to build call stack 561 InstallDefer func() // defer function to be installed 562 DeferOfFun *Env // function whose defer are running 563 PanicFun *Env // the currently panicking function 564 Panic interface{} // current panic. needed for recover() 565 CmdOpt CmdOpt 566 Debugger Debugger 567 DebugDepth int // depth of function to debug with single-step 568 PoolSize int 569 Pool [poolCapacity]*Env 570} 571 572// CompGlobals contains interpreter compile bookeeping information 573type CompGlobals struct { 574 *IrGlobals 575 Universe *xr.Universe 576 KnownImports map[string]*Import // map[path]*Import cache of known imports 577 interf2proxy map[r.Type]r.Type // interface -> proxy 578 proxy2interf map[r.Type]xr.Type // proxy -> interface 579 Prompt string 580 Jit *Jit 581} 582 583func (cg *CompGlobals) CompileOptions() CompileOptions { 584 var opts CompileOptions 585 if cg.Options&OptKeepUntyped != 0 { 586 opts = COptKeepUntyped 587 } 588 return opts 589} 590 591type CompBinds struct { 592 Binds map[string]*Bind 593 BindNum int // len(Binds) == BindNum + IntBindNum + # of constants 594 IntBindNum int 595 // if address of some Env.Ints[index] was taken, we must honor it: 596 // we can no longer reallocate Env.Ints[], thus we cannot declare IntBind variables 597 // beyond Env.Ints[] capacity. In such case, we set IntBindMax to cap(Env.Ints): 598 // Comp.NewBind() will allocate IntBind variables only up to IntBindMax, 599 // then switch and allocate them as VarBind instead (they are slower and each one allocates memory) 600 IntBindMax int 601 Types map[string]xr.Type 602 Name string // set by "package" directive 603 Path string 604} 605 606// Comp is a tree-of-closures builder: it transforms ast.Nodes into closures 607// for faster execution. Consider it a poor man's compiler (hence the name) 608type Comp struct { 609 *CompGlobals 610 CompBinds 611 // UpCost is the number of *Env.Outer hops to perform at runtime to reach the *Env corresponding to *Comp.Outer 612 // usually equals one. will be zero if this *Comp defines no local variables/functions. 613 UpCost int 614 Depth int 615 Code Code // "compiled" code 616 Loop *LoopInfo // != nil when compiling a for or switch 617 Func *FuncInfo // != nil when compiling a function 618 Labels map[string]*int 619 Outer *Comp 620 FuncMaker *funcMaker // used by debugger command 'backtrace' to obtain function name, type and binds for arguments and results 621} 622 623// ================================= Env ================================= 624 625type EnvBinds struct { 626 Vals []r.Value 627 Ints []uint64 628} 629 630// Env is the interpreter's runtime environment 631type Env struct { 632 EnvBinds 633 Outer *Env 634 IP int 635 Code []Stmt 636 Run *Run 637 FileEnv *Env 638 DebugPos []token.Pos // for debugging interpreted code: position of each statement 639 DebugComp *Comp // for debugging interpreted code: compiler with Binds, and to rebuild an Interp if needed 640 Caller *Env // for debugging interpreted code: previous function in call stack. nil for nested *Env 641 CallDepth int // for debugging interpreted code: depth of call stack 642 UsedByClosure bool // a bitfield would introduce more races among goroutines 643 IntAddressTaken bool // true if &Env.Ints[index] was executed... then we cannot reuse or reallocate Ints 644} 645 646// ================================= Import ================================= 647 648// Import represents an imported package. 649// we cannot name it "Package" because it conflicts with ast2.Package 650type Import struct { 651 // model as a combination of CompBinds and EnvBinds, because to support the command 'package PATH' 652 // we must convert Comp+Env to Import and vice-versa. 653 // This has the added benefit of allowing packages to freely mix 654 // interpreted and compiled constants, functions, variables and types. 655 CompBinds 656 *EnvBinds 657 env *Env 658} 659