1package goja
2
3import (
4	"fmt"
5	"log"
6	"math"
7	"strconv"
8	"sync"
9	"sync/atomic"
10)
11
12const (
13	maxInt = 1 << 53
14)
15
16type valueStack []Value
17
18type stash struct {
19	values    valueStack
20	extraArgs valueStack
21	names     map[string]uint32
22	obj       objectImpl
23
24	outer *stash
25}
26
27type context struct {
28	prg      *Program
29	funcName string
30	stash    *stash
31	pc, sb   int
32	args     int
33}
34
35type iterStackItem struct {
36	val Value
37	f   iterNextFunc
38}
39
40type ref interface {
41	get() Value
42	set(Value)
43	refname() string
44}
45
46type stashRef struct {
47	v *Value
48	n string
49}
50
51func (r stashRef) get() Value {
52	return *r.v
53}
54
55func (r *stashRef) set(v Value) {
56	*r.v = v
57}
58
59func (r *stashRef) refname() string {
60	return r.n
61}
62
63type objRef struct {
64	base   objectImpl
65	name   string
66	strict bool
67}
68
69func (r *objRef) get() Value {
70	return r.base.getStr(r.name)
71}
72
73func (r *objRef) set(v Value) {
74	r.base.putStr(r.name, v, r.strict)
75}
76
77func (r *objRef) refname() string {
78	return r.name
79}
80
81type unresolvedRef struct {
82	runtime *Runtime
83	name    string
84}
85
86func (r *unresolvedRef) get() Value {
87	r.runtime.throwReferenceError(r.name)
88	panic("Unreachable")
89}
90
91func (r *unresolvedRef) set(v Value) {
92	r.get()
93}
94
95func (r *unresolvedRef) refname() string {
96	return r.name
97}
98
99type vm struct {
100	r            *Runtime
101	prg          *Program
102	funcName     string
103	pc           int
104	stack        valueStack
105	sp, sb, args int
106
107	stash     *stash
108	callStack []context
109	iterStack []iterStackItem
110	refStack  []ref
111
112	stashAllocs int
113	halt        bool
114
115	interrupted   uint32
116	interruptVal  interface{}
117	interruptLock sync.Mutex
118}
119
120type instruction interface {
121	exec(*vm)
122}
123
124func intToValue(i int64) Value {
125	if i >= -maxInt && i <= maxInt {
126		if i >= -128 && i <= 127 {
127			return intCache[i+128]
128		}
129		return valueInt(i)
130	}
131	return valueFloat(float64(i))
132}
133
134func floatToInt(f float64) (result int64, ok bool) {
135	if (f != 0 || !math.Signbit(f)) && !math.IsInf(f, 0) && f == math.Trunc(f) && f >= -maxInt && f <= maxInt {
136		return int64(f), true
137	}
138	return 0, false
139}
140
141func floatToValue(f float64) (result Value) {
142	if i, ok := floatToInt(f); ok {
143		return intToValue(i)
144	}
145	switch {
146	case f == 0:
147		return _negativeZero
148	case math.IsNaN(f):
149		return _NaN
150	case math.IsInf(f, 1):
151		return _positiveInf
152	case math.IsInf(f, -1):
153		return _negativeInf
154	}
155	return valueFloat(f)
156}
157
158func toInt(v Value) (int64, bool) {
159	num := v.ToNumber()
160	if i, ok := num.assertInt(); ok {
161		return i, true
162	}
163	if f, ok := num.assertFloat(); ok {
164		if i, ok := floatToInt(f); ok {
165			return i, true
166		}
167	}
168	return 0, false
169}
170
171func toIntIgnoreNegZero(v Value) (int64, bool) {
172	num := v.ToNumber()
173	if i, ok := num.assertInt(); ok {
174		return i, true
175	}
176	if f, ok := num.assertFloat(); ok {
177		if v == _negativeZero {
178			return 0, true
179		}
180		if i, ok := floatToInt(f); ok {
181			return i, true
182		}
183	}
184	return 0, false
185}
186
187func (s *valueStack) expand(idx int) {
188	if idx < len(*s) {
189		return
190	}
191
192	if idx < cap(*s) {
193		*s = (*s)[:idx+1]
194	} else {
195		n := make([]Value, idx+1, (idx+1)<<1)
196		copy(n, *s)
197		*s = n
198	}
199}
200
201func (s *stash) put(name string, v Value) bool {
202	if s.obj != nil {
203		if found := s.obj.getStr(name); found != nil {
204			s.obj.putStr(name, v, false)
205			return true
206		}
207		return false
208	} else {
209		if idx, found := s.names[name]; found {
210			s.values.expand(int(idx))
211			s.values[idx] = v
212			return true
213		}
214		return false
215	}
216}
217
218func (s *stash) putByIdx(idx uint32, v Value) {
219	if s.obj != nil {
220		panic("Attempt to put by idx into an object scope")
221	}
222	s.values.expand(int(idx))
223	s.values[idx] = v
224}
225
226func (s *stash) getByIdx(idx uint32) Value {
227	if int(idx) < len(s.values) {
228		return s.values[idx]
229	}
230	return _undefined
231}
232
233func (s *stash) getByName(name string, vm *vm) (v Value, exists bool) {
234	if s.obj != nil {
235		v = s.obj.getStr(name)
236		if v == nil {
237			return nil, false
238			//return valueUnresolved{r: vm.r, ref: name}, false
239		}
240		return v, true
241	}
242	if idx, exists := s.names[name]; exists {
243		return s.values[idx], true
244	}
245	return nil, false
246	//return valueUnresolved{r: vm.r, ref: name}, false
247}
248
249func (s *stash) createBinding(name string) {
250	if s.names == nil {
251		s.names = make(map[string]uint32)
252	}
253	if _, exists := s.names[name]; !exists {
254		s.names[name] = uint32(len(s.names))
255		s.values = append(s.values, _undefined)
256	}
257}
258
259func (s *stash) deleteBinding(name string) bool {
260	if s.obj != nil {
261		return s.obj.deleteStr(name, false)
262	}
263	if idx, found := s.names[name]; found {
264		s.values[idx] = nil
265		delete(s.names, name)
266		return true
267	}
268	return false
269}
270
271func (vm *vm) newStash() {
272	vm.stash = &stash{
273		outer: vm.stash,
274	}
275	vm.stashAllocs++
276}
277
278func (vm *vm) init() {
279}
280
281func (vm *vm) run() {
282	vm.halt = false
283	interrupted := false
284	for !vm.halt {
285		if interrupted = atomic.LoadUint32(&vm.interrupted) != 0; interrupted {
286			break
287		}
288		vm.prg.code[vm.pc].exec(vm)
289	}
290
291	if interrupted {
292		vm.interruptLock.Lock()
293		v := &InterruptedError{
294			iface: vm.interruptVal,
295		}
296		atomic.StoreUint32(&vm.interrupted, 0)
297		vm.interruptVal = nil
298		vm.interruptLock.Unlock()
299		panic(v)
300	}
301}
302
303func (vm *vm) Interrupt(v interface{}) {
304	vm.interruptLock.Lock()
305	vm.interruptVal = v
306	atomic.StoreUint32(&vm.interrupted, 1)
307	vm.interruptLock.Unlock()
308}
309
310func (vm *vm) captureStack(stack []stackFrame, ctxOffset int) []stackFrame {
311	// Unroll the context stack
312	stack = append(stack, stackFrame{prg: vm.prg, pc: vm.pc, funcName: vm.funcName})
313	for i := len(vm.callStack) - 1; i > ctxOffset-1; i-- {
314		if vm.callStack[i].pc != -1 {
315			stack = append(stack, stackFrame{prg: vm.callStack[i].prg, pc: vm.callStack[i].pc - 1, funcName: vm.callStack[i].funcName})
316		}
317	}
318	return stack
319}
320
321func (vm *vm) try(f func()) (ex *Exception) {
322	var ctx context
323	vm.saveCtx(&ctx)
324
325	ctxOffset := len(vm.callStack)
326	sp := vm.sp
327	iterLen := len(vm.iterStack)
328	refLen := len(vm.refStack)
329
330	defer func() {
331		if x := recover(); x != nil {
332			defer func() {
333				vm.callStack = vm.callStack[:ctxOffset]
334				vm.restoreCtx(&ctx)
335				vm.sp = sp
336
337				// Restore other stacks
338				iterTail := vm.iterStack[iterLen:]
339				for i, _ := range iterTail {
340					iterTail[i] = iterStackItem{}
341				}
342				vm.iterStack = vm.iterStack[:iterLen]
343				refTail := vm.refStack[refLen:]
344				for i, _ := range refTail {
345					refTail[i] = nil
346				}
347				vm.refStack = vm.refStack[:refLen]
348			}()
349			switch x1 := x.(type) {
350			case Value:
351				ex = &Exception{
352					val: x1,
353				}
354			case *InterruptedError:
355				x1.stack = vm.captureStack(x1.stack, ctxOffset)
356				panic(x1)
357			case *Exception:
358				ex = x1
359			default:
360				if vm.prg != nil {
361					vm.prg.dumpCode(log.Printf)
362				}
363				//log.Print("Stack: ", string(debug.Stack()))
364				panic(fmt.Errorf("Panic at %d: %v", vm.pc, x))
365			}
366			ex.stack = vm.captureStack(ex.stack, ctxOffset)
367		}
368	}()
369
370	f()
371	return
372}
373
374func (vm *vm) runTry() (ex *Exception) {
375	return vm.try(vm.run)
376}
377
378func (vm *vm) push(v Value) {
379	vm.stack.expand(vm.sp)
380	vm.stack[vm.sp] = v
381	vm.sp++
382}
383
384func (vm *vm) pop() Value {
385	vm.sp--
386	return vm.stack[vm.sp]
387}
388
389func (vm *vm) peek() Value {
390	return vm.stack[vm.sp-1]
391}
392
393func (vm *vm) saveCtx(ctx *context) {
394	ctx.prg = vm.prg
395	ctx.funcName = vm.funcName
396	ctx.stash = vm.stash
397	ctx.pc = vm.pc
398	ctx.sb = vm.sb
399	ctx.args = vm.args
400}
401
402func (vm *vm) pushCtx() {
403	/*
404		vm.ctxStack = append(vm.ctxStack, context{
405			prg: vm.prg,
406			stash: vm.stash,
407			pc: vm.pc,
408			sb: vm.sb,
409			args: vm.args,
410		})*/
411	vm.callStack = append(vm.callStack, context{})
412	vm.saveCtx(&vm.callStack[len(vm.callStack)-1])
413}
414
415func (vm *vm) restoreCtx(ctx *context) {
416	vm.prg = ctx.prg
417	vm.funcName = ctx.funcName
418	vm.pc = ctx.pc
419	vm.stash = ctx.stash
420	vm.sb = ctx.sb
421	vm.args = ctx.args
422}
423
424func (vm *vm) popCtx() {
425	l := len(vm.callStack) - 1
426	vm.prg = vm.callStack[l].prg
427	vm.callStack[l].prg = nil
428	vm.funcName = vm.callStack[l].funcName
429	vm.pc = vm.callStack[l].pc
430	vm.stash = vm.callStack[l].stash
431	vm.callStack[l].stash = nil
432	vm.sb = vm.callStack[l].sb
433	vm.args = vm.callStack[l].args
434
435	vm.callStack = vm.callStack[:l]
436}
437
438func (r *Runtime) toObject(v Value, args ...interface{}) *Object {
439	//r.checkResolveable(v)
440	if obj, ok := v.(*Object); ok {
441		return obj
442	}
443	if len(args) > 0 {
444		r.typeErrorResult(true, args)
445	} else {
446		r.typeErrorResult(true, "Value is not an object: %s", v.ToString())
447	}
448	panic("Unreachable")
449}
450
451func (r *Runtime) toCallee(v Value) *Object {
452	if obj, ok := v.(*Object); ok {
453		return obj
454	}
455	switch unresolved := v.(type) {
456	case valueUnresolved:
457		unresolved.throw()
458		panic("Unreachable")
459	case memberUnresolved:
460		r.typeErrorResult(true, "Object has no member '%s'", unresolved.ref)
461		panic("Unreachable")
462	}
463	r.typeErrorResult(true, "Value is not an object: %s", v.ToString())
464	panic("Unreachable")
465}
466
467type _newStash struct{}
468
469var newStash _newStash
470
471func (_newStash) exec(vm *vm) {
472	vm.newStash()
473	vm.pc++
474}
475
476type _noop struct{}
477
478var noop _noop
479
480func (_noop) exec(vm *vm) {
481	vm.pc++
482}
483
484type loadVal uint32
485
486func (l loadVal) exec(vm *vm) {
487	vm.push(vm.prg.values[l])
488	vm.pc++
489}
490
491type loadVal1 uint32
492
493func (l *loadVal1) exec(vm *vm) {
494	vm.push(vm.prg.values[*l])
495	vm.pc++
496}
497
498type _loadUndef struct{}
499
500var loadUndef _loadUndef
501
502func (_loadUndef) exec(vm *vm) {
503	vm.push(_undefined)
504	vm.pc++
505}
506
507type _loadNil struct{}
508
509var loadNil _loadNil
510
511func (_loadNil) exec(vm *vm) {
512	vm.push(nil)
513	vm.pc++
514}
515
516type _loadGlobalObject struct{}
517
518var loadGlobalObject _loadGlobalObject
519
520func (_loadGlobalObject) exec(vm *vm) {
521	vm.push(vm.r.globalObject)
522	vm.pc++
523}
524
525type loadStack int
526
527func (l loadStack) exec(vm *vm) {
528	// l < 0 -- arg<-l-1>
529	// l > 0 -- var<l-1>
530	// l == 0 -- this
531
532	if l < 0 {
533		arg := int(-l)
534		if arg > vm.args {
535			vm.push(_undefined)
536		} else {
537			vm.push(vm.stack[vm.sb+arg])
538		}
539	} else if l > 0 {
540		vm.push(vm.stack[vm.sb+vm.args+int(l)])
541	} else {
542		vm.push(vm.stack[vm.sb])
543	}
544	vm.pc++
545}
546
547type _loadCallee struct{}
548
549var loadCallee _loadCallee
550
551func (_loadCallee) exec(vm *vm) {
552	vm.push(vm.stack[vm.sb-1])
553	vm.pc++
554}
555
556func (vm *vm) storeStack(s int) {
557	// l < 0 -- arg<-l-1>
558	// l > 0 -- var<l-1>
559	// l == 0 -- this
560
561	if s < 0 {
562		vm.stack[vm.sb-s] = vm.stack[vm.sp-1]
563	} else if s > 0 {
564		vm.stack[vm.sb+vm.args+s] = vm.stack[vm.sp-1]
565	} else {
566		panic("Attempt to modify this")
567	}
568	vm.pc++
569}
570
571type storeStack int
572
573func (s storeStack) exec(vm *vm) {
574	vm.storeStack(int(s))
575}
576
577type storeStackP int
578
579func (s storeStackP) exec(vm *vm) {
580	vm.storeStack(int(s))
581	vm.sp--
582}
583
584type _toNumber struct{}
585
586var toNumber _toNumber
587
588func (_toNumber) exec(vm *vm) {
589	vm.stack[vm.sp-1] = vm.stack[vm.sp-1].ToNumber()
590	vm.pc++
591}
592
593type _add struct{}
594
595var add _add
596
597func (_add) exec(vm *vm) {
598	right := vm.stack[vm.sp-1]
599	left := vm.stack[vm.sp-2]
600
601	if o, ok := left.(*Object); ok {
602		left = o.self.toPrimitive()
603	}
604
605	if o, ok := right.(*Object); ok {
606		right = o.self.toPrimitive()
607	}
608
609	var ret Value
610
611	leftString, isLeftString := left.assertString()
612	rightString, isRightString := right.assertString()
613
614	if isLeftString || isRightString {
615		if !isLeftString {
616			leftString = left.ToString()
617		}
618		if !isRightString {
619			rightString = right.ToString()
620		}
621		ret = leftString.concat(rightString)
622	} else {
623		if leftInt, ok := left.assertInt(); ok {
624			if rightInt, ok := right.assertInt(); ok {
625				ret = intToValue(int64(leftInt) + int64(rightInt))
626			} else {
627				ret = floatToValue(float64(leftInt) + right.ToFloat())
628			}
629		} else {
630			ret = floatToValue(left.ToFloat() + right.ToFloat())
631		}
632	}
633
634	vm.stack[vm.sp-2] = ret
635	vm.sp--
636	vm.pc++
637}
638
639type _sub struct{}
640
641var sub _sub
642
643func (_sub) exec(vm *vm) {
644	right := vm.stack[vm.sp-1]
645	left := vm.stack[vm.sp-2]
646
647	var result Value
648
649	if left, ok := left.assertInt(); ok {
650		if right, ok := right.assertInt(); ok {
651			result = intToValue(left - right)
652			goto end
653		}
654	}
655
656	result = floatToValue(left.ToFloat() - right.ToFloat())
657end:
658	vm.sp--
659	vm.stack[vm.sp-1] = result
660	vm.pc++
661}
662
663type _mul struct{}
664
665var mul _mul
666
667func (_mul) exec(vm *vm) {
668	left := vm.stack[vm.sp-2]
669	right := vm.stack[vm.sp-1]
670
671	var result Value
672
673	if left, ok := toInt(left); ok {
674		if right, ok := toInt(right); ok {
675			if left == 0 && right == -1 || left == -1 && right == 0 {
676				result = _negativeZero
677				goto end
678			}
679			res := left * right
680			// check for overflow
681			if left == 0 || right == 0 || res/left == right {
682				result = intToValue(res)
683				goto end
684			}
685
686		}
687	}
688
689	result = floatToValue(left.ToFloat() * right.ToFloat())
690
691end:
692	vm.sp--
693	vm.stack[vm.sp-1] = result
694	vm.pc++
695}
696
697type _div struct{}
698
699var div _div
700
701func (_div) exec(vm *vm) {
702	left := vm.stack[vm.sp-2].ToFloat()
703	right := vm.stack[vm.sp-1].ToFloat()
704
705	var result Value
706
707	if math.IsNaN(left) || math.IsNaN(right) {
708		result = _NaN
709		goto end
710	}
711	if math.IsInf(left, 0) && math.IsInf(right, 0) {
712		result = _NaN
713		goto end
714	}
715	if left == 0 && right == 0 {
716		result = _NaN
717		goto end
718	}
719
720	if math.IsInf(left, 0) {
721		if math.Signbit(left) == math.Signbit(right) {
722			result = _positiveInf
723			goto end
724		} else {
725			result = _negativeInf
726			goto end
727		}
728	}
729	if math.IsInf(right, 0) {
730		if math.Signbit(left) == math.Signbit(right) {
731			result = _positiveZero
732			goto end
733		} else {
734			result = _negativeZero
735			goto end
736		}
737	}
738	if right == 0 {
739		if math.Signbit(left) == math.Signbit(right) {
740			result = _positiveInf
741			goto end
742		} else {
743			result = _negativeInf
744			goto end
745		}
746	}
747
748	result = floatToValue(left / right)
749
750end:
751	vm.sp--
752	vm.stack[vm.sp-1] = result
753	vm.pc++
754}
755
756type _mod struct{}
757
758var mod _mod
759
760func (_mod) exec(vm *vm) {
761	left := vm.stack[vm.sp-2]
762	right := vm.stack[vm.sp-1]
763
764	var result Value
765
766	if leftInt, ok := toInt(left); ok {
767		if rightInt, ok := toInt(right); ok {
768			if rightInt == 0 {
769				result = _NaN
770				goto end
771			}
772			r := leftInt % rightInt
773			if r == 0 && leftInt < 0 {
774				result = _negativeZero
775			} else {
776				result = intToValue(leftInt % rightInt)
777			}
778			goto end
779		}
780	}
781
782	result = floatToValue(math.Mod(left.ToFloat(), right.ToFloat()))
783end:
784	vm.sp--
785	vm.stack[vm.sp-1] = result
786	vm.pc++
787}
788
789type _neg struct{}
790
791var neg _neg
792
793func (_neg) exec(vm *vm) {
794	operand := vm.stack[vm.sp-1]
795
796	var result Value
797
798	if i, ok := toInt(operand); ok {
799		if i == 0 {
800			result = _negativeZero
801		} else {
802			result = valueInt(-i)
803		}
804	} else {
805		f := operand.ToFloat()
806		if !math.IsNaN(f) {
807			f = -f
808		}
809		result = valueFloat(f)
810	}
811
812	vm.stack[vm.sp-1] = result
813	vm.pc++
814}
815
816type _plus struct{}
817
818var plus _plus
819
820func (_plus) exec(vm *vm) {
821	vm.stack[vm.sp-1] = vm.stack[vm.sp-1].ToNumber()
822	vm.pc++
823}
824
825type _inc struct{}
826
827var inc _inc
828
829func (_inc) exec(vm *vm) {
830	v := vm.stack[vm.sp-1]
831
832	if i, ok := toInt(v); ok {
833		v = intToValue(i + 1)
834		goto end
835	}
836
837	v = valueFloat(v.ToFloat() + 1)
838
839end:
840	vm.stack[vm.sp-1] = v
841	vm.pc++
842}
843
844type _dec struct{}
845
846var dec _dec
847
848func (_dec) exec(vm *vm) {
849	v := vm.stack[vm.sp-1]
850
851	if i, ok := toInt(v); ok {
852		v = intToValue(i - 1)
853		goto end
854	}
855
856	v = valueFloat(v.ToFloat() - 1)
857
858end:
859	vm.stack[vm.sp-1] = v
860	vm.pc++
861}
862
863type _and struct{}
864
865var and _and
866
867func (_and) exec(vm *vm) {
868	left := toInt32(vm.stack[vm.sp-2])
869	right := toInt32(vm.stack[vm.sp-1])
870	vm.stack[vm.sp-2] = intToValue(int64(left & right))
871	vm.sp--
872	vm.pc++
873}
874
875type _or struct{}
876
877var or _or
878
879func (_or) exec(vm *vm) {
880	left := toInt32(vm.stack[vm.sp-2])
881	right := toInt32(vm.stack[vm.sp-1])
882	vm.stack[vm.sp-2] = intToValue(int64(left | right))
883	vm.sp--
884	vm.pc++
885}
886
887type _xor struct{}
888
889var xor _xor
890
891func (_xor) exec(vm *vm) {
892	left := toInt32(vm.stack[vm.sp-2])
893	right := toInt32(vm.stack[vm.sp-1])
894	vm.stack[vm.sp-2] = intToValue(int64(left ^ right))
895	vm.sp--
896	vm.pc++
897}
898
899type _bnot struct{}
900
901var bnot _bnot
902
903func (_bnot) exec(vm *vm) {
904	op := toInt32(vm.stack[vm.sp-1])
905	vm.stack[vm.sp-1] = intToValue(int64(^op))
906	vm.pc++
907}
908
909type _sal struct{}
910
911var sal _sal
912
913func (_sal) exec(vm *vm) {
914	left := toInt32(vm.stack[vm.sp-2])
915	right := toUInt32(vm.stack[vm.sp-1])
916	vm.stack[vm.sp-2] = intToValue(int64(left << (right & 0x1F)))
917	vm.sp--
918	vm.pc++
919}
920
921type _sar struct{}
922
923var sar _sar
924
925func (_sar) exec(vm *vm) {
926	left := toInt32(vm.stack[vm.sp-2])
927	right := toUInt32(vm.stack[vm.sp-1])
928	vm.stack[vm.sp-2] = intToValue(int64(left >> (right & 0x1F)))
929	vm.sp--
930	vm.pc++
931}
932
933type _shr struct{}
934
935var shr _shr
936
937func (_shr) exec(vm *vm) {
938	left := toUInt32(vm.stack[vm.sp-2])
939	right := toUInt32(vm.stack[vm.sp-1])
940	vm.stack[vm.sp-2] = intToValue(int64(left >> (right & 0x1F)))
941	vm.sp--
942	vm.pc++
943}
944
945type _halt struct{}
946
947var halt _halt
948
949func (_halt) exec(vm *vm) {
950	vm.halt = true
951	vm.pc++
952}
953
954type jump int32
955
956func (j jump) exec(vm *vm) {
957	vm.pc += int(j)
958}
959
960type _setElem struct{}
961
962var setElem _setElem
963
964func (_setElem) exec(vm *vm) {
965	obj := vm.r.toObject(vm.stack[vm.sp-3])
966	propName := vm.stack[vm.sp-2]
967	val := vm.stack[vm.sp-1]
968
969	obj.self.put(propName, val, false)
970
971	vm.sp -= 2
972	vm.stack[vm.sp-1] = val
973	vm.pc++
974}
975
976type _setElemStrict struct{}
977
978var setElemStrict _setElemStrict
979
980func (_setElemStrict) exec(vm *vm) {
981	obj := vm.r.toObject(vm.stack[vm.sp-3])
982	propName := vm.stack[vm.sp-2]
983	val := vm.stack[vm.sp-1]
984
985	obj.self.put(propName, val, true)
986
987	vm.sp -= 2
988	vm.stack[vm.sp-1] = val
989	vm.pc++
990}
991
992type _deleteElem struct{}
993
994var deleteElem _deleteElem
995
996func (_deleteElem) exec(vm *vm) {
997	obj := vm.r.toObject(vm.stack[vm.sp-2])
998	propName := vm.stack[vm.sp-1]
999	if !obj.self.hasProperty(propName) || obj.self.delete(propName, false) {
1000		vm.stack[vm.sp-2] = valueTrue
1001	} else {
1002		vm.stack[vm.sp-2] = valueFalse
1003	}
1004	vm.sp--
1005	vm.pc++
1006}
1007
1008type _deleteElemStrict struct{}
1009
1010var deleteElemStrict _deleteElemStrict
1011
1012func (_deleteElemStrict) exec(vm *vm) {
1013	obj := vm.r.toObject(vm.stack[vm.sp-2])
1014	propName := vm.stack[vm.sp-1]
1015	obj.self.delete(propName, true)
1016	vm.stack[vm.sp-2] = valueTrue
1017	vm.sp--
1018	vm.pc++
1019}
1020
1021type deleteProp string
1022
1023func (d deleteProp) exec(vm *vm) {
1024	obj := vm.r.toObject(vm.stack[vm.sp-1])
1025	if !obj.self.hasPropertyStr(string(d)) || obj.self.deleteStr(string(d), false) {
1026		vm.stack[vm.sp-1] = valueTrue
1027	} else {
1028		vm.stack[vm.sp-1] = valueFalse
1029	}
1030	vm.pc++
1031}
1032
1033type deletePropStrict string
1034
1035func (d deletePropStrict) exec(vm *vm) {
1036	obj := vm.r.toObject(vm.stack[vm.sp-1])
1037	obj.self.deleteStr(string(d), true)
1038	vm.stack[vm.sp-1] = valueTrue
1039	vm.pc++
1040}
1041
1042type setProp string
1043
1044func (p setProp) exec(vm *vm) {
1045	val := vm.stack[vm.sp-1]
1046
1047	vm.r.toObject(vm.stack[vm.sp-2]).self.putStr(string(p), val, false)
1048	vm.stack[vm.sp-2] = val
1049	vm.sp--
1050	vm.pc++
1051}
1052
1053type setPropStrict string
1054
1055func (p setPropStrict) exec(vm *vm) {
1056	obj := vm.stack[vm.sp-2]
1057	val := vm.stack[vm.sp-1]
1058
1059	obj1 := vm.r.toObject(obj)
1060	obj1.self.putStr(string(p), val, true)
1061	vm.stack[vm.sp-2] = val
1062	vm.sp--
1063	vm.pc++
1064}
1065
1066type setProp1 string
1067
1068func (p setProp1) exec(vm *vm) {
1069	vm.r.toObject(vm.stack[vm.sp-2]).self._putProp(string(p), vm.stack[vm.sp-1], true, true, true)
1070
1071	vm.sp--
1072	vm.pc++
1073}
1074
1075type _setProto struct{}
1076
1077var setProto _setProto
1078
1079func (_setProto) exec(vm *vm) {
1080	vm.r.toObject(vm.stack[vm.sp-2]).self.putStr("__proto__", vm.stack[vm.sp-1], true)
1081
1082	vm.sp--
1083	vm.pc++
1084}
1085
1086type setPropGetter string
1087
1088func (s setPropGetter) exec(vm *vm) {
1089	obj := vm.r.toObject(vm.stack[vm.sp-2])
1090	val := vm.stack[vm.sp-1]
1091
1092	descr := propertyDescr{
1093		Getter:       val,
1094		Configurable: FLAG_TRUE,
1095		Enumerable:   FLAG_TRUE,
1096	}
1097
1098	obj.self.defineOwnProperty(newStringValue(string(s)), descr, false)
1099
1100	vm.sp--
1101	vm.pc++
1102}
1103
1104type setPropSetter string
1105
1106func (s setPropSetter) exec(vm *vm) {
1107	obj := vm.r.toObject(vm.stack[vm.sp-2])
1108	val := vm.stack[vm.sp-1]
1109
1110	descr := propertyDescr{
1111		Setter:       val,
1112		Configurable: FLAG_TRUE,
1113		Enumerable:   FLAG_TRUE,
1114	}
1115
1116	obj.self.defineOwnProperty(newStringValue(string(s)), descr, false)
1117
1118	vm.sp--
1119	vm.pc++
1120}
1121
1122type getProp string
1123
1124func (g getProp) exec(vm *vm) {
1125	v := vm.stack[vm.sp-1]
1126	obj := v.baseObject(vm.r)
1127	if obj == nil {
1128		vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", g)
1129	}
1130	prop := obj.self.getPropStr(string(g))
1131	if prop1, ok := prop.(*valueProperty); ok {
1132		vm.stack[vm.sp-1] = prop1.get(v)
1133	} else {
1134		if prop == nil {
1135			prop = _undefined
1136		}
1137		vm.stack[vm.sp-1] = prop
1138	}
1139
1140	vm.pc++
1141}
1142
1143type getPropCallee string
1144
1145func (g getPropCallee) exec(vm *vm) {
1146	v := vm.stack[vm.sp-1]
1147	obj := v.baseObject(vm.r)
1148	if obj == nil {
1149		vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", g)
1150	}
1151	prop := obj.self.getPropStr(string(g))
1152	if prop1, ok := prop.(*valueProperty); ok {
1153		vm.stack[vm.sp-1] = prop1.get(v)
1154	} else {
1155		if prop == nil {
1156			prop = memberUnresolved{valueUnresolved{r: vm.r, ref: string(g)}}
1157		}
1158		vm.stack[vm.sp-1] = prop
1159	}
1160
1161	vm.pc++
1162}
1163
1164type _getElem struct{}
1165
1166var getElem _getElem
1167
1168func (_getElem) exec(vm *vm) {
1169	v := vm.stack[vm.sp-2]
1170	obj := v.baseObject(vm.r)
1171	propName := vm.stack[vm.sp-1]
1172	if obj == nil {
1173		vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", propName.String())
1174	}
1175
1176	prop := obj.self.getProp(propName)
1177	if prop1, ok := prop.(*valueProperty); ok {
1178		vm.stack[vm.sp-2] = prop1.get(v)
1179	} else {
1180		if prop == nil {
1181			prop = _undefined
1182		}
1183		vm.stack[vm.sp-2] = prop
1184	}
1185
1186	vm.sp--
1187	vm.pc++
1188}
1189
1190type _getElemCallee struct{}
1191
1192var getElemCallee _getElemCallee
1193
1194func (_getElemCallee) exec(vm *vm) {
1195	v := vm.stack[vm.sp-2]
1196	obj := v.baseObject(vm.r)
1197	propName := vm.stack[vm.sp-1]
1198	if obj == nil {
1199		vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", propName.String())
1200		panic("Unreachable")
1201	}
1202
1203	prop := obj.self.getProp(propName)
1204	if prop1, ok := prop.(*valueProperty); ok {
1205		vm.stack[vm.sp-2] = prop1.get(v)
1206	} else {
1207		if prop == nil {
1208			prop = memberUnresolved{valueUnresolved{r: vm.r, ref: propName.String()}}
1209		}
1210		vm.stack[vm.sp-2] = prop
1211	}
1212
1213	vm.sp--
1214	vm.pc++
1215}
1216
1217type _dup struct{}
1218
1219var dup _dup
1220
1221func (_dup) exec(vm *vm) {
1222	vm.push(vm.stack[vm.sp-1])
1223	vm.pc++
1224}
1225
1226type dupN uint32
1227
1228func (d dupN) exec(vm *vm) {
1229	vm.push(vm.stack[vm.sp-1-int(d)])
1230	vm.pc++
1231}
1232
1233type rdupN uint32
1234
1235func (d rdupN) exec(vm *vm) {
1236	vm.stack[vm.sp-1-int(d)] = vm.stack[vm.sp-1]
1237	vm.pc++
1238}
1239
1240type _newObject struct{}
1241
1242var newObject _newObject
1243
1244func (_newObject) exec(vm *vm) {
1245	vm.push(vm.r.NewObject())
1246	vm.pc++
1247}
1248
1249type newArray uint32
1250
1251func (l newArray) exec(vm *vm) {
1252	values := make([]Value, l)
1253	if l > 0 {
1254		copy(values, vm.stack[vm.sp-int(l):vm.sp])
1255	}
1256	obj := vm.r.newArrayValues(values)
1257	if l > 0 {
1258		vm.sp -= int(l) - 1
1259		vm.stack[vm.sp-1] = obj
1260	} else {
1261		vm.push(obj)
1262	}
1263	vm.pc++
1264}
1265
1266type newRegexp struct {
1267	pattern regexpPattern
1268	src     valueString
1269
1270	global, ignoreCase, multiline bool
1271}
1272
1273func (n *newRegexp) exec(vm *vm) {
1274	vm.push(vm.r.newRegExpp(n.pattern, n.src, n.global, n.ignoreCase, n.multiline, vm.r.global.RegExpPrototype))
1275	vm.pc++
1276}
1277
1278func (vm *vm) setLocal(s int) {
1279	v := vm.stack[vm.sp-1]
1280	level := s >> 24
1281	idx := uint32(s & 0x00FFFFFF)
1282	stash := vm.stash
1283	for i := 0; i < level; i++ {
1284		stash = stash.outer
1285	}
1286	stash.putByIdx(idx, v)
1287	vm.pc++
1288}
1289
1290type setLocal uint32
1291
1292func (s setLocal) exec(vm *vm) {
1293	vm.setLocal(int(s))
1294}
1295
1296type setLocalP uint32
1297
1298func (s setLocalP) exec(vm *vm) {
1299	vm.setLocal(int(s))
1300	vm.sp--
1301}
1302
1303type setVar struct {
1304	name string
1305	idx  uint32
1306}
1307
1308func (s setVar) exec(vm *vm) {
1309	v := vm.peek()
1310
1311	level := int(s.idx >> 24)
1312	idx := uint32(s.idx & 0x00FFFFFF)
1313	stash := vm.stash
1314	name := s.name
1315	for i := 0; i < level; i++ {
1316		if stash.put(name, v) {
1317			goto end
1318		}
1319		stash = stash.outer
1320	}
1321
1322	if stash != nil {
1323		stash.putByIdx(idx, v)
1324	} else {
1325		vm.r.globalObject.self.putStr(name, v, false)
1326	}
1327
1328end:
1329	vm.pc++
1330}
1331
1332type resolveVar1 string
1333
1334func (s resolveVar1) exec(vm *vm) {
1335	name := string(s)
1336	var ref ref
1337	for stash := vm.stash; stash != nil; stash = stash.outer {
1338		if stash.obj != nil {
1339			if stash.obj.hasPropertyStr(name) {
1340				ref = &objRef{
1341					base: stash.obj,
1342					name: name,
1343				}
1344				goto end
1345			}
1346		} else {
1347			if idx, exists := stash.names[name]; exists {
1348				ref = &stashRef{
1349					v: &stash.values[idx],
1350				}
1351				goto end
1352			}
1353		}
1354	}
1355
1356	ref = &objRef{
1357		base: vm.r.globalObject.self,
1358		name: name,
1359	}
1360
1361end:
1362	vm.refStack = append(vm.refStack, ref)
1363	vm.pc++
1364}
1365
1366type deleteVar string
1367
1368func (d deleteVar) exec(vm *vm) {
1369	name := string(d)
1370	ret := true
1371	for stash := vm.stash; stash != nil; stash = stash.outer {
1372		if stash.obj != nil {
1373			if stash.obj.hasPropertyStr(name) {
1374				ret = stash.obj.deleteStr(name, false)
1375				goto end
1376			}
1377		} else {
1378			if _, exists := stash.names[name]; exists {
1379				ret = false
1380				goto end
1381			}
1382		}
1383	}
1384
1385	if vm.r.globalObject.self.hasPropertyStr(name) {
1386		ret = vm.r.globalObject.self.deleteStr(name, false)
1387	}
1388
1389end:
1390	if ret {
1391		vm.push(valueTrue)
1392	} else {
1393		vm.push(valueFalse)
1394	}
1395	vm.pc++
1396}
1397
1398type deleteGlobal string
1399
1400func (d deleteGlobal) exec(vm *vm) {
1401	name := string(d)
1402	var ret bool
1403	if vm.r.globalObject.self.hasPropertyStr(name) {
1404		ret = vm.r.globalObject.self.deleteStr(name, false)
1405	} else {
1406		ret = true
1407	}
1408	if ret {
1409		vm.push(valueTrue)
1410	} else {
1411		vm.push(valueFalse)
1412	}
1413	vm.pc++
1414}
1415
1416type resolveVar1Strict string
1417
1418func (s resolveVar1Strict) exec(vm *vm) {
1419	name := string(s)
1420	var ref ref
1421	for stash := vm.stash; stash != nil; stash = stash.outer {
1422		if stash.obj != nil {
1423			if stash.obj.hasPropertyStr(name) {
1424				ref = &objRef{
1425					base:   stash.obj,
1426					name:   name,
1427					strict: true,
1428				}
1429				goto end
1430			}
1431		} else {
1432			if idx, exists := stash.names[name]; exists {
1433				ref = &stashRef{
1434					v: &stash.values[idx],
1435				}
1436				goto end
1437			}
1438		}
1439	}
1440
1441	if vm.r.globalObject.self.hasPropertyStr(name) {
1442		ref = &objRef{
1443			base:   vm.r.globalObject.self,
1444			name:   name,
1445			strict: true,
1446		}
1447		goto end
1448	}
1449
1450	ref = &unresolvedRef{
1451		runtime: vm.r,
1452		name:    string(s),
1453	}
1454
1455end:
1456	vm.refStack = append(vm.refStack, ref)
1457	vm.pc++
1458}
1459
1460type setGlobal string
1461
1462func (s setGlobal) exec(vm *vm) {
1463	v := vm.peek()
1464
1465	vm.r.globalObject.self.putStr(string(s), v, false)
1466	vm.pc++
1467}
1468
1469type setVarStrict struct {
1470	name string
1471	idx  uint32
1472}
1473
1474func (s setVarStrict) exec(vm *vm) {
1475	v := vm.peek()
1476
1477	level := int(s.idx >> 24)
1478	idx := uint32(s.idx & 0x00FFFFFF)
1479	stash := vm.stash
1480	name := s.name
1481	for i := 0; i < level; i++ {
1482		if stash.put(name, v) {
1483			goto end
1484		}
1485		stash = stash.outer
1486	}
1487
1488	if stash != nil {
1489		stash.putByIdx(idx, v)
1490	} else {
1491		o := vm.r.globalObject.self
1492		if o.hasOwnPropertyStr(name) {
1493			o.putStr(name, v, true)
1494		} else {
1495			vm.r.throwReferenceError(name)
1496		}
1497	}
1498
1499end:
1500	vm.pc++
1501}
1502
1503type setVar1Strict string
1504
1505func (s setVar1Strict) exec(vm *vm) {
1506	v := vm.peek()
1507	var o objectImpl
1508
1509	name := string(s)
1510	for stash := vm.stash; stash != nil; stash = stash.outer {
1511		if stash.put(name, v) {
1512			goto end
1513		}
1514	}
1515	o = vm.r.globalObject.self
1516	if o.hasOwnPropertyStr(name) {
1517		o.putStr(name, v, true)
1518	} else {
1519		vm.r.throwReferenceError(name)
1520	}
1521end:
1522	vm.pc++
1523}
1524
1525type setGlobalStrict string
1526
1527func (s setGlobalStrict) exec(vm *vm) {
1528	v := vm.peek()
1529
1530	name := string(s)
1531	o := vm.r.globalObject.self
1532	if o.hasOwnPropertyStr(name) {
1533		o.putStr(name, v, true)
1534	} else {
1535		vm.r.throwReferenceError(name)
1536	}
1537	vm.pc++
1538}
1539
1540type getLocal uint32
1541
1542func (g getLocal) exec(vm *vm) {
1543	level := int(g >> 24)
1544	idx := uint32(g & 0x00FFFFFF)
1545	stash := vm.stash
1546	for i := 0; i < level; i++ {
1547		stash = stash.outer
1548	}
1549
1550	vm.push(stash.getByIdx(idx))
1551	vm.pc++
1552}
1553
1554type getVar struct {
1555	name string
1556	idx  uint32
1557	ref  bool
1558}
1559
1560func (g getVar) exec(vm *vm) {
1561	level := int(g.idx >> 24)
1562	idx := uint32(g.idx & 0x00FFFFFF)
1563	stash := vm.stash
1564	name := g.name
1565	for i := 0; i < level; i++ {
1566		if v, found := stash.getByName(name, vm); found {
1567			vm.push(v)
1568			goto end
1569		}
1570		stash = stash.outer
1571	}
1572	if stash != nil {
1573		vm.push(stash.getByIdx(idx))
1574	} else {
1575		v := vm.r.globalObject.self.getStr(name)
1576		if v == nil {
1577			if g.ref {
1578				v = valueUnresolved{r: vm.r, ref: name}
1579			} else {
1580				vm.r.throwReferenceError(name)
1581			}
1582		}
1583		vm.push(v)
1584	}
1585end:
1586	vm.pc++
1587}
1588
1589type resolveVar struct {
1590	name   string
1591	idx    uint32
1592	strict bool
1593}
1594
1595func (r resolveVar) exec(vm *vm) {
1596	level := int(r.idx >> 24)
1597	idx := uint32(r.idx & 0x00FFFFFF)
1598	stash := vm.stash
1599	var ref ref
1600	for i := 0; i < level; i++ {
1601		if stash.obj != nil {
1602			if stash.obj.hasPropertyStr(r.name) {
1603				ref = &objRef{
1604					base:   stash.obj,
1605					name:   r.name,
1606					strict: r.strict,
1607				}
1608				goto end
1609			}
1610		} else {
1611			if idx, exists := stash.names[r.name]; exists {
1612				ref = &stashRef{
1613					v: &stash.values[idx],
1614				}
1615				goto end
1616			}
1617		}
1618		stash = stash.outer
1619	}
1620
1621	if stash != nil {
1622		ref = &stashRef{
1623			v: &stash.values[idx],
1624		}
1625		goto end
1626	} /*else {
1627		if vm.r.globalObject.self.hasProperty(nameVal) {
1628			ref = &objRef{
1629				base: vm.r.globalObject.self,
1630				name: r.name,
1631			}
1632			goto end
1633		}
1634	} */
1635
1636	ref = &unresolvedRef{
1637		runtime: vm.r,
1638		name:    r.name,
1639	}
1640
1641end:
1642	vm.refStack = append(vm.refStack, ref)
1643	vm.pc++
1644}
1645
1646type _getValue struct{}
1647
1648var getValue _getValue
1649
1650func (_getValue) exec(vm *vm) {
1651	ref := vm.refStack[len(vm.refStack)-1]
1652	if v := ref.get(); v != nil {
1653		vm.push(v)
1654	} else {
1655		vm.r.throwReferenceError(ref.refname())
1656		panic("Unreachable")
1657	}
1658	vm.pc++
1659}
1660
1661type _putValue struct{}
1662
1663var putValue _putValue
1664
1665func (_putValue) exec(vm *vm) {
1666	l := len(vm.refStack) - 1
1667	ref := vm.refStack[l]
1668	vm.refStack[l] = nil
1669	vm.refStack = vm.refStack[:l]
1670	ref.set(vm.stack[vm.sp-1])
1671	vm.pc++
1672}
1673
1674type getVar1 string
1675
1676func (n getVar1) exec(vm *vm) {
1677	name := string(n)
1678	var val Value
1679	for stash := vm.stash; stash != nil; stash = stash.outer {
1680		if v, exists := stash.getByName(name, vm); exists {
1681			val = v
1682			break
1683		}
1684	}
1685	if val == nil {
1686		val = vm.r.globalObject.self.getStr(name)
1687		if val == nil {
1688			vm.r.throwReferenceError(name)
1689		}
1690	}
1691	vm.push(val)
1692	vm.pc++
1693}
1694
1695type getVar1Callee string
1696
1697func (n getVar1Callee) exec(vm *vm) {
1698	name := string(n)
1699	var val Value
1700	for stash := vm.stash; stash != nil; stash = stash.outer {
1701		if v, exists := stash.getByName(name, vm); exists {
1702			val = v
1703			break
1704		}
1705	}
1706	if val == nil {
1707		val = vm.r.globalObject.self.getStr(name)
1708		if val == nil {
1709			val = valueUnresolved{r: vm.r, ref: name}
1710		}
1711	}
1712	vm.push(val)
1713	vm.pc++
1714}
1715
1716type _pop struct{}
1717
1718var pop _pop
1719
1720func (_pop) exec(vm *vm) {
1721	vm.sp--
1722	vm.pc++
1723}
1724
1725type _swap struct{}
1726
1727var swap _swap
1728
1729func (_swap) exec(vm *vm) {
1730	vm.stack[vm.sp-1], vm.stack[vm.sp-2] = vm.stack[vm.sp-2], vm.stack[vm.sp-1]
1731	vm.pc++
1732}
1733
1734func (vm *vm) callEval(n int, strict bool) {
1735	if vm.r.toObject(vm.stack[vm.sp-n-1]) == vm.r.global.Eval {
1736		if n > 0 {
1737			srcVal := vm.stack[vm.sp-n]
1738			if src, ok := srcVal.assertString(); ok {
1739				var this Value
1740				if vm.sb != 0 {
1741					this = vm.stack[vm.sb]
1742				} else {
1743					this = vm.r.globalObject
1744				}
1745				ret := vm.r.eval(src.String(), true, strict, this)
1746				vm.stack[vm.sp-n-2] = ret
1747			} else {
1748				vm.stack[vm.sp-n-2] = srcVal
1749			}
1750		} else {
1751			vm.stack[vm.sp-n-2] = _undefined
1752		}
1753
1754		vm.sp -= n + 1
1755		vm.pc++
1756	} else {
1757		call(n).exec(vm)
1758	}
1759}
1760
1761type callEval uint32
1762
1763func (numargs callEval) exec(vm *vm) {
1764	vm.callEval(int(numargs), false)
1765}
1766
1767type callEvalStrict uint32
1768
1769func (numargs callEvalStrict) exec(vm *vm) {
1770	vm.callEval(int(numargs), true)
1771}
1772
1773type _boxThis struct{}
1774
1775var boxThis _boxThis
1776
1777func (_boxThis) exec(vm *vm) {
1778	v := vm.stack[vm.sb]
1779	if v == _undefined || v == _null {
1780		vm.stack[vm.sb] = vm.r.globalObject
1781	} else {
1782		vm.stack[vm.sb] = v.ToObject(vm.r)
1783	}
1784	vm.pc++
1785}
1786
1787type call uint32
1788
1789func (numargs call) exec(vm *vm) {
1790	// this
1791	// callee
1792	// arg0
1793	// ...
1794	// arg<numargs-1>
1795	n := int(numargs)
1796	v := vm.stack[vm.sp-n-1] // callee
1797	obj := vm.r.toCallee(v)
1798repeat:
1799	switch f := obj.self.(type) {
1800	case *funcObject:
1801		vm.pc++
1802		vm.pushCtx()
1803		vm.args = n
1804		vm.prg = f.prg
1805		vm.stash = f.stash
1806		vm.pc = 0
1807		vm.stack[vm.sp-n-1], vm.stack[vm.sp-n-2] = vm.stack[vm.sp-n-2], vm.stack[vm.sp-n-1]
1808		return
1809	case *nativeFuncObject:
1810		vm._nativeCall(f, n)
1811	case *boundFuncObject:
1812		vm._nativeCall(&f.nativeFuncObject, n)
1813	case *lazyObject:
1814		obj.self = f.create(obj)
1815		goto repeat
1816	default:
1817		vm.r.typeErrorResult(true, "Not a function: %s", obj.ToString())
1818	}
1819}
1820
1821func (vm *vm) _nativeCall(f *nativeFuncObject, n int) {
1822	if f.f != nil {
1823		vm.pushCtx()
1824		vm.prg = nil
1825		vm.funcName = f.nameProp.get(nil).String()
1826		ret := f.f(FunctionCall{
1827			Arguments: vm.stack[vm.sp-n : vm.sp],
1828			This:      vm.stack[vm.sp-n-2],
1829		})
1830		if ret == nil {
1831			ret = _undefined
1832		}
1833		vm.stack[vm.sp-n-2] = ret
1834		vm.popCtx()
1835	} else {
1836		vm.stack[vm.sp-n-2] = _undefined
1837	}
1838	vm.sp -= n + 1
1839	vm.pc++
1840}
1841
1842func (vm *vm) clearStack() {
1843	stackTail := vm.stack[vm.sp:]
1844	for i := range stackTail {
1845		stackTail[i] = nil
1846	}
1847	vm.stack = vm.stack[:vm.sp]
1848}
1849
1850type enterFunc uint32
1851
1852func (e enterFunc) exec(vm *vm) {
1853	// Input stack:
1854	//
1855	// callee
1856	// this
1857	// arg0
1858	// ...
1859	// argN
1860	// <- sp
1861
1862	// Output stack:
1863	//
1864	// this <- sb
1865	// <- sp
1866
1867	vm.newStash()
1868	offset := vm.args - int(e)
1869	vm.stash.values = make([]Value, e)
1870	if offset > 0 {
1871		copy(vm.stash.values, vm.stack[vm.sp-vm.args:])
1872		vm.stash.extraArgs = make([]Value, offset)
1873		copy(vm.stash.extraArgs, vm.stack[vm.sp-offset:])
1874	} else {
1875		copy(vm.stash.values, vm.stack[vm.sp-vm.args:])
1876		vv := vm.stash.values[vm.args:]
1877		for i, _ := range vv {
1878			vv[i] = _undefined
1879		}
1880	}
1881	vm.sp -= vm.args
1882	vm.sb = vm.sp - 1
1883	vm.pc++
1884}
1885
1886type _ret struct{}
1887
1888var ret _ret
1889
1890func (_ret) exec(vm *vm) {
1891	// callee -3
1892	// this -2
1893	// retval -1
1894
1895	vm.stack[vm.sp-3] = vm.stack[vm.sp-1]
1896	vm.sp -= 2
1897	vm.popCtx()
1898	if vm.pc < 0 {
1899		vm.halt = true
1900	}
1901}
1902
1903type enterFuncStashless struct {
1904	stackSize uint32
1905	args      uint32
1906}
1907
1908func (e enterFuncStashless) exec(vm *vm) {
1909	vm.sb = vm.sp - vm.args - 1
1910	var ss int
1911	d := int(e.args) - vm.args
1912	if d > 0 {
1913		ss = int(e.stackSize) + d
1914		vm.args = int(e.args)
1915	} else {
1916		ss = int(e.stackSize)
1917	}
1918	sp := vm.sp
1919	if ss > 0 {
1920		vm.sp += int(ss)
1921		vm.stack.expand(vm.sp)
1922		s := vm.stack[sp:vm.sp]
1923		for i, _ := range s {
1924			s[i] = _undefined
1925		}
1926	}
1927	vm.pc++
1928}
1929
1930type _retStashless struct{}
1931
1932var retStashless _retStashless
1933
1934func (_retStashless) exec(vm *vm) {
1935	retval := vm.stack[vm.sp-1]
1936	vm.sp = vm.sb
1937	vm.stack[vm.sp-1] = retval
1938	vm.popCtx()
1939	if vm.pc < 0 {
1940		vm.halt = true
1941	}
1942}
1943
1944type newFunc struct {
1945	prg    *Program
1946	name   string
1947	length uint32
1948	strict bool
1949
1950	srcStart, srcEnd uint32
1951}
1952
1953func (n *newFunc) exec(vm *vm) {
1954	obj := vm.r.newFunc(n.name, int(n.length), n.strict)
1955	obj.prg = n.prg
1956	obj.stash = vm.stash
1957	obj.src = n.prg.src.src[n.srcStart:n.srcEnd]
1958	vm.push(obj.val)
1959	vm.pc++
1960}
1961
1962type bindName string
1963
1964func (d bindName) exec(vm *vm) {
1965	if vm.stash != nil {
1966		vm.stash.createBinding(string(d))
1967	} else {
1968		vm.r.globalObject.self._putProp(string(d), _undefined, true, true, false)
1969	}
1970	vm.pc++
1971}
1972
1973type jne int32
1974
1975func (j jne) exec(vm *vm) {
1976	vm.sp--
1977	if !vm.stack[vm.sp].ToBoolean() {
1978		vm.pc += int(j)
1979	} else {
1980		vm.pc++
1981	}
1982}
1983
1984type jeq int32
1985
1986func (j jeq) exec(vm *vm) {
1987	vm.sp--
1988	if vm.stack[vm.sp].ToBoolean() {
1989		vm.pc += int(j)
1990	} else {
1991		vm.pc++
1992	}
1993}
1994
1995type jeq1 int32
1996
1997func (j jeq1) exec(vm *vm) {
1998	if vm.stack[vm.sp-1].ToBoolean() {
1999		vm.pc += int(j)
2000	} else {
2001		vm.pc++
2002	}
2003}
2004
2005type jneq1 int32
2006
2007func (j jneq1) exec(vm *vm) {
2008	if !vm.stack[vm.sp-1].ToBoolean() {
2009		vm.pc += int(j)
2010	} else {
2011		vm.pc++
2012	}
2013}
2014
2015type _not struct{}
2016
2017var not _not
2018
2019func (_not) exec(vm *vm) {
2020	if vm.stack[vm.sp-1].ToBoolean() {
2021		vm.stack[vm.sp-1] = valueFalse
2022	} else {
2023		vm.stack[vm.sp-1] = valueTrue
2024	}
2025	vm.pc++
2026}
2027
2028func toPrimitiveNumber(v Value) Value {
2029	if o, ok := v.(*Object); ok {
2030		return o.self.toPrimitiveNumber()
2031	}
2032	return v
2033}
2034
2035func cmp(px, py Value) Value {
2036	var ret bool
2037	var nx, ny float64
2038
2039	if xs, ok := px.assertString(); ok {
2040		if ys, ok := py.assertString(); ok {
2041			ret = xs.compareTo(ys) < 0
2042			goto end
2043		}
2044	}
2045
2046	if xi, ok := px.assertInt(); ok {
2047		if yi, ok := py.assertInt(); ok {
2048			ret = xi < yi
2049			goto end
2050		}
2051	}
2052
2053	nx = px.ToFloat()
2054	ny = py.ToFloat()
2055
2056	if math.IsNaN(nx) || math.IsNaN(ny) {
2057		return _undefined
2058	}
2059
2060	ret = nx < ny
2061
2062end:
2063	if ret {
2064		return valueTrue
2065	}
2066	return valueFalse
2067
2068}
2069
2070type _op_lt struct{}
2071
2072var op_lt _op_lt
2073
2074func (_op_lt) exec(vm *vm) {
2075	left := toPrimitiveNumber(vm.stack[vm.sp-2])
2076	right := toPrimitiveNumber(vm.stack[vm.sp-1])
2077
2078	r := cmp(left, right)
2079	if r == _undefined {
2080		vm.stack[vm.sp-2] = valueFalse
2081	} else {
2082		vm.stack[vm.sp-2] = r
2083	}
2084	vm.sp--
2085	vm.pc++
2086}
2087
2088type _op_lte struct{}
2089
2090var op_lte _op_lte
2091
2092func (_op_lte) exec(vm *vm) {
2093	left := toPrimitiveNumber(vm.stack[vm.sp-2])
2094	right := toPrimitiveNumber(vm.stack[vm.sp-1])
2095
2096	r := cmp(right, left)
2097	if r == _undefined || r == valueTrue {
2098		vm.stack[vm.sp-2] = valueFalse
2099	} else {
2100		vm.stack[vm.sp-2] = valueTrue
2101	}
2102
2103	vm.sp--
2104	vm.pc++
2105}
2106
2107type _op_gt struct{}
2108
2109var op_gt _op_gt
2110
2111func (_op_gt) exec(vm *vm) {
2112	left := toPrimitiveNumber(vm.stack[vm.sp-2])
2113	right := toPrimitiveNumber(vm.stack[vm.sp-1])
2114
2115	r := cmp(right, left)
2116	if r == _undefined {
2117		vm.stack[vm.sp-2] = valueFalse
2118	} else {
2119		vm.stack[vm.sp-2] = r
2120	}
2121	vm.sp--
2122	vm.pc++
2123}
2124
2125type _op_gte struct{}
2126
2127var op_gte _op_gte
2128
2129func (_op_gte) exec(vm *vm) {
2130	left := toPrimitiveNumber(vm.stack[vm.sp-2])
2131	right := toPrimitiveNumber(vm.stack[vm.sp-1])
2132
2133	r := cmp(left, right)
2134	if r == _undefined || r == valueTrue {
2135		vm.stack[vm.sp-2] = valueFalse
2136	} else {
2137		vm.stack[vm.sp-2] = valueTrue
2138	}
2139
2140	vm.sp--
2141	vm.pc++
2142}
2143
2144type _op_eq struct{}
2145
2146var op_eq _op_eq
2147
2148func (_op_eq) exec(vm *vm) {
2149	if vm.stack[vm.sp-2].Equals(vm.stack[vm.sp-1]) {
2150		vm.stack[vm.sp-2] = valueTrue
2151	} else {
2152		vm.stack[vm.sp-2] = valueFalse
2153	}
2154	vm.sp--
2155	vm.pc++
2156}
2157
2158type _op_neq struct{}
2159
2160var op_neq _op_neq
2161
2162func (_op_neq) exec(vm *vm) {
2163	if vm.stack[vm.sp-2].Equals(vm.stack[vm.sp-1]) {
2164		vm.stack[vm.sp-2] = valueFalse
2165	} else {
2166		vm.stack[vm.sp-2] = valueTrue
2167	}
2168	vm.sp--
2169	vm.pc++
2170}
2171
2172type _op_strict_eq struct{}
2173
2174var op_strict_eq _op_strict_eq
2175
2176func (_op_strict_eq) exec(vm *vm) {
2177	if vm.stack[vm.sp-2].StrictEquals(vm.stack[vm.sp-1]) {
2178		vm.stack[vm.sp-2] = valueTrue
2179	} else {
2180		vm.stack[vm.sp-2] = valueFalse
2181	}
2182	vm.sp--
2183	vm.pc++
2184}
2185
2186type _op_strict_neq struct{}
2187
2188var op_strict_neq _op_strict_neq
2189
2190func (_op_strict_neq) exec(vm *vm) {
2191	if vm.stack[vm.sp-2].StrictEquals(vm.stack[vm.sp-1]) {
2192		vm.stack[vm.sp-2] = valueFalse
2193	} else {
2194		vm.stack[vm.sp-2] = valueTrue
2195	}
2196	vm.sp--
2197	vm.pc++
2198}
2199
2200type _op_instanceof struct{}
2201
2202var op_instanceof _op_instanceof
2203
2204func (_op_instanceof) exec(vm *vm) {
2205	left := vm.stack[vm.sp-2]
2206	right := vm.r.toObject(vm.stack[vm.sp-1])
2207
2208	if right.self.hasInstance(left) {
2209		vm.stack[vm.sp-2] = valueTrue
2210	} else {
2211		vm.stack[vm.sp-2] = valueFalse
2212	}
2213
2214	vm.sp--
2215	vm.pc++
2216}
2217
2218type _op_in struct{}
2219
2220var op_in _op_in
2221
2222func (_op_in) exec(vm *vm) {
2223	left := vm.stack[vm.sp-2]
2224	right := vm.r.toObject(vm.stack[vm.sp-1])
2225
2226	if right.self.hasProperty(left) {
2227		vm.stack[vm.sp-2] = valueTrue
2228	} else {
2229		vm.stack[vm.sp-2] = valueFalse
2230	}
2231
2232	vm.sp--
2233	vm.pc++
2234}
2235
2236type try struct {
2237	catchOffset   int32
2238	finallyOffset int32
2239	dynamic       bool
2240}
2241
2242func (t try) exec(vm *vm) {
2243	o := vm.pc
2244	vm.pc++
2245	ex := vm.runTry()
2246	if ex != nil && t.catchOffset > 0 {
2247		// run the catch block (in try)
2248		vm.pc = o + int(t.catchOffset)
2249		// TODO: if ex.val is an Error, set the stack property
2250		if t.dynamic {
2251			vm.newStash()
2252			vm.stash.putByIdx(0, ex.val)
2253		} else {
2254			vm.push(ex.val)
2255		}
2256		ex = vm.runTry()
2257		if t.dynamic {
2258			vm.stash = vm.stash.outer
2259		}
2260	}
2261
2262	if t.finallyOffset > 0 {
2263		pc := vm.pc
2264		// Run finally
2265		vm.pc = o + int(t.finallyOffset)
2266		vm.run()
2267		if vm.prg.code[vm.pc] == retFinally {
2268			vm.pc = pc
2269		} else {
2270			// break or continue out of finally, dropping exception
2271			ex = nil
2272		}
2273	}
2274
2275	vm.halt = false
2276
2277	if ex != nil {
2278		panic(ex)
2279	}
2280}
2281
2282type _retFinally struct{}
2283
2284var retFinally _retFinally
2285
2286func (_retFinally) exec(vm *vm) {
2287	vm.pc++
2288}
2289
2290type enterCatch string
2291
2292func (varName enterCatch) exec(vm *vm) {
2293	vm.stash.names = map[string]uint32{
2294		string(varName): 0,
2295	}
2296	vm.pc++
2297}
2298
2299type _throw struct{}
2300
2301var throw _throw
2302
2303func (_throw) exec(vm *vm) {
2304	panic(vm.stack[vm.sp-1])
2305}
2306
2307type _new uint32
2308
2309func (n _new) exec(vm *vm) {
2310	obj := vm.r.toObject(vm.stack[vm.sp-1-int(n)])
2311repeat:
2312	switch f := obj.self.(type) {
2313	case *funcObject:
2314		args := make([]Value, n)
2315		copy(args, vm.stack[vm.sp-int(n):])
2316		vm.sp -= int(n)
2317		vm.stack[vm.sp-1] = f.construct(args)
2318	case *nativeFuncObject:
2319		vm._nativeNew(f, int(n))
2320	case *boundFuncObject:
2321		vm._nativeNew(&f.nativeFuncObject, int(n))
2322	case *lazyObject:
2323		obj.self = f.create(obj)
2324		goto repeat
2325	default:
2326		vm.r.typeErrorResult(true, "Not a constructor")
2327	}
2328
2329	vm.pc++
2330}
2331
2332func (vm *vm) _nativeNew(f *nativeFuncObject, n int) {
2333	if f.construct != nil {
2334		args := make([]Value, n)
2335		copy(args, vm.stack[vm.sp-n:])
2336		vm.sp -= n
2337		vm.stack[vm.sp-1] = f.construct(args)
2338	} else {
2339		vm.r.typeErrorResult(true, "Not a constructor")
2340	}
2341}
2342
2343type _typeof struct{}
2344
2345var typeof _typeof
2346
2347func (_typeof) exec(vm *vm) {
2348	var r Value
2349	switch v := vm.stack[vm.sp-1].(type) {
2350	case valueUndefined, valueUnresolved:
2351		r = stringUndefined
2352	case valueNull:
2353		r = stringObjectC
2354	case *Object:
2355	repeat:
2356		switch s := v.self.(type) {
2357		case *funcObject, *nativeFuncObject, *boundFuncObject:
2358			r = stringFunction
2359		case *lazyObject:
2360			v.self = s.create(v)
2361			goto repeat
2362		default:
2363			r = stringObjectC
2364		}
2365	case valueBool:
2366		r = stringBoolean
2367	case valueString:
2368		r = stringString
2369	case valueInt, valueFloat:
2370		r = stringNumber
2371	default:
2372		panic(fmt.Errorf("Unknown type: %T", v))
2373	}
2374	vm.stack[vm.sp-1] = r
2375	vm.pc++
2376}
2377
2378type createArgs uint32
2379
2380func (formalArgs createArgs) exec(vm *vm) {
2381	v := &Object{runtime: vm.r}
2382	args := &argumentsObject{}
2383	args.extensible = true
2384	args.prototype = vm.r.global.ObjectPrototype
2385	args.class = "Arguments"
2386	v.self = args
2387	args.val = v
2388	args.length = vm.args
2389	args.init()
2390	i := 0
2391	c := int(formalArgs)
2392	if vm.args < c {
2393		c = vm.args
2394	}
2395	for ; i < c; i++ {
2396		args._put(strconv.Itoa(i), &mappedProperty{
2397			valueProperty: valueProperty{
2398				writable:     true,
2399				configurable: true,
2400				enumerable:   true,
2401			},
2402			v: &vm.stash.values[i],
2403		})
2404	}
2405
2406	for _, v := range vm.stash.extraArgs {
2407		args._put(strconv.Itoa(i), v)
2408		i++
2409	}
2410
2411	args._putProp("callee", vm.stack[vm.sb-1], true, false, true)
2412	vm.push(v)
2413	vm.pc++
2414}
2415
2416type createArgsStrict uint32
2417
2418func (formalArgs createArgsStrict) exec(vm *vm) {
2419	args := vm.r.newBaseObject(vm.r.global.ObjectPrototype, "Arguments")
2420	i := 0
2421	c := int(formalArgs)
2422	if vm.args < c {
2423		c = vm.args
2424	}
2425	for _, v := range vm.stash.values[:c] {
2426		args._put(strconv.Itoa(i), v)
2427		i++
2428	}
2429
2430	for _, v := range vm.stash.extraArgs {
2431		args._put(strconv.Itoa(i), v)
2432		i++
2433	}
2434
2435	args._putProp("length", intToValue(int64(vm.args)), true, false, true)
2436	args._put("callee", vm.r.global.throwerProperty)
2437	args._put("caller", vm.r.global.throwerProperty)
2438	vm.push(args.val)
2439	vm.pc++
2440}
2441
2442type _enterWith struct{}
2443
2444var enterWith _enterWith
2445
2446func (_enterWith) exec(vm *vm) {
2447	vm.newStash()
2448	vm.stash.obj = vm.stack[vm.sp-1].ToObject(vm.r).self
2449	vm.sp--
2450	vm.pc++
2451}
2452
2453type _leaveWith struct{}
2454
2455var leaveWith _leaveWith
2456
2457func (_leaveWith) exec(vm *vm) {
2458	vm.stash = vm.stash.outer
2459	vm.pc++
2460}
2461
2462func emptyIter() (propIterItem, iterNextFunc) {
2463	return propIterItem{}, nil
2464}
2465
2466type _enumerate struct{}
2467
2468var enumerate _enumerate
2469
2470func (_enumerate) exec(vm *vm) {
2471	v := vm.stack[vm.sp-1]
2472	if v == _undefined || v == _null {
2473		vm.iterStack = append(vm.iterStack, iterStackItem{f: emptyIter})
2474	} else {
2475		vm.iterStack = append(vm.iterStack, iterStackItem{f: v.ToObject(vm.r).self.enumerate(false, true)})
2476	}
2477	vm.sp--
2478	vm.pc++
2479}
2480
2481type enumNext int32
2482
2483func (jmp enumNext) exec(vm *vm) {
2484	l := len(vm.iterStack) - 1
2485	item, n := vm.iterStack[l].f()
2486	if n != nil {
2487		vm.iterStack[l].val = newStringValue(item.name)
2488		vm.iterStack[l].f = n
2489		vm.pc++
2490	} else {
2491		vm.pc += int(jmp)
2492	}
2493}
2494
2495type _enumGet struct{}
2496
2497var enumGet _enumGet
2498
2499func (_enumGet) exec(vm *vm) {
2500	l := len(vm.iterStack) - 1
2501	vm.push(vm.iterStack[l].val)
2502	vm.pc++
2503}
2504
2505type _enumPop struct{}
2506
2507var enumPop _enumPop
2508
2509func (_enumPop) exec(vm *vm) {
2510	l := len(vm.iterStack) - 1
2511	vm.iterStack[l] = iterStackItem{}
2512	vm.iterStack = vm.iterStack[:l]
2513	vm.pc++
2514}
2515