@@ -406,72 +406,30 @@ export class FacadeVFS extends VFS.Base {
406406
407407 /**
408408 * Wrapped DataView for pointer arguments.
409- * Pointers to a single value are passed using DataView. A Proxy
410- * wrapper prevents use of incorrect type or endianness.
409+ * Pointers to a single value are passed using a DataView-like class.
410+ * This wrapper class prevents use of incorrect type or endianness, and
411+ * reacquires the underlying buffer when the WebAssembly memory is resized.
411412 * @param {'Int32'|'BigInt64' } type
412413 * @param {number } byteOffset
413414 * @returns {DataView }
414415 */
415416 #makeTypedDataView( type , byteOffset ) {
416- const byteLength = type === "Int32" ? 4 : 8
417- const getter = `get${ type } `
418- const setter = `set${ type } `
419- const makeDataView = ( ) =>
420- new DataView (
421- this . _module . HEAPU8 . buffer ,
422- this . _module . HEAPU8 . byteOffset + byteOffset ,
423- byteLength ,
424- )
425- let dataView = makeDataView ( )
426- return new Proxy ( dataView , {
427- get ( _ , prop ) {
428- if ( dataView . buffer . byteLength === 0 ) {
429- // WebAssembly memory resize detached the buffer.
430- dataView = makeDataView ( )
431- }
432- if ( prop === getter ) {
433- return function ( byteOffset , littleEndian ) {
434- if ( ! littleEndian ) throw new Error ( "must be little endian" )
435- return dataView [ prop ] ( byteOffset , littleEndian )
436- }
437- }
438- if ( prop === setter ) {
439- return function ( byteOffset , value , littleEndian ) {
440- if ( ! littleEndian ) throw new Error ( "must be little endian" )
441- return dataView [ prop ] ( byteOffset , value , littleEndian )
442- }
443- }
444- if ( typeof prop === "string" && prop . match ( / ^ ( g e t ) | ( s e t ) / ) ) {
445- throw new Error ( "invalid type" )
446- }
447- const result = dataView [ prop ]
448- return typeof result === "function" ? result . bind ( dataView ) : result
449- } ,
450- } )
417+ // @ts -ignore
418+ return new DataViewProxy ( this . _module , byteOffset , type )
451419 }
452420
453421 /**
422+ * Wrapped Uint8Array for buffer arguments.
423+ * Memory blocks are passed as a Uint8Array-like class. This wrapper
424+ * class reacquires the underlying buffer when the WebAssembly memory
425+ * is resized.
454426 * @param {number } byteOffset
455427 * @param {number } byteLength
428+ * @returns {Uint8Array }
456429 */
457430 #makeDataArray( byteOffset , byteLength ) {
458- let target = this . _module . HEAPU8 . subarray (
459- byteOffset ,
460- byteOffset + byteLength ,
461- )
462- return new Proxy ( target , {
463- get : ( _ , prop , receiver ) => {
464- if ( target . buffer . byteLength === 0 ) {
465- // WebAssembly memory resize detached the buffer.
466- target = this . _module . HEAPU8 . subarray (
467- byteOffset ,
468- byteOffset + byteLength ,
469- )
470- }
471- const result = target [ prop ]
472- return typeof result === "function" ? result . bind ( target ) : result
473- } ,
474- } )
431+ // @ts -ignore
432+ return new Uint8ArrayProxy ( this . _module , byteOffset , byteLength )
475433 }
476434
477435 #decodeFilename( zName , flags ) {
@@ -515,3 +473,212 @@ export class FacadeVFS extends VFS.Base {
515473function delegalize ( lo32 , hi32 ) {
516474 return hi32 * 0x100000000 + lo32 + ( lo32 < 0 ? 2 ** 32 : 0 )
517475}
476+
477+ // This class provides a Uint8Array-like interface for a WebAssembly memory
478+ // buffer. It is used to access memory blocks passed as arguments to
479+ // xRead, xWrite, etc. The class reacquires the underlying buffer when the
480+ // WebAssembly memory is resized, which can happen when the memory is
481+ // detached and resized by the WebAssembly module.
482+ //
483+ // Note that although this class implements the same methods as Uint8Array,
484+ // it is not a real Uint8Array and passing it to functions that expect
485+ // a Uint8Array may not work. Use subarray() to get a real Uint8Array
486+ // if needed.
487+ class Uint8ArrayProxy {
488+ #module
489+
490+ #_array = new Uint8Array ( )
491+ get #array( ) {
492+ if ( this . #_array. buffer . byteLength === 0 ) {
493+ // WebAssembly memory resize detached the buffer so re-create the
494+ // array with the new buffer.
495+ this . #_array = this . #module. HEAPU8 . subarray (
496+ this . byteOffset ,
497+ this . byteOffset + this . byteLength ,
498+ )
499+ }
500+ return this . #_array
501+ }
502+
503+ /**
504+ * @param {* } module
505+ * @param {number } byteOffset
506+ * @param {number } byteLength
507+ */
508+ constructor ( module , byteOffset , byteLength ) {
509+ this . #module = module
510+ this . byteOffset = byteOffset
511+ this . length = this . byteLength = byteLength
512+ }
513+
514+ get buffer ( ) {
515+ return this . #array. buffer
516+ }
517+
518+ at ( index ) {
519+ return this . #array. at ( index )
520+ }
521+ copyWithin ( target , start , end ) {
522+ this . #array. copyWithin ( target , start , end )
523+ }
524+ entries ( ) {
525+ return this . #array. entries ( )
526+ }
527+ every ( predicate ) {
528+ return this . #array. every ( predicate )
529+ }
530+ fill ( value , start , end ) {
531+ this . #array. fill ( value , start , end )
532+ }
533+ filter ( predicate ) {
534+ return this . #array. filter ( predicate )
535+ }
536+ find ( predicate ) {
537+ return this . #array. find ( predicate )
538+ }
539+ findIndex ( predicate ) {
540+ return this . #array. findIndex ( predicate )
541+ }
542+ findLast ( predicate ) {
543+ return this . #array. findLast ( predicate )
544+ }
545+ findLastIndex ( predicate ) {
546+ return this . #array. findLastIndex ( predicate )
547+ }
548+ forEach ( callback ) {
549+ this . #array. forEach ( callback )
550+ }
551+ includes ( value , start ) {
552+ return this . #array. includes ( value , start )
553+ }
554+ indexOf ( value , start ) {
555+ return this . #array. indexOf ( value , start )
556+ }
557+ join ( separator ) {
558+ return this . #array. join ( separator )
559+ }
560+ keys ( ) {
561+ return this . #array. keys ( )
562+ }
563+ lastIndexOf ( value , start ) {
564+ return this . #array. lastIndexOf ( value , start )
565+ }
566+ map ( callback ) {
567+ return this . #array. map ( callback )
568+ }
569+ reduce ( callback , initialValue ) {
570+ return this . #array. reduce ( callback , initialValue )
571+ }
572+ reduceRight ( callback , initialValue ) {
573+ return this . #array. reduceRight ( callback , initialValue )
574+ }
575+ reverse ( ) {
576+ this . #array. reverse ( )
577+ }
578+ set ( array , offset ) {
579+ this . #array. set ( array , offset )
580+ }
581+ slice ( start , end ) {
582+ return this . #array. slice ( start , end )
583+ }
584+ some ( predicate ) {
585+ return this . #array. some ( predicate )
586+ }
587+ sort ( compareFn ) {
588+ this . #array. sort ( compareFn )
589+ }
590+ subarray ( begin , end ) {
591+ return this . #array. subarray ( begin , end )
592+ }
593+ toLocaleString ( locales , options ) {
594+ // @ts -ignore
595+ return this . #array. toLocaleString ( locales , options )
596+ }
597+ toReversed ( ) {
598+ return this . #array. toReversed ( )
599+ }
600+ toSorted ( compareFn ) {
601+ return this . #array. toSorted ( compareFn )
602+ }
603+ toString ( ) {
604+ return this . #array. toString ( )
605+ }
606+ values ( ) {
607+ return this . #array. values ( )
608+ }
609+ with ( index , value ) {
610+ return this . #array. with ( index , value )
611+ }
612+ [ Symbol . iterator ] ( ) {
613+ return this . #array[ Symbol . iterator ] ( )
614+ }
615+ }
616+
617+ // This class provides a DataView-like interface for a WebAssembly memory
618+ // buffer, restricted to either Int32 or BigInt64 types. It also reacquires
619+ // the underlying buffer when the WebAssembly memory is resized, which can
620+ // happen when the memory is detached and resized by the WebAssembly module.
621+ class DataViewProxy {
622+ #module
623+ #type
624+
625+ #_view = new DataView ( new ArrayBuffer ( 0 ) )
626+ get #view( ) {
627+ if ( this . #_view. buffer . byteLength === 0 ) {
628+ // WebAssembly memory resize detached the buffer so re-create the
629+ // view with the new buffer.
630+ this . #_view = new DataView (
631+ this . #module. HEAPU8 . buffer ,
632+ this . #module. HEAPU8 . byteOffset + this . byteOffset ,
633+ )
634+ }
635+ return this . #_view
636+ }
637+
638+ /**
639+ * @param {* } module
640+ * @param {number } byteOffset
641+ * @param {'Int32'|'BigInt64' } type
642+ */
643+ constructor ( module , byteOffset , type ) {
644+ this . #module = module
645+ this . byteOffset = byteOffset
646+ this . #type = type
647+ }
648+
649+ get buffer ( ) {
650+ return this . #view. buffer
651+ }
652+ get byteLength ( ) {
653+ return this . #type === "Int32" ? 4 : 8
654+ }
655+
656+ getInt32 ( byteOffset , littleEndian ) {
657+ if ( this . #type !== "Int32" ) {
658+ throw new Error ( "invalid type" )
659+ }
660+ if ( ! littleEndian ) throw new Error ( "must be little endian" )
661+ return this . #view. getInt32 ( byteOffset , littleEndian )
662+ }
663+ setInt32 ( byteOffset , value , littleEndian ) {
664+ if ( this . #type !== "Int32" ) {
665+ throw new Error ( "invalid type" )
666+ }
667+ if ( ! littleEndian ) throw new Error ( "must be little endian" )
668+ this . #view. setInt32 ( byteOffset , value , littleEndian )
669+ }
670+ getBigInt64 ( byteOffset , littleEndian ) {
671+ if ( this . #type !== "BigInt64" ) {
672+ throw new Error ( "invalid type" )
673+ }
674+ if ( ! littleEndian ) throw new Error ( "must be little endian" )
675+ return this . #view. getBigInt64 ( byteOffset , littleEndian )
676+ }
677+ setBigInt64 ( byteOffset , value , littleEndian ) {
678+ if ( this . #type !== "BigInt64" ) {
679+ throw new Error ( "invalid type" )
680+ }
681+ if ( ! littleEndian ) throw new Error ( "must be little endian" )
682+ this . #view. setBigInt64 ( byteOffset , value , littleEndian )
683+ }
684+ }
0 commit comments