github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/compiler.go (about) 1 package goja 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/nuvolaris/goja/token" 8 9 "github.com/nuvolaris/goja/ast" 10 "github.com/nuvolaris/goja/file" 11 "github.com/nuvolaris/goja/unistring" 12 ) 13 14 type blockType int 15 16 const ( 17 blockLoop blockType = iota 18 blockLoopEnum 19 blockTry 20 blockLabel 21 blockSwitch 22 blockWith 23 blockScope 24 blockIterScope 25 blockOptChain 26 ) 27 28 const ( 29 maskConst = 1 << 31 30 maskVar = 1 << 30 31 maskDeletable = 1 << 29 32 maskStrict = maskDeletable 33 34 maskTyp = maskConst | maskVar | maskDeletable 35 ) 36 37 type varType byte 38 39 const ( 40 varTypeVar varType = iota 41 varTypeLet 42 varTypeStrictConst 43 varTypeConst 44 ) 45 46 const thisBindingName = " this" // must not be a valid identifier 47 48 type CompilerError struct { 49 Message string 50 File *file.File 51 Offset int 52 } 53 54 type CompilerSyntaxError struct { 55 CompilerError 56 } 57 58 type CompilerReferenceError struct { 59 CompilerError 60 } 61 62 type srcMapItem struct { 63 pc int 64 srcPos int 65 } 66 67 type Program struct { 68 code []instruction 69 values []Value 70 71 funcName unistring.String 72 src *file.File 73 srcMap []srcMapItem 74 } 75 76 type compiler struct { 77 p *Program 78 scope *scope 79 block *block 80 81 classScope *classScope 82 83 enumGetExpr compiledEnumGetExpr 84 85 evalVM *vm // VM used to evaluate constant expressions 86 ctxVM *vm // VM in which an eval() code is compiled 87 88 codeScratchpad []instruction 89 } 90 91 type binding struct { 92 scope *scope 93 name unistring.String 94 accessPoints map[*scope]*[]int 95 isConst bool 96 isStrict bool 97 isArg bool 98 isVar bool 99 inStash bool 100 } 101 102 func (b *binding) getAccessPointsForScope(s *scope) *[]int { 103 m := b.accessPoints[s] 104 if m == nil { 105 a := make([]int, 0, 1) 106 m = &a 107 if b.accessPoints == nil { 108 b.accessPoints = make(map[*scope]*[]int) 109 } 110 b.accessPoints[s] = m 111 } 112 return m 113 } 114 115 func (b *binding) markAccessPointAt(pos int) { 116 scope := b.scope.c.scope 117 m := b.getAccessPointsForScope(scope) 118 *m = append(*m, pos-scope.base) 119 } 120 121 func (b *binding) markAccessPointAtScope(scope *scope, pos int) { 122 m := b.getAccessPointsForScope(scope) 123 *m = append(*m, pos-scope.base) 124 } 125 126 func (b *binding) markAccessPoint() { 127 scope := b.scope.c.scope 128 m := b.getAccessPointsForScope(scope) 129 *m = append(*m, len(scope.prg.code)-scope.base) 130 } 131 132 func (b *binding) emitGet() { 133 b.markAccessPoint() 134 if b.isVar && !b.isArg { 135 b.scope.c.emit(loadStack(0)) 136 } else { 137 b.scope.c.emit(loadStackLex(0)) 138 } 139 } 140 141 func (b *binding) emitGetAt(pos int) { 142 b.markAccessPointAt(pos) 143 if b.isVar && !b.isArg { 144 b.scope.c.p.code[pos] = loadStack(0) 145 } else { 146 b.scope.c.p.code[pos] = loadStackLex(0) 147 } 148 } 149 150 func (b *binding) emitGetP() { 151 if b.isVar && !b.isArg { 152 // no-op 153 } else { 154 // make sure TDZ is checked 155 b.markAccessPoint() 156 b.scope.c.emit(loadStackLex(0), pop) 157 } 158 } 159 160 func (b *binding) emitSet() { 161 if b.isConst { 162 if b.isStrict || b.scope.c.scope.strict { 163 b.scope.c.emit(throwAssignToConst) 164 } 165 return 166 } 167 b.markAccessPoint() 168 if b.isVar && !b.isArg { 169 b.scope.c.emit(storeStack(0)) 170 } else { 171 b.scope.c.emit(storeStackLex(0)) 172 } 173 } 174 175 func (b *binding) emitSetP() { 176 if b.isConst { 177 if b.isStrict || b.scope.c.scope.strict { 178 b.scope.c.emit(throwAssignToConst) 179 } 180 return 181 } 182 b.markAccessPoint() 183 if b.isVar && !b.isArg { 184 b.scope.c.emit(storeStackP(0)) 185 } else { 186 b.scope.c.emit(storeStackLexP(0)) 187 } 188 } 189 190 func (b *binding) emitInitP() { 191 if !b.isVar && b.scope.outer == nil { 192 b.scope.c.emit(initGlobalP(b.name)) 193 } else { 194 b.markAccessPoint() 195 b.scope.c.emit(initStackP(0)) 196 } 197 } 198 199 func (b *binding) emitInit() { 200 if !b.isVar && b.scope.outer == nil { 201 b.scope.c.emit(initGlobal(b.name)) 202 } else { 203 b.markAccessPoint() 204 b.scope.c.emit(initStack(0)) 205 } 206 } 207 208 func (b *binding) emitInitAt(pos int) { 209 if !b.isVar && b.scope.outer == nil { 210 b.scope.c.p.code[pos] = initGlobal(b.name) 211 } else { 212 b.markAccessPointAt(pos) 213 b.scope.c.p.code[pos] = initStack(0) 214 } 215 } 216 217 func (b *binding) emitInitAtScope(scope *scope, pos int) { 218 if !b.isVar && scope.outer == nil { 219 scope.c.p.code[pos] = initGlobal(b.name) 220 } else { 221 b.markAccessPointAtScope(scope, pos) 222 scope.c.p.code[pos] = initStack(0) 223 } 224 } 225 226 func (b *binding) emitInitPAtScope(scope *scope, pos int) { 227 if !b.isVar && scope.outer == nil { 228 scope.c.p.code[pos] = initGlobalP(b.name) 229 } else { 230 b.markAccessPointAtScope(scope, pos) 231 scope.c.p.code[pos] = initStackP(0) 232 } 233 } 234 235 func (b *binding) emitGetVar(callee bool) { 236 b.markAccessPoint() 237 if b.isVar && !b.isArg { 238 b.scope.c.emit(&loadMixed{name: b.name, callee: callee}) 239 } else { 240 b.scope.c.emit(&loadMixedLex{name: b.name, callee: callee}) 241 } 242 } 243 244 func (b *binding) emitResolveVar(strict bool) { 245 b.markAccessPoint() 246 if b.isVar && !b.isArg { 247 b.scope.c.emit(&resolveMixed{name: b.name, strict: strict, typ: varTypeVar}) 248 } else { 249 var typ varType 250 if b.isConst { 251 if b.isStrict { 252 typ = varTypeStrictConst 253 } else { 254 typ = varTypeConst 255 } 256 } else { 257 typ = varTypeLet 258 } 259 b.scope.c.emit(&resolveMixed{name: b.name, strict: strict, typ: typ}) 260 } 261 } 262 263 func (b *binding) moveToStash() { 264 if b.isArg && !b.scope.argsInStash { 265 b.scope.moveArgsToStash() 266 } else { 267 b.inStash = true 268 b.scope.needStash = true 269 } 270 } 271 272 func (b *binding) useCount() (count int) { 273 for _, a := range b.accessPoints { 274 count += len(*a) 275 } 276 return 277 } 278 279 type scope struct { 280 c *compiler 281 prg *Program 282 outer *scope 283 nested []*scope 284 boundNames map[unistring.String]*binding 285 bindings []*binding 286 base int 287 numArgs int 288 289 // function type. If not funcNone, this is a function or a top-level lexical environment 290 funcType funcType 291 292 // in strict mode 293 strict bool 294 // eval top-level scope 295 eval bool 296 // at least one inner scope has direct eval() which can lookup names dynamically (by name) 297 dynLookup bool 298 // at least one binding has been marked for placement in stash 299 needStash bool 300 301 // is a variable environment, i.e. the target for dynamically created var bindings 302 variable bool 303 // a function scope that has at least one direct eval() and non-strict, so the variables can be added dynamically 304 dynamic bool 305 // arguments have been marked for placement in stash (functions only) 306 argsInStash bool 307 // need 'arguments' object (functions only) 308 argsNeeded bool 309 } 310 311 type block struct { 312 typ blockType 313 label unistring.String 314 cont int 315 breaks []int 316 conts []int 317 outer *block 318 breaking *block // set when the 'finally' block is an empty break statement sequence 319 needResult bool 320 } 321 322 func (c *compiler) leaveScopeBlock(enter *enterBlock) { 323 c.updateEnterBlock(enter) 324 leave := &leaveBlock{ 325 stackSize: enter.stackSize, 326 popStash: enter.stashSize > 0, 327 } 328 c.emit(leave) 329 for _, pc := range c.block.breaks { 330 c.p.code[pc] = leave 331 } 332 c.block.breaks = nil 333 c.leaveBlock() 334 } 335 336 func (c *compiler) leaveBlock() { 337 lbl := len(c.p.code) 338 for _, item := range c.block.breaks { 339 c.p.code[item] = jump(lbl - item) 340 } 341 if t := c.block.typ; t == blockLoop || t == blockLoopEnum { 342 for _, item := range c.block.conts { 343 c.p.code[item] = jump(c.block.cont - item) 344 } 345 } 346 c.block = c.block.outer 347 } 348 349 func (e *CompilerSyntaxError) Error() string { 350 if e.File != nil { 351 return fmt.Sprintf("SyntaxError: %s at %s", e.Message, e.File.Position(e.Offset)) 352 } 353 return fmt.Sprintf("SyntaxError: %s", e.Message) 354 } 355 356 func (e *CompilerReferenceError) Error() string { 357 return fmt.Sprintf("ReferenceError: %s", e.Message) 358 } 359 360 func (c *compiler) newScope() { 361 strict := false 362 if c.scope != nil { 363 strict = c.scope.strict 364 } 365 c.scope = &scope{ 366 c: c, 367 prg: c.p, 368 outer: c.scope, 369 strict: strict, 370 } 371 } 372 373 func (c *compiler) newBlockScope() { 374 c.newScope() 375 if outer := c.scope.outer; outer != nil { 376 outer.nested = append(outer.nested, c.scope) 377 } 378 c.scope.base = len(c.p.code) 379 } 380 381 func (c *compiler) popScope() { 382 c.scope = c.scope.outer 383 } 384 385 func newCompiler() *compiler { 386 c := &compiler{ 387 p: &Program{}, 388 } 389 390 c.enumGetExpr.init(c, file.Idx(0)) 391 392 return c 393 } 394 395 func (p *Program) defineLiteralValue(val Value) uint32 { 396 for idx, v := range p.values { 397 if v.SameAs(val) { 398 return uint32(idx) 399 } 400 } 401 idx := uint32(len(p.values)) 402 p.values = append(p.values, val) 403 return idx 404 } 405 406 func (p *Program) dumpCode(logger func(format string, args ...interface{})) { 407 p._dumpCode("", logger) 408 } 409 410 func (p *Program) _dumpCode(indent string, logger func(format string, args ...interface{})) { 411 logger("values: %+v", p.values) 412 dumpInitFields := func(initFields *Program) { 413 i := indent + ">" 414 logger("%s ---- init_fields:", i) 415 initFields._dumpCode(i, logger) 416 logger("%s ----", i) 417 } 418 for pc, ins := range p.code { 419 logger("%s %d: %T(%v)", indent, pc, ins, ins) 420 var prg *Program 421 switch f := ins.(type) { 422 case newFuncInstruction: 423 prg = f.getPrg() 424 case *newDerivedClass: 425 if f.initFields != nil { 426 dumpInitFields(f.initFields) 427 } 428 prg = f.ctor 429 case *newClass: 430 if f.initFields != nil { 431 dumpInitFields(f.initFields) 432 } 433 prg = f.ctor 434 case *newStaticFieldInit: 435 if f.initFields != nil { 436 dumpInitFields(f.initFields) 437 } 438 } 439 if prg != nil { 440 prg._dumpCode(indent+">", logger) 441 } 442 } 443 } 444 445 func (p *Program) sourceOffset(pc int) int { 446 i := sort.Search(len(p.srcMap), func(idx int) bool { 447 return p.srcMap[idx].pc > pc 448 }) - 1 449 if i >= 0 { 450 return p.srcMap[i].srcPos 451 } 452 453 return 0 454 } 455 456 func (p *Program) addSrcMap(srcPos int) { 457 if len(p.srcMap) > 0 && p.srcMap[len(p.srcMap)-1].srcPos == srcPos { 458 return 459 } 460 p.srcMap = append(p.srcMap, srcMapItem{pc: len(p.code), srcPos: srcPos}) 461 } 462 463 func (s *scope) lookupName(name unistring.String) (binding *binding, noDynamics bool) { 464 noDynamics = true 465 toStash := false 466 for curScope := s; ; curScope = curScope.outer { 467 if curScope.outer != nil { 468 if b, exists := curScope.boundNames[name]; exists { 469 if toStash && !b.inStash { 470 b.moveToStash() 471 } 472 binding = b 473 return 474 } 475 } else { 476 noDynamics = false 477 return 478 } 479 if curScope.dynamic { 480 noDynamics = false 481 } 482 if name == "arguments" && curScope.funcType != funcNone && curScope.funcType != funcArrow { 483 if curScope.funcType == funcClsInit { 484 s.c.throwSyntaxError(0, "'arguments' is not allowed in class field initializer or static initialization block") 485 } 486 curScope.argsNeeded = true 487 binding, _ = curScope.bindName(name) 488 return 489 } 490 if curScope.isFunction() { 491 toStash = true 492 } 493 } 494 } 495 496 func (s *scope) lookupThis() (*binding, bool) { 497 toStash := false 498 for curScope := s; curScope != nil; curScope = curScope.outer { 499 if curScope.outer == nil { 500 if curScope.eval { 501 return nil, true 502 } 503 } 504 if b, exists := curScope.boundNames[thisBindingName]; exists { 505 if toStash && !b.inStash { 506 b.moveToStash() 507 } 508 return b, false 509 } 510 if curScope.isFunction() { 511 toStash = true 512 } 513 } 514 return nil, false 515 } 516 517 func (s *scope) ensureBoundNamesCreated() { 518 if s.boundNames == nil { 519 s.boundNames = make(map[unistring.String]*binding) 520 } 521 } 522 523 func (s *scope) addBinding(offset int) *binding { 524 if len(s.bindings) >= (1<<24)-1 { 525 s.c.throwSyntaxError(offset, "Too many variables") 526 } 527 b := &binding{ 528 scope: s, 529 } 530 s.bindings = append(s.bindings, b) 531 return b 532 } 533 534 func (s *scope) bindNameLexical(name unistring.String, unique bool, offset int) (*binding, bool) { 535 if b := s.boundNames[name]; b != nil { 536 if unique { 537 s.c.throwSyntaxError(offset, "Identifier '%s' has already been declared", name) 538 } 539 return b, false 540 } 541 b := s.addBinding(offset) 542 b.name = name 543 s.ensureBoundNamesCreated() 544 s.boundNames[name] = b 545 return b, true 546 } 547 548 func (s *scope) createThisBinding() *binding { 549 thisBinding, _ := s.bindNameLexical(thisBindingName, false, 0) 550 thisBinding.isVar = true // don't check on load 551 return thisBinding 552 } 553 554 func (s *scope) bindName(name unistring.String) (*binding, bool) { 555 if !s.isFunction() && !s.variable && s.outer != nil { 556 return s.outer.bindName(name) 557 } 558 b, created := s.bindNameLexical(name, false, 0) 559 if created { 560 b.isVar = true 561 } 562 return b, created 563 } 564 565 func (s *scope) bindNameShadow(name unistring.String) (*binding, bool) { 566 if !s.isFunction() && s.outer != nil { 567 return s.outer.bindNameShadow(name) 568 } 569 570 _, exists := s.boundNames[name] 571 b := &binding{ 572 scope: s, 573 name: name, 574 } 575 s.bindings = append(s.bindings, b) 576 s.ensureBoundNamesCreated() 577 s.boundNames[name] = b 578 return b, !exists 579 } 580 581 func (s *scope) nearestFunction() *scope { 582 for sc := s; sc != nil; sc = sc.outer { 583 if sc.isFunction() { 584 return sc 585 } 586 } 587 return nil 588 } 589 590 func (s *scope) nearestThis() *scope { 591 for sc := s; sc != nil; sc = sc.outer { 592 if sc.eval || sc.isFunction() && sc.funcType != funcArrow { 593 return sc 594 } 595 } 596 return nil 597 } 598 599 func (s *scope) finaliseVarAlloc(stackOffset int) (stashSize, stackSize int) { 600 argsInStash := false 601 if f := s.nearestFunction(); f != nil { 602 argsInStash = f.argsInStash 603 } 604 stackIdx, stashIdx := 0, 0 605 allInStash := s.isDynamic() 606 var derivedCtor bool 607 if fs := s.nearestThis(); fs != nil && fs.funcType == funcDerivedCtor { 608 derivedCtor = true 609 } 610 for i, b := range s.bindings { 611 var this bool 612 if b.name == thisBindingName { 613 this = true 614 } 615 if allInStash || b.inStash { 616 for scope, aps := range b.accessPoints { 617 var level uint32 618 for sc := scope; sc != nil && sc != s; sc = sc.outer { 619 if sc.needStash || sc.isDynamic() { 620 level++ 621 } 622 } 623 if level > 255 { 624 s.c.throwSyntaxError(0, "Maximum nesting level (256) exceeded") 625 } 626 idx := (level << 24) | uint32(stashIdx) 627 base := scope.base 628 code := scope.prg.code 629 if this { 630 if derivedCtor { 631 for _, pc := range *aps { 632 ap := &code[base+pc] 633 switch (*ap).(type) { 634 case loadStack: 635 *ap = loadThisStash(idx) 636 case initStack: 637 *ap = initStash(idx) 638 case resolveThisStack: 639 *ap = resolveThisStash(idx) 640 case _ret: 641 *ap = cret(idx) 642 default: 643 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'") 644 } 645 } 646 } else { 647 for _, pc := range *aps { 648 ap := &code[base+pc] 649 switch (*ap).(type) { 650 case loadStack: 651 *ap = loadStash(idx) 652 case initStack: 653 *ap = initStash(idx) 654 default: 655 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'") 656 } 657 } 658 } 659 } else { 660 for _, pc := range *aps { 661 ap := &code[base+pc] 662 switch i := (*ap).(type) { 663 case loadStack: 664 *ap = loadStash(idx) 665 case storeStack: 666 *ap = storeStash(idx) 667 case storeStackP: 668 *ap = storeStashP(idx) 669 case loadStackLex: 670 *ap = loadStashLex(idx) 671 case storeStackLex: 672 *ap = storeStashLex(idx) 673 case storeStackLexP: 674 *ap = storeStashLexP(idx) 675 case initStackP: 676 *ap = initStashP(idx) 677 case initStack: 678 *ap = initStash(idx) 679 case *loadMixed: 680 i.idx = idx 681 case *loadMixedLex: 682 i.idx = idx 683 case *resolveMixed: 684 i.idx = idx 685 default: 686 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i) 687 } 688 } 689 } 690 } 691 stashIdx++ 692 } else { 693 var idx int 694 if !this { 695 if i < s.numArgs { 696 idx = -(i + 1) 697 } else { 698 stackIdx++ 699 idx = stackIdx + stackOffset 700 } 701 } 702 for scope, aps := range b.accessPoints { 703 var level int 704 for sc := scope; sc != nil && sc != s; sc = sc.outer { 705 if sc.needStash || sc.isDynamic() { 706 level++ 707 } 708 } 709 if level > 255 { 710 s.c.throwSyntaxError(0, "Maximum nesting level (256) exceeded") 711 } 712 code := scope.prg.code 713 base := scope.base 714 if this { 715 if derivedCtor { 716 for _, pc := range *aps { 717 ap := &code[base+pc] 718 switch (*ap).(type) { 719 case loadStack: 720 *ap = loadThisStack{} 721 case initStack: 722 // no-op 723 case resolveThisStack: 724 // no-op 725 case _ret: 726 // no-op, already in the right place 727 default: 728 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'") 729 } 730 } 731 } /*else { 732 no-op 733 }*/ 734 } else if argsInStash { 735 for _, pc := range *aps { 736 ap := &code[base+pc] 737 switch i := (*ap).(type) { 738 case loadStack: 739 *ap = loadStack1(idx) 740 case storeStack: 741 *ap = storeStack1(idx) 742 case storeStackP: 743 *ap = storeStack1P(idx) 744 case loadStackLex: 745 *ap = loadStack1Lex(idx) 746 case storeStackLex: 747 *ap = storeStack1Lex(idx) 748 case storeStackLexP: 749 *ap = storeStack1LexP(idx) 750 case initStackP: 751 *ap = initStack1P(idx) 752 case initStack: 753 *ap = initStack1(idx) 754 case *loadMixed: 755 *ap = &loadMixedStack1{name: i.name, idx: idx, level: uint8(level), callee: i.callee} 756 case *loadMixedLex: 757 *ap = &loadMixedStack1Lex{name: i.name, idx: idx, level: uint8(level), callee: i.callee} 758 case *resolveMixed: 759 *ap = &resolveMixedStack1{typ: i.typ, name: i.name, idx: idx, level: uint8(level), strict: i.strict} 760 default: 761 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i) 762 } 763 } 764 } else { 765 for _, pc := range *aps { 766 ap := &code[base+pc] 767 switch i := (*ap).(type) { 768 case loadStack: 769 *ap = loadStack(idx) 770 case storeStack: 771 *ap = storeStack(idx) 772 case storeStackP: 773 *ap = storeStackP(idx) 774 case loadStackLex: 775 *ap = loadStackLex(idx) 776 case storeStackLex: 777 *ap = storeStackLex(idx) 778 case storeStackLexP: 779 *ap = storeStackLexP(idx) 780 case initStack: 781 *ap = initStack(idx) 782 case initStackP: 783 *ap = initStackP(idx) 784 case *loadMixed: 785 *ap = &loadMixedStack{name: i.name, idx: idx, level: uint8(level), callee: i.callee} 786 case *loadMixedLex: 787 *ap = &loadMixedStackLex{name: i.name, idx: idx, level: uint8(level), callee: i.callee} 788 case *resolveMixed: 789 *ap = &resolveMixedStack{typ: i.typ, name: i.name, idx: idx, level: uint8(level), strict: i.strict} 790 default: 791 s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i) 792 } 793 } 794 } 795 } 796 } 797 } 798 for _, nested := range s.nested { 799 nested.finaliseVarAlloc(stackIdx + stackOffset) 800 } 801 return stashIdx, stackIdx 802 } 803 804 func (s *scope) moveArgsToStash() { 805 for _, b := range s.bindings { 806 if !b.isArg { 807 break 808 } 809 b.inStash = true 810 } 811 s.argsInStash = true 812 s.needStash = true 813 } 814 815 func (c *compiler) trimCode(delta int) { 816 src := c.p.code[delta:] 817 newCode := make([]instruction, len(src)) 818 copy(newCode, src) 819 if cap(c.codeScratchpad) < cap(c.p.code) { 820 c.codeScratchpad = c.p.code[:0] 821 } 822 c.p.code = newCode 823 } 824 825 func (s *scope) trimCode(delta int) { 826 s.c.trimCode(delta) 827 if delta != 0 { 828 srcMap := s.c.p.srcMap 829 for i := range srcMap { 830 srcMap[i].pc -= delta 831 } 832 s.adjustBase(-delta) 833 } 834 } 835 836 func (s *scope) adjustBase(delta int) { 837 s.base += delta 838 for _, nested := range s.nested { 839 nested.adjustBase(delta) 840 } 841 } 842 843 func (s *scope) makeNamesMap() map[unistring.String]uint32 { 844 l := len(s.bindings) 845 if l == 0 { 846 return nil 847 } 848 names := make(map[unistring.String]uint32, l) 849 for i, b := range s.bindings { 850 idx := uint32(i) 851 if b.isConst { 852 idx |= maskConst 853 if b.isStrict { 854 idx |= maskStrict 855 } 856 } 857 if b.isVar { 858 idx |= maskVar 859 } 860 names[b.name] = idx 861 } 862 return names 863 } 864 865 func (s *scope) isDynamic() bool { 866 return s.dynLookup || s.dynamic 867 } 868 869 func (s *scope) isFunction() bool { 870 return s.funcType != funcNone && !s.eval 871 } 872 873 func (s *scope) deleteBinding(b *binding) { 874 idx := 0 875 for i, bb := range s.bindings { 876 if bb == b { 877 idx = i 878 goto found 879 } 880 } 881 return 882 found: 883 delete(s.boundNames, b.name) 884 copy(s.bindings[idx:], s.bindings[idx+1:]) 885 l := len(s.bindings) - 1 886 s.bindings[l] = nil 887 s.bindings = s.bindings[:l] 888 } 889 890 func (c *compiler) compile(in *ast.Program, strict, inGlobal bool, evalVm *vm) { 891 c.ctxVM = evalVm 892 893 eval := evalVm != nil 894 c.p.src = in.File 895 c.newScope() 896 scope := c.scope 897 scope.dynamic = true 898 scope.eval = eval 899 if !strict && len(in.Body) > 0 { 900 strict = c.isStrict(in.Body) != nil 901 } 902 scope.strict = strict 903 ownVarScope := eval && strict 904 ownLexScope := !inGlobal || eval 905 if ownVarScope { 906 c.newBlockScope() 907 scope = c.scope 908 scope.variable = true 909 } 910 if eval && !inGlobal { 911 for s := evalVm.stash; s != nil; s = s.outer { 912 if ft := s.funcType; ft != funcNone && ft != funcArrow { 913 scope.funcType = ft 914 break 915 } 916 } 917 } 918 funcs := c.extractFunctions(in.Body) 919 c.createFunctionBindings(funcs) 920 numFuncs := len(scope.bindings) 921 if inGlobal && !ownVarScope { 922 if numFuncs == len(funcs) { 923 c.compileFunctionsGlobalAllUnique(funcs) 924 } else { 925 c.compileFunctionsGlobal(funcs) 926 } 927 } 928 c.compileDeclList(in.DeclarationList, false) 929 numVars := len(scope.bindings) - numFuncs 930 vars := make([]unistring.String, len(scope.bindings)) 931 for i, b := range scope.bindings { 932 vars[i] = b.name 933 } 934 if len(vars) > 0 && !ownVarScope && ownLexScope { 935 if inGlobal { 936 c.emit(&bindGlobal{ 937 vars: vars[numFuncs:], 938 funcs: vars[:numFuncs], 939 deletable: eval, 940 }) 941 } else { 942 c.emit(&bindVars{names: vars, deletable: eval}) 943 } 944 } 945 var enter *enterBlock 946 if c.compileLexicalDeclarations(in.Body, ownVarScope || !ownLexScope) { 947 if ownLexScope { 948 c.block = &block{ 949 outer: c.block, 950 typ: blockScope, 951 needResult: true, 952 } 953 enter = &enterBlock{} 954 c.emit(enter) 955 } 956 } 957 if len(scope.bindings) > 0 && !ownLexScope { 958 var lets, consts []unistring.String 959 for _, b := range c.scope.bindings[numFuncs+numVars:] { 960 if b.isConst { 961 consts = append(consts, b.name) 962 } else { 963 lets = append(lets, b.name) 964 } 965 } 966 c.emit(&bindGlobal{ 967 vars: vars[numFuncs:], 968 funcs: vars[:numFuncs], 969 lets: lets, 970 consts: consts, 971 }) 972 } 973 if !inGlobal || ownVarScope { 974 c.compileFunctions(funcs) 975 } 976 c.compileStatements(in.Body, true) 977 if enter != nil { 978 c.leaveScopeBlock(enter) 979 c.popScope() 980 } 981 982 scope.finaliseVarAlloc(0) 983 } 984 985 func (c *compiler) compileDeclList(v []*ast.VariableDeclaration, inFunc bool) { 986 for _, value := range v { 987 c.createVarBindings(value, inFunc) 988 } 989 } 990 991 func (c *compiler) extractLabelled(st ast.Statement) ast.Statement { 992 if st, ok := st.(*ast.LabelledStatement); ok { 993 return c.extractLabelled(st.Statement) 994 } 995 return st 996 } 997 998 func (c *compiler) extractFunctions(list []ast.Statement) (funcs []*ast.FunctionDeclaration) { 999 for _, st := range list { 1000 var decl *ast.FunctionDeclaration 1001 switch st := c.extractLabelled(st).(type) { 1002 case *ast.FunctionDeclaration: 1003 decl = st 1004 case *ast.LabelledStatement: 1005 if st1, ok := st.Statement.(*ast.FunctionDeclaration); ok { 1006 decl = st1 1007 } else { 1008 continue 1009 } 1010 default: 1011 continue 1012 } 1013 funcs = append(funcs, decl) 1014 } 1015 return 1016 } 1017 1018 func (c *compiler) createFunctionBindings(funcs []*ast.FunctionDeclaration) { 1019 s := c.scope 1020 if s.outer != nil { 1021 unique := !s.isFunction() && !s.variable && s.strict 1022 if !unique { 1023 hasNonStandard := false 1024 for _, decl := range funcs { 1025 if !decl.Function.Async && !decl.Function.Generator { 1026 s.bindNameLexical(decl.Function.Name.Name, false, int(decl.Function.Name.Idx1())-1) 1027 } else { 1028 hasNonStandard = true 1029 } 1030 } 1031 if hasNonStandard { 1032 for _, decl := range funcs { 1033 if decl.Function.Async || decl.Function.Generator { 1034 s.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1) 1035 } 1036 } 1037 } 1038 } else { 1039 for _, decl := range funcs { 1040 s.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1) 1041 } 1042 } 1043 } else { 1044 for _, decl := range funcs { 1045 s.bindName(decl.Function.Name.Name) 1046 } 1047 } 1048 } 1049 1050 func (c *compiler) compileFunctions(list []*ast.FunctionDeclaration) { 1051 for _, decl := range list { 1052 c.compileFunction(decl) 1053 } 1054 } 1055 1056 func (c *compiler) compileFunctionsGlobalAllUnique(list []*ast.FunctionDeclaration) { 1057 for _, decl := range list { 1058 c.compileFunctionLiteral(decl.Function, false).emitGetter(true) 1059 } 1060 } 1061 1062 func (c *compiler) compileFunctionsGlobal(list []*ast.FunctionDeclaration) { 1063 m := make(map[unistring.String]int, len(list)) 1064 for i := len(list) - 1; i >= 0; i-- { 1065 name := list[i].Function.Name.Name 1066 if _, exists := m[name]; !exists { 1067 m[name] = i 1068 } 1069 } 1070 idx := 0 1071 for i, decl := range list { 1072 name := decl.Function.Name.Name 1073 if m[name] == i { 1074 c.compileFunctionLiteral(decl.Function, false).emitGetter(true) 1075 c.scope.bindings[idx] = c.scope.boundNames[name] 1076 idx++ 1077 } else { 1078 leave := c.enterDummyMode() 1079 c.compileFunctionLiteral(decl.Function, false).emitGetter(false) 1080 leave() 1081 } 1082 } 1083 } 1084 1085 func (c *compiler) createVarIdBinding(name unistring.String, offset int, inFunc bool) { 1086 if c.scope.strict { 1087 c.checkIdentifierLName(name, offset) 1088 c.checkIdentifierName(name, offset) 1089 } 1090 if !inFunc || name != "arguments" { 1091 c.scope.bindName(name) 1092 } 1093 } 1094 1095 func (c *compiler) createBindings(target ast.Expression, createIdBinding func(name unistring.String, offset int)) { 1096 switch target := target.(type) { 1097 case *ast.Identifier: 1098 createIdBinding(target.Name, int(target.Idx)-1) 1099 case *ast.ObjectPattern: 1100 for _, prop := range target.Properties { 1101 switch prop := prop.(type) { 1102 case *ast.PropertyShort: 1103 createIdBinding(prop.Name.Name, int(prop.Name.Idx)-1) 1104 case *ast.PropertyKeyed: 1105 c.createBindings(prop.Value, createIdBinding) 1106 default: 1107 c.throwSyntaxError(int(target.Idx0()-1), "unsupported property type in ObjectPattern: %T", prop) 1108 } 1109 } 1110 if target.Rest != nil { 1111 c.createBindings(target.Rest, createIdBinding) 1112 } 1113 case *ast.ArrayPattern: 1114 for _, elt := range target.Elements { 1115 if elt != nil { 1116 c.createBindings(elt, createIdBinding) 1117 } 1118 } 1119 if target.Rest != nil { 1120 c.createBindings(target.Rest, createIdBinding) 1121 } 1122 case *ast.AssignExpression: 1123 c.createBindings(target.Left, createIdBinding) 1124 default: 1125 c.throwSyntaxError(int(target.Idx0()-1), "unsupported binding target: %T", target) 1126 } 1127 } 1128 1129 func (c *compiler) createVarBinding(target ast.Expression, inFunc bool) { 1130 c.createBindings(target, func(name unistring.String, offset int) { 1131 c.createVarIdBinding(name, offset, inFunc) 1132 }) 1133 } 1134 1135 func (c *compiler) createVarBindings(v *ast.VariableDeclaration, inFunc bool) { 1136 for _, item := range v.List { 1137 c.createVarBinding(item.Target, inFunc) 1138 } 1139 } 1140 1141 func (c *compiler) createLexicalIdBinding(name unistring.String, isConst bool, offset int) *binding { 1142 if name == "let" { 1143 c.throwSyntaxError(offset, "let is disallowed as a lexically bound name") 1144 } 1145 if c.scope.strict { 1146 c.checkIdentifierLName(name, offset) 1147 c.checkIdentifierName(name, offset) 1148 } 1149 b, _ := c.scope.bindNameLexical(name, true, offset) 1150 if isConst { 1151 b.isConst, b.isStrict = true, true 1152 } 1153 return b 1154 } 1155 1156 func (c *compiler) createLexicalIdBindingFuncBody(name unistring.String, isConst bool, offset int, calleeBinding *binding) *binding { 1157 if name == "let" { 1158 c.throwSyntaxError(offset, "let is disallowed as a lexically bound name") 1159 } 1160 if c.scope.strict { 1161 c.checkIdentifierLName(name, offset) 1162 c.checkIdentifierName(name, offset) 1163 } 1164 paramScope := c.scope.outer 1165 parentBinding := paramScope.boundNames[name] 1166 if parentBinding != nil { 1167 if parentBinding != calleeBinding && (name != "arguments" || !paramScope.argsNeeded) { 1168 c.throwSyntaxError(offset, "Identifier '%s' has already been declared", name) 1169 } 1170 } 1171 b, _ := c.scope.bindNameLexical(name, true, offset) 1172 if isConst { 1173 b.isConst, b.isStrict = true, true 1174 } 1175 return b 1176 } 1177 1178 func (c *compiler) createLexicalBinding(target ast.Expression, isConst bool) { 1179 c.createBindings(target, func(name unistring.String, offset int) { 1180 c.createLexicalIdBinding(name, isConst, offset) 1181 }) 1182 } 1183 1184 func (c *compiler) createLexicalBindings(lex *ast.LexicalDeclaration) { 1185 for _, d := range lex.List { 1186 c.createLexicalBinding(d.Target, lex.Token == token.CONST) 1187 } 1188 } 1189 1190 func (c *compiler) compileLexicalDeclarations(list []ast.Statement, scopeDeclared bool) bool { 1191 for _, st := range list { 1192 if lex, ok := st.(*ast.LexicalDeclaration); ok { 1193 if !scopeDeclared { 1194 c.newBlockScope() 1195 scopeDeclared = true 1196 } 1197 c.createLexicalBindings(lex) 1198 } else if cls, ok := st.(*ast.ClassDeclaration); ok { 1199 if !scopeDeclared { 1200 c.newBlockScope() 1201 scopeDeclared = true 1202 } 1203 c.createLexicalIdBinding(cls.Class.Name.Name, false, int(cls.Class.Name.Idx)-1) 1204 } 1205 } 1206 return scopeDeclared 1207 } 1208 1209 func (c *compiler) compileLexicalDeclarationsFuncBody(list []ast.Statement, calleeBinding *binding) { 1210 for _, st := range list { 1211 if lex, ok := st.(*ast.LexicalDeclaration); ok { 1212 isConst := lex.Token == token.CONST 1213 for _, d := range lex.List { 1214 c.createBindings(d.Target, func(name unistring.String, offset int) { 1215 c.createLexicalIdBindingFuncBody(name, isConst, offset, calleeBinding) 1216 }) 1217 } 1218 } 1219 } 1220 } 1221 1222 func (c *compiler) compileFunction(v *ast.FunctionDeclaration) { 1223 name := v.Function.Name.Name 1224 b := c.scope.boundNames[name] 1225 if b == nil || b.isVar { 1226 e := &compiledIdentifierExpr{ 1227 name: v.Function.Name.Name, 1228 } 1229 e.init(c, v.Function.Idx0()) 1230 e.emitSetter(c.compileFunctionLiteral(v.Function, false), false) 1231 } else { 1232 c.compileFunctionLiteral(v.Function, false).emitGetter(true) 1233 b.emitInitP() 1234 } 1235 } 1236 1237 func (c *compiler) compileStandaloneFunctionDecl(v *ast.FunctionDeclaration) { 1238 if v.Function.Async { 1239 c.throwSyntaxError(int(v.Idx0())-1, "Async functions can only be declared at top level or inside a block.") 1240 } 1241 if v.Function.Generator { 1242 c.throwSyntaxError(int(v.Idx0())-1, "Generators can only be declared at top level or inside a block.") 1243 } 1244 if c.scope.strict { 1245 c.throwSyntaxError(int(v.Idx0())-1, "In strict mode code, functions can only be declared at top level or inside a block.") 1246 } 1247 c.throwSyntaxError(int(v.Idx0())-1, "In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement.") 1248 } 1249 1250 func (c *compiler) emit(instructions ...instruction) { 1251 c.p.code = append(c.p.code, instructions...) 1252 } 1253 1254 func (c *compiler) throwSyntaxError(offset int, format string, args ...interface{}) { 1255 panic(&CompilerSyntaxError{ 1256 CompilerError: CompilerError{ 1257 File: c.p.src, 1258 Offset: offset, 1259 Message: fmt.Sprintf(format, args...), 1260 }, 1261 }) 1262 } 1263 1264 func (c *compiler) isStrict(list []ast.Statement) *ast.StringLiteral { 1265 for _, st := range list { 1266 if st, ok := st.(*ast.ExpressionStatement); ok { 1267 if e, ok := st.Expression.(*ast.StringLiteral); ok { 1268 if e.Literal == `"use strict"` || e.Literal == `'use strict'` { 1269 return e 1270 } 1271 } else { 1272 break 1273 } 1274 } else { 1275 break 1276 } 1277 } 1278 return nil 1279 } 1280 1281 func (c *compiler) isStrictStatement(s ast.Statement) *ast.StringLiteral { 1282 if s, ok := s.(*ast.BlockStatement); ok { 1283 return c.isStrict(s.List) 1284 } 1285 return nil 1286 } 1287 1288 func (c *compiler) checkIdentifierName(name unistring.String, offset int) { 1289 switch name { 1290 case "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield": 1291 c.throwSyntaxError(offset, "Unexpected strict mode reserved word") 1292 } 1293 } 1294 1295 func (c *compiler) checkIdentifierLName(name unistring.String, offset int) { 1296 switch name { 1297 case "eval", "arguments": 1298 c.throwSyntaxError(offset, "Assignment to eval or arguments is not allowed in strict mode") 1299 } 1300 } 1301 1302 // Enter a 'dummy' compilation mode. Any code produced after this method is called will be discarded after 1303 // leaveFunc is called with no additional side effects. This is useful for compiling code inside a 1304 // constant falsy condition 'if' branch or a loop (i.e 'if (false) { ... } or while (false) { ... }). 1305 // Such code should not be included in the final compilation result as it's never called, but it must 1306 // still produce compilation errors if there are any. 1307 // TODO: make sure variable lookups do not de-optimise parent scopes 1308 func (c *compiler) enterDummyMode() (leaveFunc func()) { 1309 savedBlock, savedProgram := c.block, c.p 1310 if savedBlock != nil { 1311 c.block = &block{ 1312 typ: savedBlock.typ, 1313 label: savedBlock.label, 1314 outer: savedBlock.outer, 1315 breaking: savedBlock.breaking, 1316 } 1317 } 1318 c.p = &Program{ 1319 src: c.p.src, 1320 } 1321 c.newScope() 1322 return func() { 1323 c.block, c.p = savedBlock, savedProgram 1324 c.popScope() 1325 } 1326 } 1327 1328 func (c *compiler) compileStatementDummy(statement ast.Statement) { 1329 leave := c.enterDummyMode() 1330 c.compileStatement(statement, false) 1331 leave() 1332 } 1333 1334 func (c *compiler) assert(cond bool, offset int, msg string, args ...interface{}) { 1335 if !cond { 1336 c.throwSyntaxError(offset, "Compiler bug: "+msg, args...) 1337 } 1338 } 1339 1340 func privateIdString(desc unistring.String) unistring.String { 1341 return asciiString("#").Concat(stringValueFromRaw(desc)).string() 1342 } 1343 1344 type privateName struct { 1345 idx int 1346 isStatic bool 1347 isMethod bool 1348 hasGetter, hasSetter bool 1349 } 1350 1351 type resolvedPrivateName struct { 1352 name unistring.String 1353 idx uint32 1354 level uint8 1355 isStatic bool 1356 isMethod bool 1357 } 1358 1359 func (r *resolvedPrivateName) string() unistring.String { 1360 return privateIdString(r.name) 1361 } 1362 1363 type privateEnvRegistry struct { 1364 fields, methods []unistring.String 1365 } 1366 1367 type classScope struct { 1368 c *compiler 1369 privateNames map[unistring.String]*privateName 1370 1371 instanceEnv, staticEnv privateEnvRegistry 1372 1373 outer *classScope 1374 } 1375 1376 func (r *privateEnvRegistry) createPrivateMethodId(name unistring.String) int { 1377 r.methods = append(r.methods, name) 1378 return len(r.methods) - 1 1379 } 1380 1381 func (r *privateEnvRegistry) createPrivateFieldId(name unistring.String) int { 1382 r.fields = append(r.fields, name) 1383 return len(r.fields) - 1 1384 } 1385 1386 func (s *classScope) declarePrivateId(name unistring.String, kind ast.PropertyKind, isStatic bool, offset int) { 1387 pn := s.privateNames[name] 1388 if pn != nil { 1389 if pn.isStatic == isStatic { 1390 switch kind { 1391 case ast.PropertyKindGet: 1392 if pn.hasSetter && !pn.hasGetter { 1393 pn.hasGetter = true 1394 return 1395 } 1396 case ast.PropertyKindSet: 1397 if pn.hasGetter && !pn.hasSetter { 1398 pn.hasSetter = true 1399 return 1400 } 1401 } 1402 } 1403 s.c.throwSyntaxError(offset, "Identifier '#%s' has already been declared", name) 1404 panic("unreachable") 1405 } 1406 var env *privateEnvRegistry 1407 if isStatic { 1408 env = &s.staticEnv 1409 } else { 1410 env = &s.instanceEnv 1411 } 1412 1413 pn = &privateName{ 1414 isStatic: isStatic, 1415 hasGetter: kind == ast.PropertyKindGet, 1416 hasSetter: kind == ast.PropertyKindSet, 1417 } 1418 if kind != ast.PropertyKindValue { 1419 pn.idx = env.createPrivateMethodId(name) 1420 pn.isMethod = true 1421 } else { 1422 pn.idx = env.createPrivateFieldId(name) 1423 } 1424 1425 if s.privateNames == nil { 1426 s.privateNames = make(map[unistring.String]*privateName) 1427 } 1428 s.privateNames[name] = pn 1429 } 1430 1431 func (s *classScope) getDeclaredPrivateId(name unistring.String) *privateName { 1432 if n := s.privateNames[name]; n != nil { 1433 return n 1434 } 1435 s.c.assert(false, 0, "getDeclaredPrivateId() for undeclared id") 1436 panic("unreachable") 1437 } 1438 1439 func (c *compiler) resolvePrivateName(name unistring.String, offset int) (*resolvedPrivateName, *privateId) { 1440 level := 0 1441 for s := c.classScope; s != nil; s = s.outer { 1442 if len(s.privateNames) > 0 { 1443 if pn := s.privateNames[name]; pn != nil { 1444 return &resolvedPrivateName{ 1445 name: name, 1446 idx: uint32(pn.idx), 1447 level: uint8(level), 1448 isStatic: pn.isStatic, 1449 isMethod: pn.isMethod, 1450 }, nil 1451 } 1452 level++ 1453 } 1454 } 1455 if c.ctxVM != nil { 1456 for s := c.ctxVM.privEnv; s != nil; s = s.outer { 1457 if id := s.names[name]; id != nil { 1458 return nil, id 1459 } 1460 } 1461 } 1462 c.throwSyntaxError(offset, "Private field '#%s' must be declared in an enclosing class", name) 1463 panic("unreachable") 1464 }