Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions packages/quickjs-emscripten-core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,9 @@ export class QuickJSContext
mutablePointerArray.value.ptr,
)
const promiseHandle = this.memory.heapValueHandle(promisePtr)
const [resolveHandle, rejectHandle] = Array.from(mutablePointerArray.value.typedArray).map(
(jsvaluePtr) => this.memory.heapValueHandle(jsvaluePtr as any),
)
const [resolveHandle, rejectHandle] = Array.from(
mutablePointerArray.value.typedArray.value,
).map((jsvaluePtr) => this.memory.heapValueHandle(jsvaluePtr as any))
return new QuickJSDeferredPromise({
context: this,
promiseHandle,
Expand Down Expand Up @@ -994,7 +994,7 @@ export class QuickJSContext
if (status < 0) {
return undefined
}
return this.uint32Out.value.typedArray[0]
return this.uint32Out.value.typedArray.value[0]
}

/**
Expand Down Expand Up @@ -1052,9 +1052,9 @@ export class QuickJSContext
if (errorPtr) {
return this.fail(this.memory.heapValueHandle(errorPtr))
}
const len = this.uint32Out.value.typedArray[0]
const ptr = outPtr.value.typedArray[0]
const pointerArray = new Uint32Array(this.module.HEAP8.buffer, ptr, len)
const len = this.uint32Out.value.typedArray.value[0]
const ptr = outPtr.value.typedArray.value[0]
const pointerArray = new Uint32Array(this.module.HEAPU8.buffer, ptr, len)
const handles = Array.from(pointerArray).map((ptr) =>
this.memory.heapValueHandle(ptr as JSValuePointer),
)
Expand Down
41 changes: 35 additions & 6 deletions packages/quickjs-emscripten-core/src/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,39 @@ export interface TypedArrayConstructor<T> {
BYTES_PER_ELEMENT: number
}

/**
* A TypedArray view into WASM memory that automatically refreshes when memory grows.
*
* When Emscripten's WASM memory grows (due to -sALLOW_MEMORY_GROWTH), all existing
* TypedArray views become detached because the underlying ArrayBuffer is replaced.
* This class lazily recreates the view when the buffer changes.
*
* @private
*/
export class RefreshableTypedArray<T extends TypedArray> {
private cachedArray: T | undefined
private lastBuffer: ArrayBufferLike | undefined

constructor(
private readonly module: EitherModule,
private readonly kind: TypedArrayConstructor<T>,
private readonly ptr: number,
private readonly length: number,
) {}

get value(): T {
const currentBuffer = this.module.HEAPU8.buffer
if (this.cachedArray === undefined || this.lastBuffer !== currentBuffer) {
this.cachedArray = new this.kind(currentBuffer, this.ptr, this.length)
this.lastBuffer = currentBuffer
}
return this.cachedArray
}
}

/** @private */
export type HeapTypedArray<JS extends TypedArray, C extends number> = Lifetime<{
typedArray: JS
typedArray: RefreshableTypedArray<JS>
ptr: C
}>

Expand All @@ -54,18 +84,17 @@ export class ModuleMemory {
kind: TypedArrayConstructor<JS>,
length: number,
): HeapTypedArray<JS, C> {
const zeros = new kind(new Array(length).fill(0))
const numBytes = zeros.length * zeros.BYTES_PER_ELEMENT
const numBytes = length * kind.BYTES_PER_ELEMENT
const ptr = this.module._malloc(numBytes) as C
const typedArray = new kind(this.module.HEAPU8.buffer, ptr, length)
typedArray.set(zeros)
const typedArray = new RefreshableTypedArray(this.module, kind, ptr, length)
typedArray.value.fill(0)
return new Lifetime({ typedArray, ptr }, undefined, (value) => this.module._free(value.ptr))
}

// TODO: shouldn't this be Uint32 instead of Int32?
newMutablePointerArray<T extends number>(
length: number,
): Lifetime<{ typedArray: Int32Array; ptr: T }> {
): Lifetime<{ typedArray: RefreshableTypedArray<Int32Array>; ptr: T }> {
return this.newTypedArray(Int32Array, length)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/quickjs-emscripten-core/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export class QuickJSRuntime extends UsingDisposable implements Disposable {
ctxPtrOut.value.ptr,
)

const ctxPtr = ctxPtrOut.value.typedArray[0] as JSContextPointer
const ctxPtr = ctxPtrOut.value.typedArray.value[0] as JSContextPointer
ctxPtrOut.dispose()
if (ctxPtr === 0) {
// No jobs executed.
Expand Down
Loading