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