github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/runtime.go (about) 1 package goja 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "go/ast" 8 "hash/maphash" 9 "math" 10 "math/bits" 11 "math/rand" 12 "reflect" 13 "runtime" 14 "strconv" 15 "time" 16 17 "golang.org/x/text/collate" 18 19 js_ast "github.com/nuvolaris/goja/ast" 20 "github.com/nuvolaris/goja/file" 21 "github.com/nuvolaris/goja/parser" 22 "github.com/nuvolaris/goja/unistring" 23 ) 24 25 const ( 26 sqrt1_2 float64 = math.Sqrt2 / 2 27 28 deoptimiseRegexp = false 29 ) 30 31 var ( 32 typeCallable = reflect.TypeOf(Callable(nil)) 33 typeValue = reflect.TypeOf((*Value)(nil)).Elem() 34 typeObject = reflect.TypeOf((*Object)(nil)) 35 typeTime = reflect.TypeOf(time.Time{}) 36 typeBytes = reflect.TypeOf(([]byte)(nil)) 37 ) 38 39 type iterationKind int 40 41 const ( 42 iterationKindKey iterationKind = iota 43 iterationKindValue 44 iterationKindKeyValue 45 ) 46 47 type global struct { 48 stash stash 49 varNames map[unistring.String]struct{} 50 51 Object *Object 52 Array *Object 53 Function *Object 54 String *Object 55 Number *Object 56 Boolean *Object 57 RegExp *Object 58 Date *Object 59 Symbol *Object 60 Proxy *Object 61 Promise *Object 62 63 AsyncFunction *Object 64 65 ArrayBuffer *Object 66 DataView *Object 67 TypedArray *Object 68 Uint8Array *Object 69 Uint8ClampedArray *Object 70 Int8Array *Object 71 Uint16Array *Object 72 Int16Array *Object 73 Uint32Array *Object 74 Int32Array *Object 75 Float32Array *Object 76 Float64Array *Object 77 78 WeakSet *Object 79 WeakMap *Object 80 Map *Object 81 Set *Object 82 83 Error *Object 84 AggregateError *Object 85 TypeError *Object 86 ReferenceError *Object 87 SyntaxError *Object 88 RangeError *Object 89 EvalError *Object 90 URIError *Object 91 92 GoError *Object 93 94 ObjectPrototype *Object 95 ArrayPrototype *Object 96 NumberPrototype *Object 97 StringPrototype *Object 98 BooleanPrototype *Object 99 FunctionPrototype *Object 100 RegExpPrototype *Object 101 DatePrototype *Object 102 SymbolPrototype *Object 103 104 ArrayBufferPrototype *Object 105 DataViewPrototype *Object 106 TypedArrayPrototype *Object 107 WeakSetPrototype *Object 108 WeakMapPrototype *Object 109 MapPrototype *Object 110 SetPrototype *Object 111 PromisePrototype *Object 112 113 GeneratorFunctionPrototype *Object 114 GeneratorFunction *Object 115 GeneratorPrototype *Object 116 117 AsyncFunctionPrototype *Object 118 119 IteratorPrototype *Object 120 ArrayIteratorPrototype *Object 121 MapIteratorPrototype *Object 122 SetIteratorPrototype *Object 123 StringIteratorPrototype *Object 124 RegExpStringIteratorPrototype *Object 125 126 ErrorPrototype *Object 127 AggregateErrorPrototype *Object 128 TypeErrorPrototype *Object 129 SyntaxErrorPrototype *Object 130 RangeErrorPrototype *Object 131 ReferenceErrorPrototype *Object 132 EvalErrorPrototype *Object 133 URIErrorPrototype *Object 134 135 GoErrorPrototype *Object 136 137 Eval *Object 138 139 thrower *Object 140 throwerProperty Value 141 142 stdRegexpProto *guardedObject 143 144 weakSetAdder *Object 145 weakMapAdder *Object 146 mapAdder *Object 147 setAdder *Object 148 arrayValues *Object 149 arrayToString *Object 150 } 151 152 type Flag int 153 154 const ( 155 FLAG_NOT_SET Flag = iota 156 FLAG_FALSE 157 FLAG_TRUE 158 ) 159 160 func (f Flag) Bool() bool { 161 return f == FLAG_TRUE 162 } 163 164 func ToFlag(b bool) Flag { 165 if b { 166 return FLAG_TRUE 167 } 168 return FLAG_FALSE 169 } 170 171 type RandSource func() float64 172 173 type Now func() time.Time 174 175 type Runtime struct { 176 global global 177 globalObject *Object 178 stringSingleton *stringObject 179 rand RandSource 180 now Now 181 _collator *collate.Collator 182 parserOptions []parser.Option 183 184 symbolRegistry map[unistring.String]*Symbol 185 186 fieldsInfoCache map[reflect.Type]*reflectFieldsInfo 187 methodsInfoCache map[reflect.Type]*reflectMethodsInfo 188 189 fieldNameMapper FieldNameMapper 190 191 vm *vm 192 hash *maphash.Hash 193 idSeq uint64 194 195 jobQueue []func() 196 197 promiseRejectionTracker PromiseRejectionTracker 198 asyncContextTracker AsyncContextTracker 199 } 200 201 type StackFrame struct { 202 prg *Program 203 funcName unistring.String 204 pc int 205 } 206 207 func (f *StackFrame) SrcName() string { 208 if f.prg == nil { 209 return "<native>" 210 } 211 return f.prg.src.Name() 212 } 213 214 func (f *StackFrame) FuncName() string { 215 if f.funcName == "" && f.prg == nil { 216 return "<native>" 217 } 218 if f.funcName == "" { 219 return "<anonymous>" 220 } 221 return f.funcName.String() 222 } 223 224 func (f *StackFrame) Position() file.Position { 225 if f.prg == nil || f.prg.src == nil { 226 return file.Position{} 227 } 228 return f.prg.src.Position(f.prg.sourceOffset(f.pc)) 229 } 230 231 func (f *StackFrame) WriteToValueBuilder(b *StringBuilder) { 232 if f.prg != nil { 233 if n := f.prg.funcName; n != "" { 234 b.WriteString(stringValueFromRaw(n)) 235 b.writeASCII(" (") 236 } 237 p := f.Position() 238 if p.Filename != "" { 239 b.WriteUTF8String(p.Filename) 240 } else { 241 b.writeASCII("<eval>") 242 } 243 b.WriteRune(':') 244 b.writeASCII(strconv.Itoa(p.Line)) 245 b.WriteRune(':') 246 b.writeASCII(strconv.Itoa(p.Column)) 247 b.WriteRune('(') 248 b.writeASCII(strconv.Itoa(f.pc)) 249 b.WriteRune(')') 250 if f.prg.funcName != "" { 251 b.WriteRune(')') 252 } 253 } else { 254 if f.funcName != "" { 255 b.WriteString(stringValueFromRaw(f.funcName)) 256 b.writeASCII(" (") 257 } 258 b.writeASCII("native") 259 if f.funcName != "" { 260 b.WriteRune(')') 261 } 262 } 263 } 264 265 func (f *StackFrame) Write(b *bytes.Buffer) { 266 if f.prg != nil { 267 if n := f.prg.funcName; n != "" { 268 b.WriteString(n.String()) 269 b.WriteString(" (") 270 } 271 p := f.Position() 272 if p.Filename != "" { 273 b.WriteString(p.Filename) 274 } else { 275 b.WriteString("<eval>") 276 } 277 b.WriteByte(':') 278 b.WriteString(strconv.Itoa(p.Line)) 279 b.WriteByte(':') 280 b.WriteString(strconv.Itoa(p.Column)) 281 b.WriteByte('(') 282 b.WriteString(strconv.Itoa(f.pc)) 283 b.WriteByte(')') 284 if f.prg.funcName != "" { 285 b.WriteByte(')') 286 } 287 } else { 288 if f.funcName != "" { 289 b.WriteString(f.funcName.String()) 290 b.WriteString(" (") 291 } 292 b.WriteString("native") 293 if f.funcName != "" { 294 b.WriteByte(')') 295 } 296 } 297 } 298 299 // An un-catchable exception is not catchable by try/catch statements (finally is not executed either), 300 // but it is returned as an error to a Go caller rather than causing a panic. 301 type uncatchableException interface { 302 error 303 _uncatchableException() 304 } 305 306 type Exception struct { 307 val Value 308 stack []StackFrame 309 } 310 311 type baseUncatchableException struct { 312 Exception 313 } 314 315 func (e *baseUncatchableException) _uncatchableException() {} 316 317 type InterruptedError struct { 318 baseUncatchableException 319 iface interface{} 320 } 321 322 func (e *InterruptedError) Unwrap() error { 323 if err, ok := e.iface.(error); ok { 324 return err 325 } 326 return nil 327 } 328 329 type StackOverflowError struct { 330 baseUncatchableException 331 } 332 333 func (e *InterruptedError) Value() interface{} { 334 return e.iface 335 } 336 337 func (e *InterruptedError) String() string { 338 if e == nil { 339 return "<nil>" 340 } 341 var b bytes.Buffer 342 if e.iface != nil { 343 b.WriteString(fmt.Sprint(e.iface)) 344 b.WriteByte('\n') 345 } 346 e.writeFullStack(&b) 347 return b.String() 348 } 349 350 func (e *InterruptedError) Error() string { 351 if e == nil || e.iface == nil { 352 return "<nil>" 353 } 354 var b bytes.Buffer 355 b.WriteString(fmt.Sprint(e.iface)) 356 e.writeShortStack(&b) 357 return b.String() 358 } 359 360 func (e *Exception) writeFullStack(b *bytes.Buffer) { 361 for _, frame := range e.stack { 362 b.WriteString("\tat ") 363 frame.Write(b) 364 b.WriteByte('\n') 365 } 366 } 367 368 func (e *Exception) writeShortStack(b *bytes.Buffer) { 369 if len(e.stack) > 0 && (e.stack[0].prg != nil || e.stack[0].funcName != "") { 370 b.WriteString(" at ") 371 e.stack[0].Write(b) 372 } 373 } 374 375 func (e *Exception) String() string { 376 if e == nil { 377 return "<nil>" 378 } 379 var b bytes.Buffer 380 if e.val != nil { 381 b.WriteString(e.val.String()) 382 b.WriteByte('\n') 383 } 384 e.writeFullStack(&b) 385 return b.String() 386 } 387 388 func (e *Exception) Error() string { 389 if e == nil || e.val == nil { 390 return "<nil>" 391 } 392 var b bytes.Buffer 393 b.WriteString(e.val.String()) 394 e.writeShortStack(&b) 395 return b.String() 396 } 397 398 func (e *Exception) Value() Value { 399 return e.val 400 } 401 402 func (r *Runtime) addToGlobal(name string, value Value) { 403 r.globalObject.self._putProp(unistring.String(name), value, true, false, true) 404 } 405 406 func (r *Runtime) createIterProto(val *Object) objectImpl { 407 o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject) 408 409 o._putSym(SymIterator, valueProp(r.newNativeFunc(r.returnThis, nil, "[Symbol.iterator]", nil, 0), true, false, true)) 410 return o 411 } 412 413 func (r *Runtime) getIteratorPrototype() *Object { 414 var o *Object 415 if o = r.global.IteratorPrototype; o == nil { 416 o = &Object{runtime: r} 417 r.global.IteratorPrototype = o 418 o.self = r.createIterProto(o) 419 } 420 return o 421 } 422 423 func (r *Runtime) init() { 424 r.rand = rand.Float64 425 r.now = time.Now 426 r.global.ObjectPrototype = r.newBaseObject(nil, classObject).val 427 r.globalObject = r.NewObject() 428 429 r.vm = &vm{ 430 r: r, 431 } 432 r.vm.init() 433 434 funcProto := r.newNativeFunc(func(FunctionCall) Value { 435 return _undefined 436 }, nil, " ", nil, 0) 437 r.global.FunctionPrototype = funcProto 438 funcProtoObj := funcProto.self.(*nativeFuncObject) 439 440 r.initObject() 441 r.initFunction() 442 r.initArray() 443 r.initString() 444 r.initGlobalObject() 445 r.initNumber() 446 r.initRegExp() 447 r.initDate() 448 r.initBoolean() 449 r.initProxy() 450 r.initReflect() 451 452 r.initErrors() 453 454 r.global.Eval = r.newNativeFunc(r.builtin_eval, nil, "eval", nil, 1) 455 r.addToGlobal("eval", r.global.Eval) 456 457 r.initMath() 458 r.initJSON() 459 460 r.initTypedArrays() 461 r.initSymbol() 462 r.initWeakSet() 463 r.initWeakMap() 464 r.initMap() 465 r.initSet() 466 r.initPromise() 467 468 r.global.thrower = r.newNativeFunc(r.builtin_thrower, nil, "", nil, 0) 469 r.global.throwerProperty = &valueProperty{ 470 getterFunc: r.global.thrower, 471 setterFunc: r.global.thrower, 472 accessor: true, 473 } 474 r.object_freeze(FunctionCall{Arguments: []Value{r.global.thrower}}) 475 476 funcProtoObj._put("caller", &valueProperty{ 477 getterFunc: r.global.thrower, 478 setterFunc: r.global.thrower, 479 accessor: true, 480 configurable: true, 481 }) 482 funcProtoObj._put("arguments", &valueProperty{ 483 getterFunc: r.global.thrower, 484 setterFunc: r.global.thrower, 485 accessor: true, 486 configurable: true, 487 }) 488 } 489 490 func (r *Runtime) typeErrorResult(throw bool, args ...interface{}) { 491 if throw { 492 panic(r.NewTypeError(args...)) 493 } 494 } 495 496 func (r *Runtime) newError(typ *Object, format string, args ...interface{}) Value { 497 var msg string 498 if len(args) > 0 { 499 msg = fmt.Sprintf(format, args...) 500 } else { 501 msg = format 502 } 503 return r.builtin_new(typ, []Value{newStringValue(msg)}) 504 } 505 506 func (r *Runtime) throwReferenceError(name unistring.String) { 507 panic(r.newReferenceError(name)) 508 } 509 510 func (r *Runtime) newReferenceError(name unistring.String) Value { 511 return r.newError(r.global.ReferenceError, "%s is not defined", name) 512 } 513 514 func (r *Runtime) newSyntaxError(msg string, offset int) Value { 515 return r.builtin_new(r.global.SyntaxError, []Value{newStringValue(msg)}) 516 } 517 518 func newBaseObjectObj(obj, proto *Object, class string) *baseObject { 519 o := &baseObject{ 520 class: class, 521 val: obj, 522 extensible: true, 523 prototype: proto, 524 } 525 obj.self = o 526 o.init() 527 return o 528 } 529 530 func newGuardedObj(proto *Object, class string) *guardedObject { 531 return &guardedObject{ 532 baseObject: baseObject{ 533 class: class, 534 extensible: true, 535 prototype: proto, 536 }, 537 } 538 } 539 540 func (r *Runtime) newBaseObject(proto *Object, class string) (o *baseObject) { 541 v := &Object{runtime: r} 542 return newBaseObjectObj(v, proto, class) 543 } 544 545 func (r *Runtime) newGuardedObject(proto *Object, class string) (o *guardedObject) { 546 v := &Object{runtime: r} 547 o = newGuardedObj(proto, class) 548 v.self = o 549 o.val = v 550 o.init() 551 return 552 } 553 554 func (r *Runtime) NewObject() (v *Object) { 555 return r.newBaseObject(r.global.ObjectPrototype, classObject).val 556 } 557 558 // CreateObject creates an object with given prototype. Equivalent of Object.create(proto). 559 func (r *Runtime) CreateObject(proto *Object) *Object { 560 return r.newBaseObject(proto, classObject).val 561 } 562 563 func (r *Runtime) NewArray(items ...interface{}) *Object { 564 values := make([]Value, len(items)) 565 for i, item := range items { 566 values[i] = r.ToValue(item) 567 } 568 return r.newArrayValues(values) 569 } 570 571 func (r *Runtime) NewTypeError(args ...interface{}) *Object { 572 msg := "" 573 if len(args) > 0 { 574 f, _ := args[0].(string) 575 msg = fmt.Sprintf(f, args[1:]...) 576 } 577 return r.builtin_new(r.global.TypeError, []Value{newStringValue(msg)}) 578 } 579 580 func (r *Runtime) NewGoError(err error) *Object { 581 e := r.newError(r.global.GoError, err.Error()).(*Object) 582 e.Set("value", err) 583 return e 584 } 585 586 func (r *Runtime) newFunc(name unistring.String, length int, strict bool) (f *funcObject) { 587 f = &funcObject{} 588 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 589 f.val.self = f 590 f.init(name, intToValue(int64(length))) 591 return 592 } 593 594 func (r *Runtime) newAsyncFunc(name unistring.String, length int, strict bool) (f *asyncFuncObject) { 595 f = &asyncFuncObject{} 596 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 597 f.class = classFunction 598 f.prototype = r.getAsyncFunctionPrototype() 599 f.val.self = f 600 f.init(name, intToValue(int64(length))) 601 return 602 } 603 604 func (r *Runtime) newGeneratorFunc(name unistring.String, length int, strict bool) (f *generatorFuncObject) { 605 f = &generatorFuncObject{} 606 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 607 f.class = classFunction 608 f.prototype = r.getGeneratorFunctionPrototype() 609 f.val.self = f 610 f.init(name, intToValue(int64(length))) 611 f._putProp("prototype", r.newBaseObject(r.getGeneratorPrototype(), classObject).val, true, false, false) 612 return 613 } 614 615 func (r *Runtime) newClassFunc(name unistring.String, length int, proto *Object, derived bool) (f *classFuncObject) { 616 v := &Object{runtime: r} 617 618 f = &classFuncObject{} 619 f.class = classFunction 620 f.val = v 621 f.extensible = true 622 f.strict = true 623 f.derived = derived 624 v.self = f 625 f.prototype = proto 626 f.init(name, intToValue(int64(length))) 627 return 628 } 629 630 func (r *Runtime) initBaseJsFunction(f *baseJsFuncObject, strict bool) { 631 v := &Object{runtime: r} 632 633 f.class = classFunction 634 f.val = v 635 f.extensible = true 636 f.strict = strict 637 f.prototype = r.global.FunctionPrototype 638 } 639 640 func (r *Runtime) newMethod(name unistring.String, length int, strict bool) (f *methodFuncObject) { 641 f = &methodFuncObject{} 642 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 643 f.val.self = f 644 f.init(name, intToValue(int64(length))) 645 return 646 } 647 648 func (r *Runtime) newGeneratorMethod(name unistring.String, length int, strict bool) (f *generatorMethodFuncObject) { 649 f = &generatorMethodFuncObject{} 650 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 651 f.prototype = r.getGeneratorFunctionPrototype() 652 f.val.self = f 653 f.init(name, intToValue(int64(length))) 654 f._putProp("prototype", r.newBaseObject(r.getGeneratorPrototype(), classObject).val, true, false, false) 655 return 656 } 657 658 func (r *Runtime) newAsyncMethod(name unistring.String, length int, strict bool) (f *asyncMethodFuncObject) { 659 f = &asyncMethodFuncObject{} 660 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 661 f.val.self = f 662 f.init(name, intToValue(int64(length))) 663 return 664 } 665 666 func (r *Runtime) initArrowFunc(f *arrowFuncObject, strict bool) { 667 r.initBaseJsFunction(&f.baseJsFuncObject, strict) 668 f.newTarget = r.vm.newTarget 669 } 670 671 func (r *Runtime) newArrowFunc(name unistring.String, length int, strict bool) (f *arrowFuncObject) { 672 f = &arrowFuncObject{} 673 r.initArrowFunc(f, strict) 674 f.val.self = f 675 f.init(name, intToValue(int64(length))) 676 return 677 } 678 679 func (r *Runtime) newAsyncArrowFunc(name unistring.String, length int, strict bool) (f *asyncArrowFuncObject) { 680 f = &asyncArrowFuncObject{} 681 r.initArrowFunc(&f.arrowFuncObject, strict) 682 f.class = classObject 683 f.prototype = r.getAsyncFunctionPrototype() 684 f.val.self = f 685 f.init(name, intToValue(int64(length))) 686 return 687 } 688 689 func (r *Runtime) newNativeFuncObj(v *Object, call func(FunctionCall) Value, construct func(args []Value, proto *Object) *Object, name unistring.String, proto *Object, length Value) *nativeFuncObject { 690 f := &nativeFuncObject{ 691 baseFuncObject: baseFuncObject{ 692 baseObject: baseObject{ 693 class: classFunction, 694 val: v, 695 extensible: true, 696 prototype: r.global.FunctionPrototype, 697 }, 698 }, 699 f: call, 700 construct: r.wrapNativeConstruct(construct, proto), 701 } 702 v.self = f 703 f.init(name, length) 704 if proto != nil { 705 f._putProp("prototype", proto, false, false, false) 706 } 707 return f 708 } 709 710 func (r *Runtime) newNativeConstructor(call func(ConstructorCall) *Object, name unistring.String, length int64) *Object { 711 v := &Object{runtime: r} 712 713 f := &nativeFuncObject{ 714 baseFuncObject: baseFuncObject{ 715 baseObject: baseObject{ 716 class: classFunction, 717 val: v, 718 extensible: true, 719 prototype: r.global.FunctionPrototype, 720 }, 721 }, 722 } 723 724 f.f = func(c FunctionCall) Value { 725 thisObj, _ := c.This.(*Object) 726 if thisObj != nil { 727 res := call(ConstructorCall{ 728 This: thisObj, 729 Arguments: c.Arguments, 730 }) 731 if res == nil { 732 return _undefined 733 } 734 return res 735 } 736 return f.defaultConstruct(call, c.Arguments, nil) 737 } 738 739 f.construct = func(args []Value, newTarget *Object) *Object { 740 return f.defaultConstruct(call, args, newTarget) 741 } 742 743 v.self = f 744 f.init(name, intToValue(length)) 745 746 proto := r.NewObject() 747 proto.self._putProp("constructor", v, true, false, true) 748 f._putProp("prototype", proto, true, false, false) 749 750 return v 751 } 752 753 func (r *Runtime) newNativeConstructOnly(v *Object, ctor func(args []Value, newTarget *Object) *Object, defaultProto *Object, name unistring.String, length int64) *nativeFuncObject { 754 return r.newNativeFuncAndConstruct(v, func(call FunctionCall) Value { 755 return ctor(call.Arguments, nil) 756 }, 757 func(args []Value, newTarget *Object) *Object { 758 if newTarget == nil { 759 newTarget = v 760 } 761 return ctor(args, newTarget) 762 }, defaultProto, name, intToValue(length)) 763 } 764 765 func (r *Runtime) newNativeFuncAndConstruct(v *Object, call func(call FunctionCall) Value, ctor func(args []Value, newTarget *Object) *Object, defaultProto *Object, name unistring.String, l Value) *nativeFuncObject { 766 if v == nil { 767 v = &Object{runtime: r} 768 } 769 770 f := &nativeFuncObject{ 771 baseFuncObject: baseFuncObject{ 772 baseObject: baseObject{ 773 class: classFunction, 774 val: v, 775 extensible: true, 776 prototype: r.global.FunctionPrototype, 777 }, 778 }, 779 f: call, 780 construct: ctor, 781 } 782 v.self = f 783 f.init(name, l) 784 if defaultProto != nil { 785 f._putProp("prototype", defaultProto, false, false, false) 786 } 787 788 return f 789 } 790 791 func (r *Runtime) newNativeFunc(call func(FunctionCall) Value, construct func(args []Value, proto *Object) *Object, name unistring.String, proto *Object, length int) *Object { 792 v := &Object{runtime: r} 793 794 f := &nativeFuncObject{ 795 baseFuncObject: baseFuncObject{ 796 baseObject: baseObject{ 797 class: classFunction, 798 val: v, 799 extensible: true, 800 prototype: r.global.FunctionPrototype, 801 }, 802 }, 803 f: call, 804 construct: r.wrapNativeConstruct(construct, proto), 805 } 806 v.self = f 807 f.init(name, intToValue(int64(length))) 808 if proto != nil { 809 f._putProp("prototype", proto, false, false, false) 810 proto.self._putProp("constructor", v, true, false, true) 811 } 812 return v 813 } 814 815 func (r *Runtime) newWrappedFunc(value reflect.Value) *Object { 816 817 v := &Object{runtime: r} 818 819 f := &wrappedFuncObject{ 820 nativeFuncObject: nativeFuncObject{ 821 baseFuncObject: baseFuncObject{ 822 baseObject: baseObject{ 823 class: classFunction, 824 val: v, 825 extensible: true, 826 prototype: r.global.FunctionPrototype, 827 }, 828 }, 829 f: r.wrapReflectFunc(value), 830 }, 831 wrapped: value, 832 } 833 v.self = f 834 name := unistring.NewFromString(runtime.FuncForPC(value.Pointer()).Name()) 835 f.init(name, intToValue(int64(value.Type().NumIn()))) 836 return v 837 } 838 839 func (r *Runtime) newNativeFuncConstructObj(v *Object, construct func(args []Value, proto *Object) *Object, name unistring.String, proto *Object, length int) *nativeFuncObject { 840 f := &nativeFuncObject{ 841 baseFuncObject: baseFuncObject{ 842 baseObject: baseObject{ 843 class: classFunction, 844 val: v, 845 extensible: true, 846 prototype: r.global.FunctionPrototype, 847 }, 848 }, 849 f: r.constructToCall(construct, proto), 850 construct: r.wrapNativeConstruct(construct, proto), 851 } 852 853 f.init(name, intToValue(int64(length))) 854 if proto != nil { 855 f._putProp("prototype", proto, false, false, false) 856 } 857 return f 858 } 859 860 func (r *Runtime) newNativeFuncConstruct(construct func(args []Value, proto *Object) *Object, name unistring.String, prototype *Object, length int64) *Object { 861 return r.newNativeFuncConstructProto(construct, name, prototype, r.global.FunctionPrototype, length) 862 } 863 864 func (r *Runtime) newNativeFuncConstructProto(construct func(args []Value, proto *Object) *Object, name unistring.String, prototype, proto *Object, length int64) *Object { 865 v := &Object{runtime: r} 866 867 f := &nativeFuncObject{} 868 f.class = classFunction 869 f.val = v 870 f.extensible = true 871 v.self = f 872 f.prototype = proto 873 f.f = r.constructToCall(construct, prototype) 874 f.construct = r.wrapNativeConstruct(construct, prototype) 875 f.init(name, intToValue(length)) 876 if prototype != nil { 877 f._putProp("prototype", prototype, false, false, false) 878 prototype.self._putProp("constructor", v, true, false, true) 879 } 880 return v 881 } 882 883 func (r *Runtime) newPrimitiveObject(value Value, proto *Object, class string) *Object { 884 v := &Object{runtime: r} 885 886 o := &primitiveValueObject{} 887 o.class = class 888 o.val = v 889 o.extensible = true 890 v.self = o 891 o.prototype = proto 892 o.pValue = value 893 o.init() 894 return v 895 } 896 897 func (r *Runtime) builtin_Number(call FunctionCall) Value { 898 if len(call.Arguments) > 0 { 899 return call.Arguments[0].ToNumber() 900 } else { 901 return valueInt(0) 902 } 903 } 904 905 func (r *Runtime) builtin_newNumber(args []Value, proto *Object) *Object { 906 var v Value 907 if len(args) > 0 { 908 v = args[0].ToNumber() 909 } else { 910 v = intToValue(0) 911 } 912 return r.newPrimitiveObject(v, proto, classNumber) 913 } 914 915 func (r *Runtime) builtin_Boolean(call FunctionCall) Value { 916 if len(call.Arguments) > 0 { 917 if call.Arguments[0].ToBoolean() { 918 return valueTrue 919 } else { 920 return valueFalse 921 } 922 } else { 923 return valueFalse 924 } 925 } 926 927 func (r *Runtime) builtin_newBoolean(args []Value, proto *Object) *Object { 928 var v Value 929 if len(args) > 0 { 930 if args[0].ToBoolean() { 931 v = valueTrue 932 } else { 933 v = valueFalse 934 } 935 } else { 936 v = valueFalse 937 } 938 return r.newPrimitiveObject(v, proto, classBoolean) 939 } 940 941 func (r *Runtime) builtin_new(construct *Object, args []Value) *Object { 942 return r.toConstructor(construct)(args, nil) 943 } 944 945 func (r *Runtime) builtin_thrower(call FunctionCall) Value { 946 obj := r.toObject(call.This) 947 strict := true 948 switch fn := obj.self.(type) { 949 case *funcObject: 950 strict = fn.strict 951 } 952 r.typeErrorResult(strict, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") 953 return nil 954 } 955 956 func (r *Runtime) eval(srcVal String, direct, strict bool) Value { 957 src := escapeInvalidUtf16(srcVal) 958 vm := r.vm 959 inGlobal := true 960 if direct { 961 for s := vm.stash; s != nil; s = s.outer { 962 if s.isVariable() { 963 inGlobal = false 964 break 965 } 966 } 967 } 968 vm.pushCtx() 969 funcObj := _undefined 970 if !direct { 971 vm.stash = &r.global.stash 972 vm.privEnv = nil 973 } else { 974 if sb := vm.sb; sb > 0 { 975 funcObj = vm.stack[sb-1] 976 } 977 } 978 p, err := r.compile("<eval>", src, strict, inGlobal, r.vm) 979 if err != nil { 980 panic(err) 981 } 982 983 vm.prg = p 984 vm.pc = 0 985 vm.args = 0 986 vm.result = _undefined 987 vm.push(funcObj) 988 vm.sb = vm.sp 989 vm.push(nil) // this 990 ex := vm.runTry() 991 retval := vm.result 992 vm.popCtx() 993 if ex != nil { 994 panic(ex) 995 } 996 vm.sp -= 2 997 return retval 998 } 999 1000 func (r *Runtime) builtin_eval(call FunctionCall) Value { 1001 if len(call.Arguments) == 0 { 1002 return _undefined 1003 } 1004 if str, ok := call.Arguments[0].(String); ok { 1005 return r.eval(str, false, false) 1006 } 1007 return call.Arguments[0] 1008 } 1009 1010 func (r *Runtime) constructToCall(construct func(args []Value, proto *Object) *Object, proto *Object) func(call FunctionCall) Value { 1011 return func(call FunctionCall) Value { 1012 return construct(call.Arguments, proto) 1013 } 1014 } 1015 1016 func (r *Runtime) wrapNativeConstruct(c func(args []Value, proto *Object) *Object, proto *Object) func(args []Value, newTarget *Object) *Object { 1017 if c == nil { 1018 return nil 1019 } 1020 return func(args []Value, newTarget *Object) *Object { 1021 var p *Object 1022 if newTarget != nil { 1023 if pp, ok := newTarget.self.getStr("prototype", nil).(*Object); ok { 1024 p = pp 1025 } 1026 } 1027 if p == nil { 1028 p = proto 1029 } 1030 return c(args, p) 1031 } 1032 } 1033 1034 func (r *Runtime) toCallable(v Value) func(FunctionCall) Value { 1035 if call, ok := r.toObject(v).self.assertCallable(); ok { 1036 return call 1037 } 1038 r.typeErrorResult(true, "Value is not callable: %s", v.toString()) 1039 return nil 1040 } 1041 1042 func (r *Runtime) checkObjectCoercible(v Value) { 1043 switch v.(type) { 1044 case valueUndefined, valueNull: 1045 r.typeErrorResult(true, "Value is not object coercible") 1046 } 1047 } 1048 1049 func toInt8(v Value) int8 { 1050 v = v.ToNumber() 1051 if i, ok := v.(valueInt); ok { 1052 return int8(i) 1053 } 1054 1055 if f, ok := v.(valueFloat); ok { 1056 f := float64(f) 1057 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1058 return int8(int64(f)) 1059 } 1060 } 1061 return 0 1062 } 1063 1064 func toUint8(v Value) uint8 { 1065 v = v.ToNumber() 1066 if i, ok := v.(valueInt); ok { 1067 return uint8(i) 1068 } 1069 1070 if f, ok := v.(valueFloat); ok { 1071 f := float64(f) 1072 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1073 return uint8(int64(f)) 1074 } 1075 } 1076 return 0 1077 } 1078 1079 func toUint8Clamp(v Value) uint8 { 1080 v = v.ToNumber() 1081 if i, ok := v.(valueInt); ok { 1082 if i < 0 { 1083 return 0 1084 } 1085 if i <= 255 { 1086 return uint8(i) 1087 } 1088 return 255 1089 } 1090 1091 if num, ok := v.(valueFloat); ok { 1092 num := float64(num) 1093 if !math.IsNaN(num) { 1094 if num < 0 { 1095 return 0 1096 } 1097 if num > 255 { 1098 return 255 1099 } 1100 f := math.Floor(num) 1101 f1 := f + 0.5 1102 if f1 < num { 1103 return uint8(f + 1) 1104 } 1105 if f1 > num { 1106 return uint8(f) 1107 } 1108 r := uint8(f) 1109 if r&1 != 0 { 1110 return r + 1 1111 } 1112 return r 1113 } 1114 } 1115 return 0 1116 } 1117 1118 func toInt16(v Value) int16 { 1119 v = v.ToNumber() 1120 if i, ok := v.(valueInt); ok { 1121 return int16(i) 1122 } 1123 1124 if f, ok := v.(valueFloat); ok { 1125 f := float64(f) 1126 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1127 return int16(int64(f)) 1128 } 1129 } 1130 return 0 1131 } 1132 1133 func toUint16(v Value) uint16 { 1134 v = v.ToNumber() 1135 if i, ok := v.(valueInt); ok { 1136 return uint16(i) 1137 } 1138 1139 if f, ok := v.(valueFloat); ok { 1140 f := float64(f) 1141 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1142 return uint16(int64(f)) 1143 } 1144 } 1145 return 0 1146 } 1147 1148 func toInt32(v Value) int32 { 1149 v = v.ToNumber() 1150 if i, ok := v.(valueInt); ok { 1151 return int32(i) 1152 } 1153 1154 if f, ok := v.(valueFloat); ok { 1155 f := float64(f) 1156 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1157 return int32(int64(f)) 1158 } 1159 } 1160 return 0 1161 } 1162 1163 func toUint32(v Value) uint32 { 1164 v = v.ToNumber() 1165 if i, ok := v.(valueInt); ok { 1166 return uint32(i) 1167 } 1168 1169 if f, ok := v.(valueFloat); ok { 1170 f := float64(f) 1171 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1172 return uint32(int64(f)) 1173 } 1174 } 1175 return 0 1176 } 1177 1178 func toInt64(v Value) int64 { 1179 v = v.ToNumber() 1180 if i, ok := v.(valueInt); ok { 1181 return int64(i) 1182 } 1183 1184 if f, ok := v.(valueFloat); ok { 1185 f := float64(f) 1186 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1187 return int64(f) 1188 } 1189 } 1190 return 0 1191 } 1192 1193 func toUint64(v Value) uint64 { 1194 v = v.ToNumber() 1195 if i, ok := v.(valueInt); ok { 1196 return uint64(i) 1197 } 1198 1199 if f, ok := v.(valueFloat); ok { 1200 f := float64(f) 1201 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1202 return uint64(int64(f)) 1203 } 1204 } 1205 return 0 1206 } 1207 1208 func toInt(v Value) int { 1209 v = v.ToNumber() 1210 if i, ok := v.(valueInt); ok { 1211 return int(i) 1212 } 1213 1214 if f, ok := v.(valueFloat); ok { 1215 f := float64(f) 1216 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1217 return int(f) 1218 } 1219 } 1220 return 0 1221 } 1222 1223 func toUint(v Value) uint { 1224 v = v.ToNumber() 1225 if i, ok := v.(valueInt); ok { 1226 return uint(i) 1227 } 1228 1229 if f, ok := v.(valueFloat); ok { 1230 f := float64(f) 1231 if !math.IsNaN(f) && !math.IsInf(f, 0) { 1232 return uint(int64(f)) 1233 } 1234 } 1235 return 0 1236 } 1237 1238 func toFloat32(v Value) float32 { 1239 return float32(v.ToFloat()) 1240 } 1241 1242 func toLength(v Value) int64 { 1243 if v == nil { 1244 return 0 1245 } 1246 i := v.ToInteger() 1247 if i < 0 { 1248 return 0 1249 } 1250 if i >= maxInt { 1251 return maxInt - 1 1252 } 1253 return i 1254 } 1255 1256 func (r *Runtime) toLengthUint32(v Value) uint32 { 1257 var intVal int64 1258 repeat: 1259 switch num := v.(type) { 1260 case valueInt: 1261 intVal = int64(num) 1262 case valueFloat: 1263 if v != _negativeZero { 1264 if i, ok := floatToInt(float64(num)); ok { 1265 intVal = i 1266 } else { 1267 goto fail 1268 } 1269 } 1270 case String: 1271 v = num.ToNumber() 1272 goto repeat 1273 default: 1274 // Legacy behaviour as specified in https://tc39.es/ecma262/#sec-arraysetlength (see the note) 1275 n2 := toUint32(v) 1276 n1 := v.ToNumber() 1277 if f, ok := n1.(valueFloat); ok { 1278 f := float64(f) 1279 if f != 0 || !math.Signbit(f) { 1280 goto fail 1281 } 1282 } 1283 if n1.ToInteger() != int64(n2) { 1284 goto fail 1285 } 1286 return n2 1287 } 1288 if intVal >= 0 && intVal <= math.MaxUint32 { 1289 return uint32(intVal) 1290 } 1291 fail: 1292 panic(r.newError(r.global.RangeError, "Invalid array length")) 1293 } 1294 1295 func toIntStrict(i int64) int { 1296 if bits.UintSize == 32 { 1297 if i > math.MaxInt32 || i < math.MinInt32 { 1298 panic(rangeError("Integer value overflows 32-bit int")) 1299 } 1300 } 1301 return int(i) 1302 } 1303 1304 func toIntClamp(i int64) int { 1305 if bits.UintSize == 32 { 1306 if i > math.MaxInt32 { 1307 return math.MaxInt32 1308 } 1309 if i < math.MinInt32 { 1310 return math.MinInt32 1311 } 1312 } 1313 return int(i) 1314 } 1315 1316 func (r *Runtime) toIndex(v Value) int { 1317 num := v.ToInteger() 1318 if num >= 0 && num < maxInt { 1319 if bits.UintSize == 32 && num >= math.MaxInt32 { 1320 panic(r.newError(r.global.RangeError, "Index %s overflows int", v.String())) 1321 } 1322 return int(num) 1323 } 1324 panic(r.newError(r.global.RangeError, "Invalid index %s", v.String())) 1325 } 1326 1327 func (r *Runtime) toBoolean(b bool) Value { 1328 if b { 1329 return valueTrue 1330 } else { 1331 return valueFalse 1332 } 1333 } 1334 1335 // New creates an instance of a Javascript runtime that can be used to run code. Multiple instances may be created and 1336 // used simultaneously, however it is not possible to pass JS values across runtimes. 1337 func New() *Runtime { 1338 r := &Runtime{} 1339 r.init() 1340 return r 1341 } 1342 1343 // Compile creates an internal representation of the JavaScript code that can be later run using the Runtime.RunProgram() 1344 // method. This representation is not linked to a runtime in any way and can be run in multiple runtimes (possibly 1345 // at the same time). 1346 func Compile(name, src string, strict bool) (*Program, error) { 1347 return compile(name, src, strict, true, nil) 1348 } 1349 1350 // CompileAST creates an internal representation of the JavaScript code that can be later run using the Runtime.RunProgram() 1351 // method. This representation is not linked to a runtime in any way and can be run in multiple runtimes (possibly 1352 // at the same time). 1353 func CompileAST(prg *js_ast.Program, strict bool) (*Program, error) { 1354 return compileAST(prg, strict, true, nil) 1355 } 1356 1357 // MustCompile is like Compile but panics if the code cannot be compiled. 1358 // It simplifies safe initialization of global variables holding compiled JavaScript code. 1359 func MustCompile(name, src string, strict bool) *Program { 1360 prg, err := Compile(name, src, strict) 1361 if err != nil { 1362 panic(err) 1363 } 1364 1365 return prg 1366 } 1367 1368 // Parse takes a source string and produces a parsed AST. Use this function if you want to pass options 1369 // to the parser, e.g.: 1370 // 1371 // p, err := Parse("test.js", "var a = true", parser.WithDisableSourceMaps) 1372 // if err != nil { /* ... */ } 1373 // prg, err := CompileAST(p, true) 1374 // // ... 1375 // 1376 // Otherwise use Compile which combines both steps. 1377 func Parse(name, src string, options ...parser.Option) (prg *js_ast.Program, err error) { 1378 prg, err1 := parser.ParseFile(nil, name, src, 0, options...) 1379 if err1 != nil { 1380 // FIXME offset 1381 err = &CompilerSyntaxError{ 1382 CompilerError: CompilerError{ 1383 Message: err1.Error(), 1384 }, 1385 } 1386 } 1387 return 1388 } 1389 1390 func compile(name, src string, strict, inGlobal bool, evalVm *vm, parserOptions ...parser.Option) (p *Program, err error) { 1391 prg, err := Parse(name, src, parserOptions...) 1392 if err != nil { 1393 return 1394 } 1395 1396 return compileAST(prg, strict, inGlobal, evalVm) 1397 } 1398 1399 func compileAST(prg *js_ast.Program, strict, inGlobal bool, evalVm *vm) (p *Program, err error) { 1400 c := newCompiler() 1401 1402 defer func() { 1403 if x := recover(); x != nil { 1404 p = nil 1405 switch x1 := x.(type) { 1406 case *CompilerSyntaxError: 1407 err = x1 1408 default: 1409 panic(x) 1410 } 1411 } 1412 }() 1413 1414 c.compile(prg, strict, inGlobal, evalVm) 1415 p = c.p 1416 return 1417 } 1418 1419 func (r *Runtime) compile(name, src string, strict, inGlobal bool, evalVm *vm) (p *Program, err error) { 1420 p, err = compile(name, src, strict, inGlobal, evalVm, r.parserOptions...) 1421 if err != nil { 1422 switch x1 := err.(type) { 1423 case *CompilerSyntaxError: 1424 err = &Exception{ 1425 val: r.builtin_new(r.global.SyntaxError, []Value{newStringValue(x1.Error())}), 1426 } 1427 case *CompilerReferenceError: 1428 err = &Exception{ 1429 val: r.newError(r.global.ReferenceError, x1.Message), 1430 } // TODO proper message 1431 } 1432 } 1433 return 1434 } 1435 1436 // RunString executes the given string in the global context. 1437 func (r *Runtime) RunString(str string) (Value, error) { 1438 return r.RunScript("", str) 1439 } 1440 1441 // RunScript executes the given string in the global context. 1442 func (r *Runtime) RunScript(name, src string) (Value, error) { 1443 p, err := r.compile(name, src, false, true, nil) 1444 1445 if err != nil { 1446 return nil, err 1447 } 1448 1449 return r.RunProgram(p) 1450 } 1451 1452 func isUncatchableException(e error) bool { 1453 for ; e != nil; e = errors.Unwrap(e) { 1454 if _, ok := e.(uncatchableException); ok { 1455 return true 1456 } 1457 } 1458 return false 1459 } 1460 1461 func asUncatchableException(v interface{}) error { 1462 switch v := v.(type) { 1463 case uncatchableException: 1464 return v 1465 case error: 1466 if isUncatchableException(v) { 1467 return v 1468 } 1469 } 1470 return nil 1471 } 1472 1473 // RunProgram executes a pre-compiled (see Compile()) code in the global context. 1474 func (r *Runtime) RunProgram(p *Program) (result Value, err error) { 1475 vm := r.vm 1476 recursive := len(vm.callStack) > 0 1477 defer func() { 1478 if recursive { 1479 vm.sp -= 2 1480 vm.popCtx() 1481 } else { 1482 vm.callStack = vm.callStack[:len(vm.callStack)-1] 1483 } 1484 if x := recover(); x != nil { 1485 if ex := asUncatchableException(x); ex != nil { 1486 err = ex 1487 if len(vm.callStack) == 0 { 1488 r.leaveAbrupt() 1489 } 1490 } else { 1491 panic(x) 1492 } 1493 } 1494 }() 1495 if recursive { 1496 vm.pushCtx() 1497 vm.stash = &r.global.stash 1498 vm.privEnv = nil 1499 vm.newTarget = nil 1500 vm.args = 0 1501 sp := vm.sp 1502 vm.stack.expand(sp + 1) 1503 vm.stack[sp] = _undefined // 'callee' 1504 vm.stack[sp+1] = nil // 'this' 1505 vm.sb = sp + 1 1506 vm.sp = sp + 2 1507 } else { 1508 vm.callStack = append(vm.callStack, context{}) 1509 } 1510 vm.prg = p 1511 vm.pc = 0 1512 vm.result = _undefined 1513 ex := vm.runTry() 1514 if ex == nil { 1515 result = r.vm.result 1516 } else { 1517 err = ex 1518 } 1519 if recursive { 1520 vm.clearStack() 1521 } else { 1522 vm.prg = nil 1523 vm.sb = -1 1524 r.leave() 1525 } 1526 return 1527 } 1528 1529 // CaptureCallStack appends the current call stack frames to the stack slice (which may be nil) up to the specified depth. 1530 // The most recent frame will be the first one. 1531 // If depth <= 0 or more than the number of available frames, returns the entire stack. 1532 // This method is not safe for concurrent use and should only be called by a Go function that is 1533 // called from a running script. 1534 func (r *Runtime) CaptureCallStack(depth int, stack []StackFrame) []StackFrame { 1535 l := len(r.vm.callStack) 1536 var offset int 1537 if depth > 0 { 1538 offset = l - depth + 1 1539 if offset < 0 { 1540 offset = 0 1541 } 1542 } 1543 if stack == nil { 1544 stack = make([]StackFrame, 0, l-offset+1) 1545 } 1546 return r.vm.captureStack(stack, offset) 1547 } 1548 1549 // Interrupt a running JavaScript. The corresponding Go call will return an *InterruptedError containing v. 1550 // If the interrupt propagates until the stack is empty the currently queued promise resolve/reject jobs will be cleared 1551 // without being executed. This is the same time they would be executed otherwise. 1552 // Note, it only works while in JavaScript code, it does not interrupt native Go functions (which includes all built-ins). 1553 // If the runtime is currently not running, it will be immediately interrupted on the next Run*() call. 1554 // To avoid that use ClearInterrupt() 1555 func (r *Runtime) Interrupt(v interface{}) { 1556 r.vm.Interrupt(v) 1557 } 1558 1559 // ClearInterrupt resets the interrupt flag. Typically this needs to be called before the runtime 1560 // is made available for re-use if there is a chance it could have been interrupted with Interrupt(). 1561 // Otherwise if Interrupt() was called when runtime was not running (e.g. if it had already finished) 1562 // so that Interrupt() didn't actually trigger, an attempt to use the runtime will immediately cause 1563 // an interruption. It is up to the user to ensure proper synchronisation so that ClearInterrupt() is 1564 // only called when the runtime has finished and there is no chance of a concurrent Interrupt() call. 1565 func (r *Runtime) ClearInterrupt() { 1566 r.vm.ClearInterrupt() 1567 } 1568 1569 /* 1570 ToValue converts a Go value into a JavaScript value of a most appropriate type. Structural types (such as structs, maps 1571 and slices) are wrapped so that changes are reflected on the original value which can be retrieved using Value.Export(). 1572 1573 WARNING! These wrapped Go values do not behave in the same way as native ECMAScript values. If you plan to modify 1574 them in ECMAScript, bear in mind the following caveats: 1575 1576 1. If a regular JavaScript Object is assigned as an element of a wrapped Go struct, map or array, it is 1577 Export()'ed and therefore copied. This may result in an unexpected behaviour in JavaScript: 1578 1579 m := map[string]interface{}{} 1580 vm.Set("m", m) 1581 vm.RunString(` 1582 var obj = {test: false}; 1583 m.obj = obj; // obj gets Export()'ed, i.e. copied to a new map[string]interface{} and then this map is set as m["obj"] 1584 obj.test = true; // note, m.obj.test is still false 1585 `) 1586 fmt.Println(m["obj"].(map[string]interface{})["test"]) // prints "false" 1587 1588 2. Be careful with nested non-pointer compound types (structs, slices and arrays) if you modify them in 1589 ECMAScript. Better avoid it at all if possible. One of the fundamental differences between ECMAScript and Go is in 1590 the former all Objects are references whereas in Go you can have a literal struct or array. Consider the following 1591 example: 1592 1593 type S struct { 1594 Field int 1595 } 1596 1597 a := []S{{1}, {2}} // slice of literal structs 1598 vm.Set("a", &a) 1599 vm.RunString(` 1600 let tmp = {Field: 1}; 1601 a[0] = tmp; 1602 a[1] = tmp; 1603 tmp.Field = 2; 1604 `) 1605 1606 In ECMAScript one would expect a[0].Field and a[1].Field to be equal to 2, but this is really not possible 1607 (or at least non-trivial without some complex reference tracking). 1608 1609 To cover the most common use cases and to avoid excessive memory allocation, the following 'copy-on-change' mechanism 1610 is implemented (for both arrays and structs): 1611 1612 * When a nested compound value is accessed, the returned ES value becomes a reference to the literal value. 1613 This ensures that things like 'a[0].Field = 1' work as expected and simple access to 'a[0].Field' does not result 1614 in copying of a[0]. 1615 1616 * The original container ('a' in our case) keeps track of the returned reference value and if a[0] is reassigned 1617 (e.g. by direct assignment, deletion or shrinking the array) the old a[0] is copied and the earlier returned value 1618 becomes a reference to the copy: 1619 1620 let tmp = a[0]; // no copy, tmp is a reference to a[0] 1621 tmp.Field = 1; // a[0].Field === 1 after this 1622 a[0] = {Field: 2}; // tmp is now a reference to a copy of the old value (with Field === 1) 1623 a[0].Field === 2 && tmp.Field === 1; // true 1624 1625 * Array value swaps caused by in-place sort (using Array.prototype.sort()) do not count as re-assignments, instead 1626 the references are adjusted to point to the new indices. 1627 1628 * Assignment to an inner compound value always does a copy (and sometimes type conversion): 1629 1630 a[1] = tmp; // a[1] is now a copy of tmp 1631 tmp.Field = 3; // does not affect a[1].Field 1632 1633 3. Non-addressable structs, slices and arrays get copied. This sometimes may lead to a confusion as assigning to 1634 inner fields does not appear to work: 1635 1636 a1 := []interface{}{S{1}, S{2}} 1637 vm.Set("a1", &a1) 1638 vm.RunString(` 1639 a1[0].Field === 1; // true 1640 a1[0].Field = 2; 1641 a1[0].Field === 2; // FALSE, because what it really did was copy a1[0] set its Field to 2 and immediately drop it 1642 `) 1643 1644 An alternative would be making a1[0].Field a non-writable property which would probably be more in line with 1645 ECMAScript, however it would require to manually copy the value if it does need to be modified which may be 1646 impractical. 1647 1648 Note, the same applies to slices. If a slice is passed by value (not as a pointer), resizing the slice does not reflect on the original 1649 value. Moreover, extending the slice may result in the underlying array being re-allocated and copied. 1650 For example: 1651 1652 a := []interface{}{1} 1653 vm.Set("a", a) 1654 vm.RunString(`a.push(2); a[0] = 0;`) 1655 fmt.Println(a[0]) // prints "1" 1656 1657 Notes on individual types: 1658 1659 # Primitive types 1660 1661 Primitive types (numbers, string, bool) are converted to the corresponding JavaScript primitives. These values 1662 are goroutine-safe and can be transferred between runtimes. 1663 1664 # Strings 1665 1666 Because of the difference in internal string representation between ECMAScript (which uses UTF-16) and Go (which uses 1667 UTF-8) conversion from JS to Go may be lossy. In particular, code points that can be part of UTF-16 surrogate pairs 1668 (0xD800-0xDFFF) cannot be represented in UTF-8 unless they form a valid surrogate pair and are replaced with 1669 utf8.RuneError. 1670 1671 The string value must be a valid UTF-8. If it is not, invalid characters are replaced with utf8.RuneError, but 1672 the behaviour of a subsequent Export() is unspecified (it may return the original value, or a value with replaced 1673 invalid characters). 1674 1675 # Nil 1676 1677 Nil is converted to null. 1678 1679 # Functions 1680 1681 func(FunctionCall) Value is treated as a native JavaScript function. This increases performance because there are no 1682 automatic argument and return value type conversions (which involves reflect). Attempting to use 1683 the function as a constructor will result in a TypeError. Note: implementations must not retain and use references 1684 to FunctionCall.Arguments after the function returns. 1685 1686 func(FunctionCall, *Runtime) Value is treated as above, except the *Runtime is also passed as a parameter. 1687 1688 func(ConstructorCall) *Object is treated as a native constructor, allowing to use it with the new 1689 operator: 1690 1691 func MyObject(call goja.ConstructorCall) *goja.Object { 1692 // call.This contains the newly created object as per http://www.ecma-international.org/ecma-262/5.1/index.html#sec-13.2.2 1693 // call.Arguments contain arguments passed to the function 1694 1695 call.This.Set("method", method) 1696 1697 //... 1698 1699 // If return value is a non-nil *Object, it will be used instead of call.This 1700 // This way it is possible to return a Go struct or a map converted 1701 // into goja.Value using ToValue(), however in this case 1702 // instanceof will not work as expected, unless you set the prototype: 1703 // 1704 // instance := &myCustomStruct{} 1705 // instanceValue := vm.ToValue(instance).(*Object) 1706 // instanceValue.SetPrototype(call.This.Prototype()) 1707 // return instanceValue 1708 return nil 1709 } 1710 1711 runtime.Set("MyObject", MyObject) 1712 1713 Then it can be used in JS as follows: 1714 1715 var o = new MyObject(arg); 1716 var o1 = MyObject(arg); // same thing 1717 o instanceof MyObject && o1 instanceof MyObject; // true 1718 1719 When a native constructor is called directly (without the new operator) its behavior depends on 1720 this value: if it's an Object, it is passed through, otherwise a new one is created exactly as 1721 if it was called with the new operator. In either case call.NewTarget will be nil. 1722 1723 func(ConstructorCall, *Runtime) *Object is treated as above, except the *Runtime is also passed as a parameter. 1724 1725 Any other Go function is wrapped so that the arguments are automatically converted into the required Go types and the 1726 return value is converted to a JavaScript value (using this method). If conversion is not possible, a TypeError is 1727 thrown. 1728 1729 Functions with multiple return values return an Array. If the last return value is an `error` it is not returned but 1730 converted into a JS exception. If the error is *Exception, it is thrown as is, otherwise it's wrapped in a GoEerror. 1731 Note that if there are exactly two return values and the last is an `error`, the function returns the first value as is, 1732 not an Array. 1733 1734 # Structs 1735 1736 Structs are converted to Object-like values. Fields and methods are available as properties, their values are 1737 results of this method (ToValue()) applied to the corresponding Go value. 1738 1739 Field properties are writable and non-configurable. Method properties are non-writable and non-configurable. 1740 1741 Attempt to define a new property or delete an existing property will fail (throw in strict mode) unless it's a Symbol 1742 property. Symbol properties only exist in the wrapper and do not affect the underlying Go value. 1743 Note that because a wrapper is created every time a property is accessed it may lead to unexpected results such as this: 1744 1745 type Field struct{ 1746 } 1747 type S struct { 1748 Field *Field 1749 } 1750 var s = S{ 1751 Field: &Field{}, 1752 } 1753 vm := New() 1754 vm.Set("s", &s) 1755 res, err := vm.RunString(` 1756 var sym = Symbol(66); 1757 var field1 = s.Field; 1758 field1[sym] = true; 1759 var field2 = s.Field; 1760 field1 === field2; // true, because the equality operation compares the wrapped values, not the wrappers 1761 field1[sym] === true; // true 1762 field2[sym] === undefined; // also true 1763 `) 1764 1765 The same applies to values from maps and slices as well. 1766 1767 # Handling of time.Time 1768 1769 time.Time does not get special treatment and therefore is converted just like any other `struct` providing access to 1770 all its methods. This is done deliberately instead of converting it to a `Date` because these two types are not fully 1771 compatible: `time.Time` includes zone, whereas JS `Date` doesn't. Doing the conversion implicitly therefore would 1772 result in a loss of information. 1773 1774 If you need to convert it to a `Date`, it can be done either in JS: 1775 1776 var d = new Date(goval.UnixNano()/1e6); 1777 1778 ... or in Go: 1779 1780 now := time.Now() 1781 vm := New() 1782 val, err := vm.New(vm.Get("Date").ToObject(vm), vm.ToValue(now.UnixNano()/1e6)) 1783 if err != nil { 1784 ... 1785 } 1786 vm.Set("d", val) 1787 1788 Note that Value.Export() for a `Date` value returns time.Time in local timezone. 1789 1790 # Maps 1791 1792 Maps with string or integer key type are converted into host objects that largely behave like a JavaScript Object. 1793 1794 # Maps with methods 1795 1796 If a map type has at least one method defined, the properties of the resulting Object represent methods, not map keys. 1797 This is because in JavaScript there is no distinction between 'object.key` and `object[key]`, unlike Go. 1798 If access to the map values is required, it can be achieved by defining another method or, if it's not possible, by 1799 defining an external getter function. 1800 1801 # Slices 1802 1803 Slices are converted into host objects that behave largely like JavaScript Array. It has the appropriate 1804 prototype and all the usual methods should work. There is, however, a caveat: converted Arrays may not contain holes 1805 (because Go slices cannot). This means that hasOwnProperty(n) always returns `true` if n < length. Deleting an item with 1806 an index < length will set it to a zero value (but the property will remain). Nil slice elements are be converted to 1807 `null`. Accessing an element beyond `length` returns `undefined`. Also see the warning above about passing slices as 1808 values (as opposed to pointers). 1809 1810 # Arrays 1811 1812 Arrays are converted similarly to slices, except the resulting Arrays are not resizable (and therefore the 'length' 1813 property is non-writable). 1814 1815 Any other type is converted to a generic reflect based host object. Depending on the underlying type it behaves similar 1816 to a Number, String, Boolean or Object. 1817 1818 Note that the underlying type is not lost, calling Export() returns the original Go value. This applies to all 1819 reflect based types. 1820 */ 1821 func (r *Runtime) ToValue(i interface{}) Value { 1822 return r.toValue(i, reflect.Value{}) 1823 } 1824 1825 func (r *Runtime) toValue(i interface{}, origValue reflect.Value) Value { 1826 switch i := i.(type) { 1827 case nil: 1828 return _null 1829 case *Object: 1830 if i == nil || i.self == nil { 1831 return _null 1832 } 1833 if i.runtime != nil && i.runtime != r { 1834 panic(r.NewTypeError("Illegal runtime transition of an Object")) 1835 } 1836 return i 1837 case valueContainer: 1838 return i.toValue(r) 1839 case Value: 1840 return i 1841 case string: 1842 if len(i) <= 16 { 1843 if u := unistring.Scan(i); u != nil { 1844 return &importedString{s: i, u: u, scanned: true} 1845 } 1846 return asciiString(i) 1847 } 1848 return &importedString{s: i} 1849 case bool: 1850 if i { 1851 return valueTrue 1852 } else { 1853 return valueFalse 1854 } 1855 case func(FunctionCall) Value: 1856 name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) 1857 return r.newNativeFunc(i, nil, name, nil, 0) 1858 case func(FunctionCall, *Runtime) Value: 1859 name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) 1860 return r.newNativeFunc(func(call FunctionCall) Value { 1861 return i(call, r) 1862 }, nil, name, nil, 0) 1863 case func(ConstructorCall) *Object: 1864 name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) 1865 return r.newNativeConstructor(i, name, 0) 1866 case func(ConstructorCall, *Runtime) *Object: 1867 name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) 1868 return r.newNativeConstructor(func(call ConstructorCall) *Object { 1869 return i(call, r) 1870 }, name, 0) 1871 case int: 1872 return intToValue(int64(i)) 1873 case int8: 1874 return intToValue(int64(i)) 1875 case int16: 1876 return intToValue(int64(i)) 1877 case int32: 1878 return intToValue(int64(i)) 1879 case int64: 1880 return intToValue(i) 1881 case uint: 1882 if uint64(i) <= math.MaxInt64 { 1883 return intToValue(int64(i)) 1884 } else { 1885 return floatToValue(float64(i)) 1886 } 1887 case uint8: 1888 return intToValue(int64(i)) 1889 case uint16: 1890 return intToValue(int64(i)) 1891 case uint32: 1892 return intToValue(int64(i)) 1893 case uint64: 1894 if i <= math.MaxInt64 { 1895 return intToValue(int64(i)) 1896 } 1897 return floatToValue(float64(i)) 1898 case float32: 1899 return floatToValue(float64(i)) 1900 case float64: 1901 return floatToValue(i) 1902 case map[string]interface{}: 1903 if i == nil { 1904 return _null 1905 } 1906 obj := &Object{runtime: r} 1907 m := &objectGoMapSimple{ 1908 baseObject: baseObject{ 1909 val: obj, 1910 extensible: true, 1911 }, 1912 data: i, 1913 } 1914 obj.self = m 1915 m.init() 1916 return obj 1917 case []interface{}: 1918 return r.newObjectGoSlice(&i, false).val 1919 case *[]interface{}: 1920 if i == nil { 1921 return _null 1922 } 1923 return r.newObjectGoSlice(i, true).val 1924 } 1925 1926 if !origValue.IsValid() { 1927 origValue = reflect.ValueOf(i) 1928 } 1929 1930 value := origValue 1931 for value.Kind() == reflect.Ptr { 1932 value = value.Elem() 1933 } 1934 1935 if !value.IsValid() { 1936 return _null 1937 } 1938 1939 switch value.Kind() { 1940 case reflect.Map: 1941 if value.Type().NumMethod() == 0 { 1942 switch value.Type().Key().Kind() { 1943 case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 1944 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 1945 reflect.Float64, reflect.Float32: 1946 1947 obj := &Object{runtime: r} 1948 m := &objectGoMapReflect{ 1949 objectGoReflect: objectGoReflect{ 1950 baseObject: baseObject{ 1951 val: obj, 1952 extensible: true, 1953 }, 1954 origValue: origValue, 1955 fieldsValue: value, 1956 }, 1957 } 1958 m.init() 1959 obj.self = m 1960 return obj 1961 } 1962 } 1963 case reflect.Array: 1964 obj := &Object{runtime: r} 1965 a := &objectGoArrayReflect{ 1966 objectGoReflect: objectGoReflect{ 1967 baseObject: baseObject{ 1968 val: obj, 1969 }, 1970 origValue: origValue, 1971 fieldsValue: value, 1972 }, 1973 } 1974 a.init() 1975 obj.self = a 1976 return obj 1977 case reflect.Slice: 1978 obj := &Object{runtime: r} 1979 a := &objectGoSliceReflect{ 1980 objectGoArrayReflect: objectGoArrayReflect{ 1981 objectGoReflect: objectGoReflect{ 1982 baseObject: baseObject{ 1983 val: obj, 1984 }, 1985 origValue: origValue, 1986 fieldsValue: value, 1987 }, 1988 }, 1989 } 1990 a.init() 1991 obj.self = a 1992 return obj 1993 case reflect.Func: 1994 return r.newWrappedFunc(value) 1995 } 1996 1997 obj := &Object{runtime: r} 1998 o := &objectGoReflect{ 1999 baseObject: baseObject{ 2000 val: obj, 2001 }, 2002 origValue: origValue, 2003 fieldsValue: value, 2004 } 2005 obj.self = o 2006 o.init() 2007 return obj 2008 } 2009 2010 func (r *Runtime) wrapReflectFunc(value reflect.Value) func(FunctionCall) Value { 2011 return func(call FunctionCall) Value { 2012 typ := value.Type() 2013 nargs := typ.NumIn() 2014 var in []reflect.Value 2015 2016 if l := len(call.Arguments); l < nargs { 2017 // fill missing arguments with zero values 2018 n := nargs 2019 if typ.IsVariadic() { 2020 n-- 2021 } 2022 in = make([]reflect.Value, n) 2023 for i := l; i < n; i++ { 2024 in[i] = reflect.Zero(typ.In(i)) 2025 } 2026 } else { 2027 if l > nargs && !typ.IsVariadic() { 2028 l = nargs 2029 } 2030 in = make([]reflect.Value, l) 2031 } 2032 2033 for i, a := range call.Arguments { 2034 var t reflect.Type 2035 2036 n := i 2037 if n >= nargs-1 && typ.IsVariadic() { 2038 if n > nargs-1 { 2039 n = nargs - 1 2040 } 2041 2042 t = typ.In(n).Elem() 2043 } else if n > nargs-1 { // ignore extra arguments 2044 break 2045 } else { 2046 t = typ.In(n) 2047 } 2048 2049 v := reflect.New(t).Elem() 2050 err := r.toReflectValue(a, v, &objectExportCtx{}) 2051 if err != nil { 2052 panic(r.NewTypeError("could not convert function call parameter %d: %v", i, err)) 2053 } 2054 in[i] = v 2055 } 2056 2057 out := value.Call(in) 2058 if len(out) == 0 { 2059 return _undefined 2060 } 2061 2062 if last := out[len(out)-1]; last.Type() == reflectTypeError { 2063 if !last.IsNil() { 2064 err := last.Interface().(error) 2065 if _, ok := err.(*Exception); ok { 2066 panic(err) 2067 } 2068 if isUncatchableException(err) { 2069 panic(err) 2070 } 2071 panic(r.NewGoError(err)) 2072 } 2073 out = out[:len(out)-1] 2074 } 2075 2076 switch len(out) { 2077 case 0: 2078 return _undefined 2079 case 1: 2080 return r.ToValue(out[0].Interface()) 2081 default: 2082 s := make([]interface{}, len(out)) 2083 for i, v := range out { 2084 s[i] = v.Interface() 2085 } 2086 2087 return r.ToValue(s) 2088 } 2089 } 2090 } 2091 2092 func (r *Runtime) toReflectValue(v Value, dst reflect.Value, ctx *objectExportCtx) error { 2093 typ := dst.Type() 2094 2095 if typ == typeValue { 2096 dst.Set(reflect.ValueOf(v)) 2097 return nil 2098 } 2099 2100 if typ == typeObject { 2101 if obj, ok := v.(*Object); ok { 2102 dst.Set(reflect.ValueOf(obj)) 2103 return nil 2104 } 2105 } 2106 2107 if typ == typeCallable { 2108 if fn, ok := AssertFunction(v); ok { 2109 dst.Set(reflect.ValueOf(fn)) 2110 return nil 2111 } 2112 } 2113 2114 et := v.ExportType() 2115 if et == nil || et == reflectTypeNil { 2116 dst.Set(reflect.Zero(typ)) 2117 return nil 2118 } 2119 2120 kind := typ.Kind() 2121 for i := 0; ; i++ { 2122 if et.AssignableTo(typ) { 2123 ev := reflect.ValueOf(exportValue(v, ctx)) 2124 for ; i > 0; i-- { 2125 ev = ev.Elem() 2126 } 2127 dst.Set(ev) 2128 return nil 2129 } 2130 expKind := et.Kind() 2131 if expKind == kind && et.ConvertibleTo(typ) || expKind == reflect.String && typ == typeBytes { 2132 ev := reflect.ValueOf(exportValue(v, ctx)) 2133 for ; i > 0; i-- { 2134 ev = ev.Elem() 2135 } 2136 dst.Set(ev.Convert(typ)) 2137 return nil 2138 } 2139 if expKind == reflect.Ptr { 2140 et = et.Elem() 2141 } else { 2142 break 2143 } 2144 } 2145 2146 if typ == typeTime { 2147 if obj, ok := v.(*Object); ok { 2148 if d, ok := obj.self.(*dateObject); ok { 2149 dst.Set(reflect.ValueOf(d.time())) 2150 return nil 2151 } 2152 } 2153 if et.Kind() == reflect.String { 2154 tme, ok := dateParse(v.String()) 2155 if !ok { 2156 return fmt.Errorf("could not convert string %v to %v", v, typ) 2157 } 2158 dst.Set(reflect.ValueOf(tme)) 2159 return nil 2160 } 2161 } 2162 2163 switch kind { 2164 case reflect.String: 2165 dst.Set(reflect.ValueOf(v.String()).Convert(typ)) 2166 return nil 2167 case reflect.Bool: 2168 dst.Set(reflect.ValueOf(v.ToBoolean()).Convert(typ)) 2169 return nil 2170 case reflect.Int: 2171 dst.Set(reflect.ValueOf(toInt(v)).Convert(typ)) 2172 return nil 2173 case reflect.Int64: 2174 dst.Set(reflect.ValueOf(toInt64(v)).Convert(typ)) 2175 return nil 2176 case reflect.Int32: 2177 dst.Set(reflect.ValueOf(toInt32(v)).Convert(typ)) 2178 return nil 2179 case reflect.Int16: 2180 dst.Set(reflect.ValueOf(toInt16(v)).Convert(typ)) 2181 return nil 2182 case reflect.Int8: 2183 dst.Set(reflect.ValueOf(toInt8(v)).Convert(typ)) 2184 return nil 2185 case reflect.Uint: 2186 dst.Set(reflect.ValueOf(toUint(v)).Convert(typ)) 2187 return nil 2188 case reflect.Uint64: 2189 dst.Set(reflect.ValueOf(toUint64(v)).Convert(typ)) 2190 return nil 2191 case reflect.Uint32: 2192 dst.Set(reflect.ValueOf(toUint32(v)).Convert(typ)) 2193 return nil 2194 case reflect.Uint16: 2195 dst.Set(reflect.ValueOf(toUint16(v)).Convert(typ)) 2196 return nil 2197 case reflect.Uint8: 2198 dst.Set(reflect.ValueOf(toUint8(v)).Convert(typ)) 2199 return nil 2200 case reflect.Float64: 2201 dst.Set(reflect.ValueOf(v.ToFloat()).Convert(typ)) 2202 return nil 2203 case reflect.Float32: 2204 dst.Set(reflect.ValueOf(toFloat32(v)).Convert(typ)) 2205 return nil 2206 case reflect.Slice, reflect.Array: 2207 if o, ok := v.(*Object); ok { 2208 if v, exists := ctx.getTyped(o, typ); exists { 2209 dst.Set(reflect.ValueOf(v)) 2210 return nil 2211 } 2212 return o.self.exportToArrayOrSlice(dst, typ, ctx) 2213 } 2214 case reflect.Map: 2215 if o, ok := v.(*Object); ok { 2216 if v, exists := ctx.getTyped(o, typ); exists { 2217 dst.Set(reflect.ValueOf(v)) 2218 return nil 2219 } 2220 return o.self.exportToMap(dst, typ, ctx) 2221 } 2222 case reflect.Struct: 2223 if o, ok := v.(*Object); ok { 2224 t := reflect.PtrTo(typ) 2225 if v, exists := ctx.getTyped(o, t); exists { 2226 dst.Set(reflect.ValueOf(v).Elem()) 2227 return nil 2228 } 2229 s := dst 2230 ctx.putTyped(o, t, s.Addr().Interface()) 2231 for i := 0; i < typ.NumField(); i++ { 2232 field := typ.Field(i) 2233 if ast.IsExported(field.Name) { 2234 name := field.Name 2235 if r.fieldNameMapper != nil { 2236 name = r.fieldNameMapper.FieldName(typ, field) 2237 } 2238 var v Value 2239 if field.Anonymous { 2240 v = o 2241 } else { 2242 v = o.self.getStr(unistring.NewFromString(name), nil) 2243 } 2244 2245 if v != nil { 2246 err := r.toReflectValue(v, s.Field(i), ctx) 2247 if err != nil { 2248 return fmt.Errorf("could not convert struct value %v to %v for field %s: %w", v, field.Type, field.Name, err) 2249 } 2250 } 2251 } 2252 } 2253 return nil 2254 } 2255 case reflect.Func: 2256 if fn, ok := AssertFunction(v); ok { 2257 dst.Set(reflect.MakeFunc(typ, r.wrapJSFunc(fn, typ))) 2258 return nil 2259 } 2260 case reflect.Ptr: 2261 if o, ok := v.(*Object); ok { 2262 if v, exists := ctx.getTyped(o, typ); exists { 2263 dst.Set(reflect.ValueOf(v)) 2264 return nil 2265 } 2266 } 2267 if dst.IsNil() { 2268 dst.Set(reflect.New(typ.Elem())) 2269 } 2270 return r.toReflectValue(v, dst.Elem(), ctx) 2271 } 2272 2273 return fmt.Errorf("could not convert %v to %v", v, typ) 2274 } 2275 2276 func (r *Runtime) wrapJSFunc(fn Callable, typ reflect.Type) func(args []reflect.Value) (results []reflect.Value) { 2277 return func(args []reflect.Value) (results []reflect.Value) { 2278 jsArgs := make([]Value, len(args)) 2279 for i, arg := range args { 2280 jsArgs[i] = r.ToValue(arg.Interface()) 2281 } 2282 2283 numOut := typ.NumOut() 2284 results = make([]reflect.Value, numOut) 2285 res, err := fn(_undefined, jsArgs...) 2286 if err == nil { 2287 if numOut > 0 { 2288 v := reflect.New(typ.Out(0)).Elem() 2289 err = r.toReflectValue(res, v, &objectExportCtx{}) 2290 if err == nil { 2291 results[0] = v 2292 } 2293 } 2294 } 2295 2296 if err != nil { 2297 if numOut > 0 && typ.Out(numOut-1) == reflectTypeError { 2298 if ex, ok := err.(*Exception); ok { 2299 if exo, ok := ex.val.(*Object); ok { 2300 if v := exo.self.getStr("value", nil); v != nil { 2301 if v.ExportType().AssignableTo(reflectTypeError) { 2302 err = v.Export().(error) 2303 } 2304 } 2305 } 2306 } 2307 results[numOut-1] = reflect.ValueOf(err).Convert(typ.Out(numOut - 1)) 2308 } else { 2309 panic(err) 2310 } 2311 } 2312 2313 for i, v := range results { 2314 if !v.IsValid() { 2315 results[i] = reflect.Zero(typ.Out(i)) 2316 } 2317 } 2318 2319 return 2320 } 2321 } 2322 2323 // ExportTo converts a JavaScript value into the specified Go value. The second parameter must be a non-nil pointer. 2324 // Returns error if conversion is not possible. 2325 // 2326 // Notes on specific cases: 2327 // 2328 // # Empty interface 2329 // 2330 // Exporting to an interface{} results in a value of the same type as Value.Export() would produce. 2331 // 2332 // # Numeric types 2333 // 2334 // Exporting to numeric types uses the standard ECMAScript conversion operations, same as used when assigning 2335 // values to non-clamped typed array items, e.g. https://262.ecma-international.org/#sec-toint32. 2336 // 2337 // # Functions 2338 // 2339 // Exporting to a 'func' creates a strictly typed 'gateway' into an ES function which can be called from Go. 2340 // The arguments are converted into ES values using Runtime.ToValue(). If the func has no return values, 2341 // the return value is ignored. If the func has exactly one return value, it is converted to the appropriate 2342 // type using ExportTo(). If the last return value is 'error', exceptions are caught and returned as *Exception 2343 // (instances of GoError are unwrapped, i.e. their 'value' is returned instead). In all other cases exceptions 2344 // result in a panic. Any extra return values are zeroed. 2345 // 2346 // 'this' value will always be set to 'undefined'. 2347 // 2348 // For a more low-level mechanism see AssertFunction(). 2349 // 2350 // # Map types 2351 // 2352 // An ES Map can be exported into a Go map type. If any exported key value is non-hashable, the operation panics 2353 // (as reflect.Value.SetMapIndex() would). Symbol.iterator is ignored. 2354 // 2355 // Exporting an ES Set into a map type results in the map being populated with (element) -> (zero value) key/value 2356 // pairs. If any value is non-hashable, the operation panics (as reflect.Value.SetMapIndex() would). 2357 // Symbol.iterator is ignored. 2358 // 2359 // Any other Object populates the map with own enumerable non-symbol properties. 2360 // 2361 // # Slice types 2362 // 2363 // Exporting an ES Set into a slice type results in its elements being exported. 2364 // 2365 // Exporting any Object that implements the iterable protocol (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) 2366 // into a slice type results in the slice being populated with the results of the iteration. 2367 // 2368 // Array is treated as iterable (i.e. overwriting Symbol.iterator affects the result). 2369 // 2370 // If an object has a 'length' property and is not a function it is treated as array-like. The resulting slice 2371 // will contain obj[0], ... obj[length-1]. 2372 // 2373 // ArrayBuffer and ArrayBuffer-backed types (i.e. typed arrays and DataView) can be exported into []byte. The result 2374 // is backed by the original data, no copy is performed. 2375 // 2376 // For any other Object an error is returned. 2377 // 2378 // # Array types 2379 // 2380 // Anything that can be exported to a slice type can also be exported to an array type, as long as the lengths 2381 // match. If they do not, an error is returned. 2382 // 2383 // # Proxy 2384 // 2385 // Proxy objects are treated the same way as if they were accessed from ES code in regard to their properties 2386 // (such as 'length' or [Symbol.iterator]). This means exporting them to slice types works, however 2387 // exporting a proxied Map into a map type does not produce its contents, because the Proxy is not recognised 2388 // as a Map. Same applies to a proxied Set. 2389 func (r *Runtime) ExportTo(v Value, target interface{}) error { 2390 tval := reflect.ValueOf(target) 2391 if tval.Kind() != reflect.Ptr || tval.IsNil() { 2392 return errors.New("target must be a non-nil pointer") 2393 } 2394 return r.toReflectValue(v, tval.Elem(), &objectExportCtx{}) 2395 } 2396 2397 // GlobalObject returns the global object. 2398 func (r *Runtime) GlobalObject() *Object { 2399 return r.globalObject 2400 } 2401 2402 // Set the specified variable in the global context. 2403 // Equivalent to running "name = value" in non-strict mode. 2404 // The value is first converted using ToValue(). 2405 // Note, this is not the same as GlobalObject().Set(name, value), 2406 // because if a global lexical binding (let or const) exists, it is set instead. 2407 func (r *Runtime) Set(name string, value interface{}) error { 2408 return r.try(func() { 2409 name := unistring.NewFromString(name) 2410 v := r.ToValue(value) 2411 if ref := r.global.stash.getRefByName(name, false); ref != nil { 2412 ref.set(v) 2413 } else { 2414 r.globalObject.self.setOwnStr(name, v, true) 2415 } 2416 }) 2417 } 2418 2419 // Get the specified variable in the global context. 2420 // Equivalent to dereferencing a variable by name in non-strict mode. If variable is not defined returns nil. 2421 // Note, this is not the same as GlobalObject().Get(name), 2422 // because if a global lexical binding (let or const) exists, it is used instead. 2423 // This method will panic with an *Exception if a JavaScript exception is thrown in the process. 2424 func (r *Runtime) Get(name string) Value { 2425 n := unistring.NewFromString(name) 2426 if v, exists := r.global.stash.getByName(n); exists { 2427 return v 2428 } else { 2429 return r.globalObject.self.getStr(n, nil) 2430 } 2431 } 2432 2433 // SetRandSource sets random source for this Runtime. If not called, the default math/rand is used. 2434 func (r *Runtime) SetRandSource(source RandSource) { 2435 r.rand = source 2436 } 2437 2438 // SetTimeSource sets the current time source for this Runtime. 2439 // If not called, the default time.Now() is used. 2440 func (r *Runtime) SetTimeSource(now Now) { 2441 r.now = now 2442 } 2443 2444 // SetParserOptions sets parser options to be used by RunString, RunScript and eval() within the code. 2445 func (r *Runtime) SetParserOptions(opts ...parser.Option) { 2446 r.parserOptions = opts 2447 } 2448 2449 // SetMaxCallStackSize sets the maximum function call depth. When exceeded, a *StackOverflowError is thrown and 2450 // returned by RunProgram or by a Callable call. This is useful to prevent memory exhaustion caused by an 2451 // infinite recursion. The default value is math.MaxInt32. 2452 // This method (as the rest of the Set* methods) is not safe for concurrent use and may only be called 2453 // from the vm goroutine or when the vm is not running. 2454 func (r *Runtime) SetMaxCallStackSize(size int) { 2455 r.vm.maxCallStackSize = size 2456 } 2457 2458 // New is an equivalent of the 'new' operator allowing to call it directly from Go. 2459 func (r *Runtime) New(construct Value, args ...Value) (o *Object, err error) { 2460 err = r.try(func() { 2461 o = r.builtin_new(r.toObject(construct), args) 2462 }) 2463 return 2464 } 2465 2466 // Callable represents a JavaScript function that can be called from Go. 2467 type Callable func(this Value, args ...Value) (Value, error) 2468 2469 // AssertFunction checks if the Value is a function and returns a Callable. 2470 // Note, for classes this returns a callable and a 'true', however calling it will always result in a TypeError. 2471 // For classes use AssertConstructor(). 2472 func AssertFunction(v Value) (Callable, bool) { 2473 if obj, ok := v.(*Object); ok { 2474 if f, ok := obj.self.assertCallable(); ok { 2475 return func(this Value, args ...Value) (ret Value, err error) { 2476 err = obj.runtime.runWrapped(func() { 2477 ret = f(FunctionCall{ 2478 This: this, 2479 Arguments: args, 2480 }) 2481 }) 2482 return 2483 }, true 2484 } 2485 } 2486 return nil, false 2487 } 2488 2489 // Constructor is a type that can be used to call constructors. The first argument (newTarget) can be nil 2490 // which sets it to the constructor function itself. 2491 type Constructor func(newTarget *Object, args ...Value) (*Object, error) 2492 2493 // AssertConstructor checks if the Value is a constructor and returns a Constructor. 2494 func AssertConstructor(v Value) (Constructor, bool) { 2495 if obj, ok := v.(*Object); ok { 2496 if ctor := obj.self.assertConstructor(); ctor != nil { 2497 return func(newTarget *Object, args ...Value) (ret *Object, err error) { 2498 err = obj.runtime.runWrapped(func() { 2499 ret = ctor(args, newTarget) 2500 }) 2501 return 2502 }, true 2503 } 2504 } 2505 return nil, false 2506 } 2507 2508 func (r *Runtime) runWrapped(f func()) (err error) { 2509 defer func() { 2510 if x := recover(); x != nil { 2511 if ex := asUncatchableException(x); ex != nil { 2512 err = ex 2513 if len(r.vm.callStack) == 0 { 2514 r.leaveAbrupt() 2515 } 2516 } else { 2517 panic(x) 2518 } 2519 } 2520 }() 2521 ex := r.vm.try(f) 2522 if ex != nil { 2523 err = ex 2524 } 2525 if len(r.vm.callStack) == 0 { 2526 r.leave() 2527 } else { 2528 r.vm.clearStack() 2529 } 2530 return 2531 } 2532 2533 // IsUndefined returns true if the supplied Value is undefined. Note, it checks against the real undefined, not 2534 // against the global object's 'undefined' property. 2535 func IsUndefined(v Value) bool { 2536 return v == _undefined 2537 } 2538 2539 // IsNull returns true if the supplied Value is null. 2540 func IsNull(v Value) bool { 2541 return v == _null 2542 } 2543 2544 // IsNaN returns true if the supplied value is NaN. 2545 func IsNaN(v Value) bool { 2546 f, ok := v.(valueFloat) 2547 return ok && math.IsNaN(float64(f)) 2548 } 2549 2550 // IsInfinity returns true if the supplied is (+/-)Infinity 2551 func IsInfinity(v Value) bool { 2552 return v == _positiveInf || v == _negativeInf 2553 } 2554 2555 // Undefined returns JS undefined value. Note if global 'undefined' property is changed this still returns the original value. 2556 func Undefined() Value { 2557 return _undefined 2558 } 2559 2560 // Null returns JS null value. 2561 func Null() Value { 2562 return _null 2563 } 2564 2565 // NaN returns a JS NaN value. 2566 func NaN() Value { 2567 return _NaN 2568 } 2569 2570 // PositiveInf returns a JS +Inf value. 2571 func PositiveInf() Value { 2572 return _positiveInf 2573 } 2574 2575 // NegativeInf returns a JS -Inf value. 2576 func NegativeInf() Value { 2577 return _negativeInf 2578 } 2579 2580 func tryFunc(f func()) (ret interface{}) { 2581 defer func() { 2582 ret = recover() 2583 }() 2584 2585 f() 2586 return 2587 } 2588 2589 // Try runs a given function catching and returning any JS exception. Use this method to run any code 2590 // that may throw exceptions (such as Object.Get, Object.String, Object.ToInteger, Object.Export, Runtime.Get, Runtime.InstanceOf, etc.) 2591 // outside the Runtime execution context (i.e. when calling directly from Go, not from a JS function implemented in Go). 2592 func (r *Runtime) Try(f func()) *Exception { 2593 return r.vm.try(f) 2594 } 2595 2596 func (r *Runtime) try(f func()) error { 2597 if ex := r.vm.try(f); ex != nil { 2598 return ex 2599 } 2600 return nil 2601 } 2602 2603 func (r *Runtime) toObject(v Value, args ...interface{}) *Object { 2604 if obj, ok := v.(*Object); ok { 2605 return obj 2606 } 2607 if len(args) > 0 { 2608 panic(r.NewTypeError(args...)) 2609 } else { 2610 var s string 2611 if v == nil { 2612 s = "undefined" 2613 } else { 2614 s = v.String() 2615 } 2616 panic(r.NewTypeError("Value is not an object: %s", s)) 2617 } 2618 } 2619 2620 func (r *Runtime) speciesConstructor(o, defaultConstructor *Object) func(args []Value, newTarget *Object) *Object { 2621 c := o.self.getStr("constructor", nil) 2622 if c != nil && c != _undefined { 2623 c = r.toObject(c).self.getSym(SymSpecies, nil) 2624 } 2625 if c == nil || c == _undefined || c == _null { 2626 c = defaultConstructor 2627 } 2628 return r.toConstructor(c) 2629 } 2630 2631 func (r *Runtime) speciesConstructorObj(o, defaultConstructor *Object) *Object { 2632 c := o.self.getStr("constructor", nil) 2633 if c != nil && c != _undefined { 2634 c = r.toObject(c).self.getSym(SymSpecies, nil) 2635 } 2636 if c == nil || c == _undefined || c == _null { 2637 return defaultConstructor 2638 } 2639 obj := r.toObject(c) 2640 if obj.self.assertConstructor() == nil { 2641 panic(r.NewTypeError("Value is not a constructor")) 2642 } 2643 return obj 2644 } 2645 2646 func (r *Runtime) returnThis(call FunctionCall) Value { 2647 return call.This 2648 } 2649 2650 func createDataProperty(o *Object, p Value, v Value) { 2651 o.defineOwnProperty(p, PropertyDescriptor{ 2652 Writable: FLAG_TRUE, 2653 Enumerable: FLAG_TRUE, 2654 Configurable: FLAG_TRUE, 2655 Value: v, 2656 }, false) 2657 } 2658 2659 func createDataPropertyOrThrow(o *Object, p Value, v Value) { 2660 o.defineOwnProperty(p, PropertyDescriptor{ 2661 Writable: FLAG_TRUE, 2662 Enumerable: FLAG_TRUE, 2663 Configurable: FLAG_TRUE, 2664 Value: v, 2665 }, true) 2666 } 2667 2668 func toPropertyKey(key Value) Value { 2669 return key.ToString() 2670 } 2671 2672 func (r *Runtime) getVStr(v Value, p unistring.String) Value { 2673 o := v.ToObject(r) 2674 return o.self.getStr(p, v) 2675 } 2676 2677 func (r *Runtime) getV(v Value, p Value) Value { 2678 o := v.ToObject(r) 2679 return o.get(p, v) 2680 } 2681 2682 type iteratorRecord struct { 2683 iterator *Object 2684 next func(FunctionCall) Value 2685 } 2686 2687 func (r *Runtime) getIterator(obj Value, method func(FunctionCall) Value) *iteratorRecord { 2688 if method == nil { 2689 method = toMethod(r.getV(obj, SymIterator)) 2690 if method == nil { 2691 panic(r.NewTypeError("object is not iterable")) 2692 } 2693 } 2694 2695 iter := r.toObject(method(FunctionCall{ 2696 This: obj, 2697 })) 2698 2699 var next func(FunctionCall) Value 2700 2701 if obj, ok := iter.self.getStr("next", nil).(*Object); ok { 2702 if call, ok := obj.self.assertCallable(); ok { 2703 next = call 2704 } 2705 } 2706 2707 return &iteratorRecord{ 2708 iterator: iter, 2709 next: next, 2710 } 2711 } 2712 2713 func iteratorComplete(iterResult *Object) bool { 2714 return nilSafe(iterResult.self.getStr("done", nil)).ToBoolean() 2715 } 2716 2717 func iteratorValue(iterResult *Object) Value { 2718 return nilSafe(iterResult.self.getStr("value", nil)) 2719 } 2720 2721 func (ir *iteratorRecord) iterate(step func(Value)) { 2722 r := ir.iterator.runtime 2723 for { 2724 if ir.next == nil { 2725 panic(r.NewTypeError("iterator.next is missing or not a function")) 2726 } 2727 res := r.toObject(ir.next(FunctionCall{This: ir.iterator})) 2728 if iteratorComplete(res) { 2729 break 2730 } 2731 value := iteratorValue(res) 2732 ret := tryFunc(func() { 2733 step(value) 2734 }) 2735 if ret != nil { 2736 _ = tryFunc(func() { 2737 ir.returnIter() 2738 }) 2739 panic(ret) 2740 } 2741 } 2742 } 2743 2744 func (ir *iteratorRecord) step() (value Value, ex *Exception) { 2745 r := ir.iterator.runtime 2746 ex = r.vm.try(func() { 2747 res := r.toObject(ir.next(FunctionCall{This: ir.iterator})) 2748 done := iteratorComplete(res) 2749 if !done { 2750 value = iteratorValue(res) 2751 } else { 2752 ir.close() 2753 } 2754 }) 2755 return 2756 } 2757 2758 func (ir *iteratorRecord) returnIter() { 2759 if ir.iterator == nil { 2760 return 2761 } 2762 retMethod := toMethod(ir.iterator.self.getStr("return", nil)) 2763 if retMethod != nil { 2764 ir.iterator.runtime.toObject(retMethod(FunctionCall{This: ir.iterator})) 2765 } 2766 ir.iterator = nil 2767 ir.next = nil 2768 } 2769 2770 func (ir *iteratorRecord) close() { 2771 ir.iterator = nil 2772 ir.next = nil 2773 } 2774 2775 // ForOf is a Go equivalent of for-of loop. The function panics if an exception is thrown at any point 2776 // while iterating, including if the supplied value is not iterable 2777 // (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol). 2778 // When using outside of Runtime.Run (i.e. when calling directly from Go code, not from a JS function implemented 2779 // in Go) it must be enclosed in Try. See the example. 2780 func (r *Runtime) ForOf(iterable Value, step func(curValue Value) (continueIteration bool)) { 2781 iter := r.getIterator(iterable, nil) 2782 for { 2783 value, ex := iter.step() 2784 if ex != nil { 2785 panic(ex) 2786 } 2787 if value != nil { 2788 var continueIteration bool 2789 ex := r.vm.try(func() { 2790 continueIteration = step(value) 2791 }) 2792 if ex != nil { 2793 iter.returnIter() 2794 panic(ex) 2795 } 2796 if !continueIteration { 2797 iter.returnIter() 2798 break 2799 } 2800 } else { 2801 break 2802 } 2803 } 2804 } 2805 2806 func (r *Runtime) createIterResultObject(value Value, done bool) Value { 2807 o := r.NewObject() 2808 o.self.setOwnStr("value", value, false) 2809 o.self.setOwnStr("done", r.toBoolean(done), false) 2810 return o 2811 } 2812 2813 func (r *Runtime) newLazyObject(create func(*Object) objectImpl) *Object { 2814 val := &Object{runtime: r} 2815 o := &lazyObject{ 2816 val: val, 2817 create: create, 2818 } 2819 val.self = o 2820 return val 2821 } 2822 2823 func (r *Runtime) getHash() *maphash.Hash { 2824 if r.hash == nil { 2825 r.hash = &maphash.Hash{} 2826 } 2827 return r.hash 2828 } 2829 2830 // called when the top level function returns normally (i.e. control is passed outside the Runtime). 2831 func (r *Runtime) leave() { 2832 var jobs []func() 2833 for len(r.jobQueue) > 0 { 2834 jobs, r.jobQueue = r.jobQueue, jobs[:0] 2835 for _, job := range jobs { 2836 job() 2837 } 2838 } 2839 r.jobQueue = nil 2840 r.vm.stack = nil 2841 } 2842 2843 // called when the top level function returns (i.e. control is passed outside the Runtime) but it was due to an interrupt 2844 func (r *Runtime) leaveAbrupt() { 2845 r.jobQueue = nil 2846 r.ClearInterrupt() 2847 } 2848 2849 func nilSafe(v Value) Value { 2850 if v != nil { 2851 return v 2852 } 2853 return _undefined 2854 } 2855 2856 func isArray(object *Object) bool { 2857 self := object.self 2858 if proxy, ok := self.(*proxyObject); ok { 2859 if proxy.target == nil { 2860 panic(typeError("Cannot perform 'IsArray' on a proxy that has been revoked")) 2861 } 2862 return isArray(proxy.target) 2863 } 2864 switch self.className() { 2865 case classArray: 2866 return true 2867 default: 2868 return false 2869 } 2870 } 2871 2872 func isRegexp(v Value) bool { 2873 if o, ok := v.(*Object); ok { 2874 matcher := o.self.getSym(SymMatch, nil) 2875 if matcher != nil && matcher != _undefined { 2876 return matcher.ToBoolean() 2877 } 2878 _, reg := o.self.(*regexpObject) 2879 return reg 2880 } 2881 return false 2882 } 2883 2884 func limitCallArgs(call FunctionCall, n int) FunctionCall { 2885 if len(call.Arguments) > n { 2886 return FunctionCall{This: call.This, Arguments: call.Arguments[:n]} 2887 } else { 2888 return call 2889 } 2890 } 2891 2892 func shrinkCap(newSize, oldCap int) int { 2893 if oldCap > 8 { 2894 if cap := oldCap / 2; cap >= newSize { 2895 return cap 2896 } 2897 } 2898 return oldCap 2899 } 2900 2901 func growCap(newSize, oldSize, oldCap int) int { 2902 // Use the same algorithm as in runtime.growSlice 2903 doublecap := oldCap + oldCap 2904 if newSize > doublecap { 2905 return newSize 2906 } else { 2907 if oldSize < 1024 { 2908 return doublecap 2909 } else { 2910 cap := oldCap 2911 // Check 0 < cap to detect overflow 2912 // and prevent an infinite loop. 2913 for 0 < cap && cap < newSize { 2914 cap += cap / 4 2915 } 2916 // Return the requested cap when 2917 // the calculation overflowed. 2918 if cap <= 0 { 2919 return newSize 2920 } 2921 return cap 2922 } 2923 } 2924 } 2925 2926 func (r *Runtime) genId() (ret uint64) { 2927 if r.hash == nil { 2928 h := r.getHash() 2929 r.idSeq = h.Sum64() 2930 } 2931 if r.idSeq == 0 { 2932 r.idSeq = 1 2933 } 2934 ret = r.idSeq 2935 r.idSeq++ 2936 return 2937 } 2938 2939 func (r *Runtime) setGlobal(name unistring.String, v Value, strict bool) { 2940 if ref := r.global.stash.getRefByName(name, strict); ref != nil { 2941 ref.set(v) 2942 } else { 2943 o := r.globalObject.self 2944 if strict { 2945 if o.hasOwnPropertyStr(name) { 2946 o.setOwnStr(name, v, true) 2947 } else { 2948 r.throwReferenceError(name) 2949 } 2950 } else { 2951 o.setOwnStr(name, v, false) 2952 } 2953 } 2954 } 2955 2956 func (r *Runtime) trackPromiseRejection(p *Promise, operation PromiseRejectionOperation) { 2957 if r.promiseRejectionTracker != nil { 2958 r.promiseRejectionTracker(p, operation) 2959 } 2960 } 2961 2962 func (r *Runtime) callJobCallback(job *jobCallback, this Value, args ...Value) Value { 2963 return job.callback(FunctionCall{This: this, Arguments: args}) 2964 } 2965 2966 func (r *Runtime) invoke(v Value, p unistring.String, args ...Value) Value { 2967 o := v.ToObject(r) 2968 return r.toCallable(o.self.getStr(p, nil))(FunctionCall{This: v, Arguments: args}) 2969 } 2970 2971 func (r *Runtime) iterableToList(iterable Value, method func(FunctionCall) Value) []Value { 2972 iter := r.getIterator(iterable, method) 2973 var values []Value 2974 iter.iterate(func(item Value) { 2975 values = append(values, item) 2976 }) 2977 return values 2978 } 2979 2980 func (r *Runtime) putSpeciesReturnThis(o objectImpl) { 2981 o._putSym(SymSpecies, &valueProperty{ 2982 getterFunc: r.newNativeFunc(r.returnThis, nil, "get [Symbol.species]", nil, 0), 2983 accessor: true, 2984 configurable: true, 2985 }) 2986 } 2987 2988 func strToArrayIdx(s unistring.String) uint32 { 2989 if s == "" { 2990 return math.MaxUint32 2991 } 2992 l := len(s) 2993 if s[0] == '0' { 2994 if l == 1 { 2995 return 0 2996 } 2997 return math.MaxUint32 2998 } 2999 var n uint32 3000 if l < 10 { 3001 // guaranteed not to overflow 3002 for i := 0; i < len(s); i++ { 3003 c := s[i] 3004 if c < '0' || c > '9' { 3005 return math.MaxUint32 3006 } 3007 n = n*10 + uint32(c-'0') 3008 } 3009 return n 3010 } 3011 if l > 10 { 3012 // guaranteed to overflow 3013 return math.MaxUint32 3014 } 3015 c9 := s[9] 3016 if c9 < '0' || c9 > '9' { 3017 return math.MaxUint32 3018 } 3019 for i := 0; i < 9; i++ { 3020 c := s[i] 3021 if c < '0' || c > '9' { 3022 return math.MaxUint32 3023 } 3024 n = n*10 + uint32(c-'0') 3025 } 3026 if n >= math.MaxUint32/10+1 { 3027 return math.MaxUint32 3028 } 3029 n *= 10 3030 n1 := n + uint32(c9-'0') 3031 if n1 < n { 3032 return math.MaxUint32 3033 } 3034 3035 return n1 3036 } 3037 3038 func strToInt32(s unistring.String) (int32, bool) { 3039 if s == "" { 3040 return -1, false 3041 } 3042 neg := s[0] == '-' 3043 if neg { 3044 s = s[1:] 3045 } 3046 l := len(s) 3047 if s[0] == '0' { 3048 if l == 1 { 3049 return 0, !neg 3050 } 3051 return -1, false 3052 } 3053 var n uint32 3054 if l < 10 { 3055 // guaranteed not to overflow 3056 for i := 0; i < len(s); i++ { 3057 c := s[i] 3058 if c < '0' || c > '9' { 3059 return -1, false 3060 } 3061 n = n*10 + uint32(c-'0') 3062 } 3063 } else if l > 10 { 3064 // guaranteed to overflow 3065 return -1, false 3066 } else { 3067 c9 := s[9] 3068 if c9 >= '0' { 3069 if !neg && c9 > '7' || c9 > '8' { 3070 // guaranteed to overflow 3071 return -1, false 3072 } 3073 for i := 0; i < 9; i++ { 3074 c := s[i] 3075 if c < '0' || c > '9' { 3076 return -1, false 3077 } 3078 n = n*10 + uint32(c-'0') 3079 } 3080 if n >= math.MaxInt32/10+1 { 3081 // valid number, but it overflows integer 3082 return 0, false 3083 } 3084 n = n*10 + uint32(c9-'0') 3085 } else { 3086 return -1, false 3087 } 3088 } 3089 if neg { 3090 return int32(-n), true 3091 } 3092 return int32(n), true 3093 } 3094 3095 func strToInt64(s unistring.String) (int64, bool) { 3096 if s == "" { 3097 return -1, false 3098 } 3099 neg := s[0] == '-' 3100 if neg { 3101 s = s[1:] 3102 } 3103 l := len(s) 3104 if s[0] == '0' { 3105 if l == 1 { 3106 return 0, !neg 3107 } 3108 return -1, false 3109 } 3110 var n uint64 3111 if l < 19 { 3112 // guaranteed not to overflow 3113 for i := 0; i < len(s); i++ { 3114 c := s[i] 3115 if c < '0' || c > '9' { 3116 return -1, false 3117 } 3118 n = n*10 + uint64(c-'0') 3119 } 3120 } else if l > 19 { 3121 // guaranteed to overflow 3122 return -1, false 3123 } else { 3124 c18 := s[18] 3125 if c18 >= '0' { 3126 if !neg && c18 > '7' || c18 > '8' { 3127 // guaranteed to overflow 3128 return -1, false 3129 } 3130 for i := 0; i < 18; i++ { 3131 c := s[i] 3132 if c < '0' || c > '9' { 3133 return -1, false 3134 } 3135 n = n*10 + uint64(c-'0') 3136 } 3137 if n >= math.MaxInt64/10+1 { 3138 // valid number, but it overflows integer 3139 return 0, false 3140 } 3141 n = n*10 + uint64(c18-'0') 3142 } else { 3143 return -1, false 3144 } 3145 } 3146 if neg { 3147 return int64(-n), true 3148 } 3149 return int64(n), true 3150 } 3151 3152 func strToInt(s unistring.String) (int, bool) { 3153 if bits.UintSize == 32 { 3154 n, ok := strToInt32(s) 3155 return int(n), ok 3156 } 3157 n, ok := strToInt64(s) 3158 return int(n), ok 3159 } 3160 3161 // Attempts to convert a string into a canonical integer. 3162 // On success returns (number, true). 3163 // If it was a canonical number, but not an integer returns (0, false). This includes -0 and overflows. 3164 // In all other cases returns (-1, false). 3165 // See https://262.ecma-international.org/#sec-canonicalnumericindexstring 3166 func strToIntNum(s unistring.String) (int, bool) { 3167 n, ok := strToInt64(s) 3168 if n == 0 { 3169 return 0, ok 3170 } 3171 if ok && n >= -maxInt && n <= maxInt { 3172 if bits.UintSize == 32 { 3173 if n > math.MaxInt32 || n < math.MinInt32 { 3174 return 0, false 3175 } 3176 } 3177 return int(n), true 3178 } 3179 str := stringValueFromRaw(s) 3180 if str.ToNumber().toString().SameAs(str) { 3181 return 0, false 3182 } 3183 return -1, false 3184 } 3185 3186 func strToGoIdx(s unistring.String) int { 3187 if n, ok := strToInt(s); ok { 3188 return n 3189 } 3190 return -1 3191 } 3192 3193 func strToIdx64(s unistring.String) int64 { 3194 if n, ok := strToInt64(s); ok { 3195 return n 3196 } 3197 return -1 3198 } 3199 3200 func assertCallable(v Value) (func(FunctionCall) Value, bool) { 3201 if obj, ok := v.(*Object); ok { 3202 return obj.self.assertCallable() 3203 } 3204 return nil, false 3205 } 3206 3207 // InstanceOf is an equivalent of "left instanceof right". 3208 // This method will panic with an *Exception if a JavaScript exception is thrown in the process. 3209 func (r *Runtime) InstanceOf(left Value, right *Object) (res bool) { 3210 return instanceOfOperator(left, right) 3211 }