js.mx raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build js && wasm
   6  
   7  // Package js gives access to the WebAssembly host environment when using the js/wasm architecture.
   8  // Its API is based on JavaScript semantics.
   9  //
  10  // This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a
  11  // comprehensive API for users. It is exempt from the Go compatibility promise.
  12  package js
  13  
  14  import (
  15  	"runtime"
  16  	"unsafe"
  17  )
  18  
  19  // ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly.
  20  //
  21  // The JavaScript value "undefined" is represented by the value 0.
  22  // A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation.
  23  // All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as
  24  // an ID and bits 32-34 used to differentiate between string, symbol, function and object.
  25  type ref uint64
  26  
  27  // nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
  28  const nanHead = 0x7FF80000
  29  
  30  // Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
  31  // Values can be checked for equality with the Equal method.
  32  type Value struct {
  33  	_     [0]func() // uncomparable; to make == not compile
  34  	ref   ref       // identifies a JavaScript value, see ref type
  35  	gcPtr *ref      // used to trigger the finalizer when the Value is not referenced any more
  36  }
  37  
  38  const (
  39  	// the type flags need to be in sync with wasm_exec.js
  40  	typeFlagNone = iota
  41  	typeFlagObject
  42  	typeFlagString
  43  	typeFlagSymbol
  44  	typeFlagFunction
  45  )
  46  
  47  func makeValue(r ref) Value {
  48  	var gcPtr *ref
  49  	typeFlag := (r >> 32) & 7
  50  	if (r>>32)&nanHead == nanHead && typeFlag != typeFlagNone {
  51  		gcPtr = new(ref)
  52  		*gcPtr = r
  53  		runtime.SetFinalizer(gcPtr, func(p *ref) {
  54  			finalizeRef(*p)
  55  		})
  56  	}
  57  
  58  	return Value{ref: r, gcPtr: gcPtr}
  59  }
  60  
  61  //go:wasmimport gojs syscall/js.finalizeRef
  62  func finalizeRef(r ref)
  63  
  64  func predefValue(id uint32, typeFlag byte) Value {
  65  	return Value{ref: (nanHead|ref(typeFlag))<<32 | ref(id)}
  66  }
  67  
  68  func floatValue(f float64) Value {
  69  	if f == 0 {
  70  		return valueZero
  71  	}
  72  	if f != f {
  73  		return valueNaN
  74  	}
  75  	return Value{ref: *(*ref)(unsafe.Pointer(&f))}
  76  }
  77  
  78  // Error wraps a JavaScript error.
  79  type Error struct {
  80  	// Value is the underlying JavaScript error value.
  81  	Value
  82  }
  83  
  84  // Error implements the error interface.
  85  func (e Error) Error() string {
  86  	return "JavaScript error: " + e.Get("message").String()
  87  }
  88  
  89  var (
  90  	valueUndefined = Value{ref: 0}
  91  	valueNaN       = predefValue(0, typeFlagNone)
  92  	valueZero      = predefValue(1, typeFlagNone)
  93  	valueNull      = predefValue(2, typeFlagNone)
  94  	valueTrue      = predefValue(3, typeFlagNone)
  95  	valueFalse     = predefValue(4, typeFlagNone)
  96  	valueGlobal    = predefValue(5, typeFlagObject)
  97  	jsGo           = predefValue(6, typeFlagObject) // instance of the Go class in JavaScript
  98  
  99  	objectConstructor = valueGlobal.Get("Object")
 100  	arrayConstructor  = valueGlobal.Get("Array")
 101  )
 102  
 103  // Equal reports whether v and w are equal according to JavaScript's === operator.
 104  func (v Value) Equal(w Value) bool {
 105  	return v.ref == w.ref && v.ref != valueNaN.ref
 106  }
 107  
 108  // Undefined returns the JavaScript value "undefined".
 109  func Undefined() Value {
 110  	return valueUndefined
 111  }
 112  
 113  // IsUndefined reports whether v is the JavaScript value "undefined".
 114  func (v Value) IsUndefined() bool {
 115  	return v.ref == valueUndefined.ref
 116  }
 117  
 118  // Null returns the JavaScript value "null".
 119  func Null() Value {
 120  	return valueNull
 121  }
 122  
 123  // IsNull reports whether v is the JavaScript value "null".
 124  func (v Value) IsNull() bool {
 125  	return v.ref == valueNull.ref
 126  }
 127  
 128  // IsNaN reports whether v is the JavaScript value "NaN".
 129  func (v Value) IsNaN() bool {
 130  	return v.ref == valueNaN.ref
 131  }
 132  
 133  // Global returns the JavaScript global object, usually "window" or "global".
 134  func Global() Value {
 135  	return valueGlobal
 136  }
 137  
 138  // ValueOf returns x as a JavaScript value:
 139  //
 140  //	| Go                     | JavaScript             |
 141  //	| ---------------------- | ---------------------- |
 142  //	| js.Value               | [its value]            |
 143  //	| js.Func                | function               |
 144  //	| nil                    | null                   |
 145  //	| bool                   | boolean                |
 146  //	| integers and floats    | number                 |
 147  //	| string                 | string                 |
 148  //	| []interface{}          | new array              |
 149  //	| map[string]interface{} | new object             |
 150  //
 151  // Panics if x is not one of the expected types.
 152  func ValueOf(x any) Value {
 153  	switch x := x.(type) {
 154  	case Value:
 155  		return x
 156  	case Func:
 157  		return x.Value
 158  	case nil:
 159  		return valueNull
 160  	case bool:
 161  		if x {
 162  			return valueTrue
 163  		} else {
 164  			return valueFalse
 165  		}
 166  	case int:
 167  		return floatValue(float64(x))
 168  	case int8:
 169  		return floatValue(float64(x))
 170  	case int16:
 171  		return floatValue(float64(x))
 172  	case int64:
 173  		return floatValue(float64(x))
 174  	case uint:
 175  		return floatValue(float64(x))
 176  	case uint8:
 177  		return floatValue(float64(x))
 178  	case uint16:
 179  		return floatValue(float64(x))
 180  	case uint64:
 181  		return floatValue(float64(x))
 182  	case uintptr:
 183  		return floatValue(float64(x))
 184  	case unsafe.Pointer:
 185  		return floatValue(float64(uintptr(x)))
 186  	case float32:
 187  		return floatValue(float64(x))
 188  	case float64:
 189  		return floatValue(x)
 190  	case string:
 191  		return makeValue(stringVal(x))
 192  	case []any:
 193  		a := arrayConstructor.New(len(x))
 194  		for i, s := range x {
 195  			a.SetIndex(i, s)
 196  		}
 197  		return a
 198  	case map[string]any:
 199  		o := objectConstructor.New()
 200  		for k, v := range x {
 201  			o.Set(k, v)
 202  		}
 203  		return o
 204  	default:
 205  		panic("ValueOf: invalid value")
 206  	}
 207  }
 208  
 209  // stringVal copies string x to Javascript and returns a ref.
 210  //
 211  // Using go:noescape is safe because no references are maintained to the
 212  // Go string x after the syscall returns.
 213  //
 214  //go:wasmimport gojs syscall/js.stringVal
 215  //go:noescape
 216  func stringVal(x string) ref
 217  
 218  // Type represents the JavaScript type of a Value.
 219  type Type int
 220  
 221  const (
 222  	TypeUndefined Type = iota
 223  	TypeNull
 224  	TypeBoolean
 225  	TypeNumber
 226  	TypeString
 227  	TypeSymbol
 228  	TypeObject
 229  	TypeFunction
 230  )
 231  
 232  func (t Type) String() string {
 233  	switch t {
 234  	case TypeUndefined:
 235  		return "undefined"
 236  	case TypeNull:
 237  		return "null"
 238  	case TypeBoolean:
 239  		return "boolean"
 240  	case TypeNumber:
 241  		return "number"
 242  	case TypeString:
 243  		return "string"
 244  	case TypeSymbol:
 245  		return "symbol"
 246  	case TypeObject:
 247  		return "object"
 248  	case TypeFunction:
 249  		return "function"
 250  	default:
 251  		panic("bad type")
 252  	}
 253  }
 254  
 255  func (t Type) isObject() bool {
 256  	return t == TypeObject || t == TypeFunction
 257  }
 258  
 259  // Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator,
 260  // except that it returns TypeNull instead of TypeObject for null.
 261  func (v Value) Type() Type {
 262  	switch v.ref {
 263  	case valueUndefined.ref:
 264  		return TypeUndefined
 265  	case valueNull.ref:
 266  		return TypeNull
 267  	case valueTrue.ref, valueFalse.ref:
 268  		return TypeBoolean
 269  	}
 270  	if v.isNumber() {
 271  		return TypeNumber
 272  	}
 273  	typeFlag := (v.ref >> 32) & 7
 274  	switch typeFlag {
 275  	case typeFlagObject:
 276  		return TypeObject
 277  	case typeFlagString:
 278  		return TypeString
 279  	case typeFlagSymbol:
 280  		return TypeSymbol
 281  	case typeFlagFunction:
 282  		return TypeFunction
 283  	default:
 284  		panic("bad type flag")
 285  	}
 286  }
 287  
 288  // Get returns the JavaScript property p of value v.
 289  // It panics if v is not a JavaScript object.
 290  func (v Value) Get(p string) Value {
 291  	if vType := v.Type(); !vType.isObject() {
 292  		panic(&ValueError{"Value.Get", vType})
 293  	}
 294  	r := makeValue(valueGet(v.ref, p))
 295  	runtime.KeepAlive(v)
 296  	return r
 297  }
 298  
 299  // valueGet returns a ref to JavaScript property p of ref v.
 300  //
 301  // Using go:noescape is safe because no references are maintained to the
 302  // Go string p after the syscall returns.
 303  //
 304  //go:wasmimport gojs syscall/js.valueGet
 305  //go:noescape
 306  func valueGet(v ref, p string) ref
 307  
 308  // Set sets the JavaScript property p of value v to ValueOf(x).
 309  // It panics if v is not a JavaScript object.
 310  func (v Value) Set(p string, x any) {
 311  	if vType := v.Type(); !vType.isObject() {
 312  		panic(&ValueError{"Value.Set", vType})
 313  	}
 314  	xv := ValueOf(x)
 315  	valueSet(v.ref, p, xv.ref)
 316  	runtime.KeepAlive(v)
 317  	runtime.KeepAlive(xv)
 318  }
 319  
 320  // valueSet sets property p of ref v to ref x.
 321  //
 322  // Using go:noescape is safe because no references are maintained to the
 323  // Go string p after the syscall returns.
 324  //
 325  //go:wasmimport gojs syscall/js.valueSet
 326  //go:noescape
 327  func valueSet(v ref, p string, x ref)
 328  
 329  // Delete deletes the JavaScript property p of value v.
 330  // It panics if v is not a JavaScript object.
 331  func (v Value) Delete(p string) {
 332  	if vType := v.Type(); !vType.isObject() {
 333  		panic(&ValueError{"Value.Delete", vType})
 334  	}
 335  	valueDelete(v.ref, p)
 336  	runtime.KeepAlive(v)
 337  }
 338  
 339  // valueDelete deletes the JavaScript property p of ref v.
 340  //
 341  // Using go:noescape is safe because no references are maintained to the
 342  // Go string p after the syscall returns.
 343  //
 344  //go:wasmimport gojs syscall/js.valueDelete
 345  //go:noescape
 346  func valueDelete(v ref, p string)
 347  
 348  // Index returns JavaScript index i of value v.
 349  // It panics if v is not a JavaScript object.
 350  func (v Value) Index(i int) Value {
 351  	if vType := v.Type(); !vType.isObject() {
 352  		panic(&ValueError{"Value.Index", vType})
 353  	}
 354  	r := makeValue(valueIndex(v.ref, i))
 355  	runtime.KeepAlive(v)
 356  	return r
 357  }
 358  
 359  //go:wasmimport gojs syscall/js.valueIndex
 360  func valueIndex(v ref, i int) ref
 361  
 362  // SetIndex sets the JavaScript index i of value v to ValueOf(x).
 363  // It panics if v is not a JavaScript object.
 364  func (v Value) SetIndex(i int, x any) {
 365  	if vType := v.Type(); !vType.isObject() {
 366  		panic(&ValueError{"Value.SetIndex", vType})
 367  	}
 368  	xv := ValueOf(x)
 369  	valueSetIndex(v.ref, i, xv.ref)
 370  	runtime.KeepAlive(v)
 371  	runtime.KeepAlive(xv)
 372  }
 373  
 374  //go:wasmimport gojs syscall/js.valueSetIndex
 375  func valueSetIndex(v ref, i int, x ref)
 376  
 377  // makeArgSlices makes two slices to hold JavaScript arg data.
 378  // It can be paired with storeArgs to make-and-store JavaScript arg slices.
 379  // However, the two functions are separated to ensure makeArgSlices is inlined
 380  // which will prevent the slices from being heap allocated for small (<=16)
 381  // numbers of args.
 382  func makeArgSlices(size int) (argVals []Value, argRefs []ref) {
 383  	// value chosen for being power of two, and enough to handle all web APIs
 384  	// in particular, note that WebGL2's texImage2D takes up to 10 arguments
 385  	const maxStackArgs = 16
 386  	if size <= maxStackArgs {
 387  		// as long as makeArgs is inlined, these will be stack-allocated
 388  		argVals = make([]Value, size, maxStackArgs)
 389  		argRefs = make([]ref, size, maxStackArgs)
 390  	} else {
 391  		// allocates on the heap, but exceeding maxStackArgs should be rare
 392  		argVals = make([]Value, size)
 393  		argRefs = make([]ref, size)
 394  	}
 395  	return
 396  }
 397  
 398  // storeArgs maps input args onto respective Value and ref slices.
 399  // It can be paired with makeArgSlices to make-and-store JavaScript arg slices.
 400  func storeArgs(args []any, argValsDst []Value, argRefsDst []ref) {
 401  	// would go in makeArgs if the combined func was simple enough to inline
 402  	for i, arg := range args {
 403  		v := ValueOf(arg)
 404  		argValsDst[i] = v
 405  		argRefsDst[i] = v.ref
 406  	}
 407  }
 408  
 409  // Length returns the JavaScript property "length" of v.
 410  // It panics if v is not a JavaScript object.
 411  func (v Value) Length() int {
 412  	if vType := v.Type(); !vType.isObject() {
 413  		panic(&ValueError{"Value.SetIndex", vType})
 414  	}
 415  	r := valueLength(v.ref)
 416  	runtime.KeepAlive(v)
 417  	return r
 418  }
 419  
 420  //go:wasmimport gojs syscall/js.valueLength
 421  func valueLength(v ref) int
 422  
 423  // Call does a JavaScript call to the method m of value v with the given arguments.
 424  // It panics if v has no method m.
 425  // The arguments get mapped to JavaScript values according to the ValueOf function.
 426  func (v Value) Call(m string, args ...any) Value {
 427  	argVals, argRefs := makeArgSlices(len(args))
 428  	storeArgs(args, argVals, argRefs)
 429  	res, ok := valueCall(v.ref, m, argRefs)
 430  	runtime.KeepAlive(v)
 431  	runtime.KeepAlive(argVals)
 432  	if !ok {
 433  		if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case
 434  			panic(&ValueError{"Value.Call", vType})
 435  		}
 436  		if propType := v.Get(m).Type(); propType != TypeFunction {
 437  			panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String())
 438  		}
 439  		panic(Error{makeValue(res)})
 440  	}
 441  	return makeValue(res)
 442  }
 443  
 444  // valueCall does a JavaScript call to the method name m of ref v with the given arguments.
 445  //
 446  // Using go:noescape is safe because no references are maintained to the
 447  // Go string m after the syscall returns. Additionally, the args slice
 448  // is only used temporarily to collect the JavaScript objects for
 449  // the JavaScript method invocation.
 450  //
 451  //go:wasmimport gojs syscall/js.valueCall
 452  //go:nosplit
 453  //go:noescape
 454  func valueCall(v ref, m string, args []ref) (ref, bool)
 455  
 456  // Invoke does a JavaScript call of the value v with the given arguments.
 457  // It panics if v is not a JavaScript function.
 458  // The arguments get mapped to JavaScript values according to the ValueOf function.
 459  func (v Value) Invoke(args ...any) Value {
 460  	argVals, argRefs := makeArgSlices(len(args))
 461  	storeArgs(args, argVals, argRefs)
 462  	res, ok := valueInvoke(v.ref, argRefs)
 463  	runtime.KeepAlive(v)
 464  	runtime.KeepAlive(argVals)
 465  	if !ok {
 466  		if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
 467  			panic(&ValueError{"Value.Invoke", vType})
 468  		}
 469  		panic(Error{makeValue(res)})
 470  	}
 471  	return makeValue(res)
 472  }
 473  
 474  // valueInvoke does a JavaScript call to value v with the given arguments.
 475  //
 476  // Using go:noescape is safe because the args slice is only used temporarily
 477  // to collect the JavaScript objects for the JavaScript method
 478  // invocation.
 479  //
 480  //go:wasmimport gojs syscall/js.valueInvoke
 481  //go:noescape
 482  func valueInvoke(v ref, args []ref) (ref, bool)
 483  
 484  // New uses JavaScript's "new" operator with value v as constructor and the given arguments.
 485  // It panics if v is not a JavaScript function.
 486  // The arguments get mapped to JavaScript values according to the ValueOf function.
 487  func (v Value) New(args ...any) Value {
 488  	argVals, argRefs := makeArgSlices(len(args))
 489  	storeArgs(args, argVals, argRefs)
 490  	res, ok := valueNew(v.ref, argRefs)
 491  	runtime.KeepAlive(v)
 492  	runtime.KeepAlive(argVals)
 493  	if !ok {
 494  		if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
 495  			panic(&ValueError{"Value.Invoke", vType})
 496  		}
 497  		panic(Error{makeValue(res)})
 498  	}
 499  	return makeValue(res)
 500  }
 501  
 502  // valueNew uses JavaScript's "new" operator with value v as a constructor and the given arguments.
 503  //
 504  // Using go:noescape is safe because the args slice is only used temporarily
 505  // to collect the JavaScript objects for the constructor execution.
 506  //
 507  //go:wasmimport gojs syscall/js.valueNew
 508  //go:noescape
 509  func valueNew(v ref, args []ref) (ref, bool)
 510  
 511  func (v Value) isNumber() bool {
 512  	return v.ref == valueZero.ref ||
 513  		v.ref == valueNaN.ref ||
 514  		(v.ref != valueUndefined.ref && (v.ref>>32)&nanHead != nanHead)
 515  }
 516  
 517  func (v Value) float(method string) float64 {
 518  	if !v.isNumber() {
 519  		panic(&ValueError{method, v.Type()})
 520  	}
 521  	if v.ref == valueZero.ref {
 522  		return 0
 523  	}
 524  	return *(*float64)(unsafe.Pointer(&v.ref))
 525  }
 526  
 527  // Float returns the value v as a float64.
 528  // It panics if v is not a JavaScript number.
 529  func (v Value) Float() float64 {
 530  	return v.float("Value.Float")
 531  }
 532  
 533  // Int returns the value v truncated to an int.
 534  // It panics if v is not a JavaScript number.
 535  func (v Value) Int() int {
 536  	return int(v.float("Value.Int"))
 537  }
 538  
 539  // Bool returns the value v as a bool.
 540  // It panics if v is not a JavaScript boolean.
 541  func (v Value) Bool() bool {
 542  	switch v.ref {
 543  	case valueTrue.ref:
 544  		return true
 545  	case valueFalse.ref:
 546  		return false
 547  	default:
 548  		panic(&ValueError{"Value.Bool", v.Type()})
 549  	}
 550  }
 551  
 552  // Truthy returns the JavaScript "truthiness" of the value v. In JavaScript,
 553  // false, 0, "", null, undefined, and NaN are "falsy", and everything else is
 554  // "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy.
 555  func (v Value) Truthy() bool {
 556  	switch v.Type() {
 557  	case TypeUndefined, TypeNull:
 558  		return false
 559  	case TypeBoolean:
 560  		return v.Bool()
 561  	case TypeNumber:
 562  		return v.ref != valueNaN.ref && v.ref != valueZero.ref
 563  	case TypeString:
 564  		return v.String() != ""
 565  	case TypeSymbol, TypeFunction, TypeObject:
 566  		return true
 567  	default:
 568  		panic("bad type")
 569  	}
 570  }
 571  
 572  // String returns the value v as a string.
 573  // String is a special case because of Go's String method convention. Unlike the other getters,
 574  // it does not panic if v's Type is not TypeString. Instead, it returns a string of the form "<T>"
 575  // or "<T: V>" where T is v's type and V is a string representation of v's value.
 576  func (v Value) String() string {
 577  	switch v.Type() {
 578  	case TypeString:
 579  		return jsString(v)
 580  	case TypeUndefined:
 581  		return "<undefined>"
 582  	case TypeNull:
 583  		return "<null>"
 584  	case TypeBoolean:
 585  		return "<boolean: " + jsString(v) + ">"
 586  	case TypeNumber:
 587  		return "<number: " + jsString(v) + ">"
 588  	case TypeSymbol:
 589  		return "<symbol>"
 590  	case TypeObject:
 591  		return "<object>"
 592  	case TypeFunction:
 593  		return "<function>"
 594  	default:
 595  		panic("bad type")
 596  	}
 597  }
 598  
 599  func jsString(v Value) string {
 600  	str, length := valuePrepareString(v.ref)
 601  	runtime.KeepAlive(v)
 602  	b := make([]byte, length)
 603  	valueLoadString(str, b)
 604  	finalizeRef(str)
 605  	return string(b)
 606  }
 607  
 608  //go:wasmimport gojs syscall/js.valuePrepareString
 609  func valuePrepareString(v ref) (ref, int)
 610  
 611  // valueLoadString loads string data located at ref v into byte slice b.
 612  //
 613  // Using go:noescape is safe because the byte slice is only used as a destination
 614  // for storing the string data and references to it are not maintained.
 615  //
 616  //go:wasmimport gojs syscall/js.valueLoadString
 617  //go:noescape
 618  func valueLoadString(v ref, b []byte)
 619  
 620  // InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator.
 621  func (v Value) InstanceOf(t Value) bool {
 622  	r := valueInstanceOf(v.ref, t.ref)
 623  	runtime.KeepAlive(v)
 624  	runtime.KeepAlive(t)
 625  	return r
 626  }
 627  
 628  //go:wasmimport gojs syscall/js.valueInstanceOf
 629  func valueInstanceOf(v ref, t ref) bool
 630  
 631  // A ValueError occurs when a Value method is invoked on
 632  // a Value that does not support it. Such cases are documented
 633  // in the description of each method.
 634  type ValueError struct {
 635  	Method string
 636  	Type   Type
 637  }
 638  
 639  func (e *ValueError) Error() string {
 640  	return "syscall/js: call of " + e.Method + " on " + e.Type.String()
 641  }
 642  
 643  // CopyBytesToGo copies bytes from src to dst.
 644  // It panics if src is not a Uint8Array or Uint8ClampedArray.
 645  // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst.
 646  func CopyBytesToGo(dst []byte, src Value) int {
 647  	n, ok := copyBytesToGo(dst, src.ref)
 648  	runtime.KeepAlive(src)
 649  	if !ok {
 650  		panic("syscall/js: CopyBytesToGo: expected src to be a Uint8Array or Uint8ClampedArray")
 651  	}
 652  	return n
 653  }
 654  
 655  // copyBytesToGo copies bytes from src to dst.
 656  //
 657  // Using go:noescape is safe because the dst byte slice is only used as a dst
 658  // copy buffer and no references to it are maintained.
 659  //
 660  //go:wasmimport gojs syscall/js.copyBytesToGo
 661  //go:noescape
 662  func copyBytesToGo(dst []byte, src ref) (int, bool)
 663  
 664  // CopyBytesToJS copies bytes from src to dst.
 665  // It panics if dst is not a Uint8Array or Uint8ClampedArray.
 666  // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst.
 667  func CopyBytesToJS(dst Value, src []byte) int {
 668  	n, ok := copyBytesToJS(dst.ref, src)
 669  	runtime.KeepAlive(dst)
 670  	if !ok {
 671  		panic("syscall/js: CopyBytesToJS: expected dst to be a Uint8Array or Uint8ClampedArray")
 672  	}
 673  	return n
 674  }
 675  
 676  // copyBytesToJS copies bytes from src to dst.
 677  //
 678  // Using go:noescape is safe because the src byte slice is only used as a src
 679  // copy buffer and no references to it are maintained.
 680  //
 681  //go:wasmimport gojs syscall/js.copyBytesToJS
 682  //go:noescape
 683  func copyBytesToJS(dst ref, src []byte) (int, bool)
 684