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