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