diff --git a/wasm-wasi-core/src/common/buffer.ts b/wasm-wasi-core/src/common/buffer.ts new file mode 100644 index 00000000..13cada55 --- /dev/null +++ b/wasm-wasi-core/src/common/buffer.ts @@ -0,0 +1,52 @@ +import { size } from './baseTypes'; + +export function read(content: Uint8Array, offset: number, buffers: Uint8Array[]): size { + let totalBytesRead = 0; + for (const buffer of buffers) { + const toRead = Math.min(buffer.length, content.byteLength - offset); + buffer.set(content.subarray(offset, offset + toRead)); + totalBytesRead += toRead; + if (toRead < buffer.length) { + break; + } + offset += toRead; + } + return totalBytesRead; +} + +export function write(content: Uint8Array, offset: number, buffers: Uint8Array[]): [Uint8Array, size] { + let bytesToWrite: size = 0; + for (const bytes of buffers) { + bytesToWrite += bytes.byteLength; + } + + const newSize = offset + bytesToWrite; + + // Do we need to increase the buffer + if (newSize > content.byteLength) { + interface ResizeableArrayBuffer extends ArrayBuffer { + resize: (newByteLength: number) => void; + maxByteLength: number; + } + //Utilize ECMAScript 2024 In-Place Resizable ArrayBuffers + + const buffer = content.buffer as ResizeableArrayBuffer; + const oldSize = buffer.maxByteLength; + + if(newSize < oldSize){ + buffer.resize(newSize); + } else { + const newBuffer = new (ArrayBuffer as any)(newSize, { maxByteLength: Math.max(newSize, oldSize << 1) }); + const newContent = new Uint8Array(newBuffer); + newContent.set(content); + content = newContent; + } + } + + for (const bytes of buffers) { + content.set(bytes, offset); + offset += bytes.length; + } + + return [content, bytesToWrite]; +} \ No newline at end of file diff --git a/wasm-wasi-core/src/common/memoryFileSystemDriver.ts b/wasm-wasi-core/src/common/memoryFileSystemDriver.ts index 32acb1a6..646b68fb 100644 --- a/wasm-wasi-core/src/common/memoryFileSystemDriver.ts +++ b/wasm-wasi-core/src/common/memoryFileSystemDriver.ts @@ -13,6 +13,7 @@ import { Errno, Fdflags, Filetype, Lookupflags, Oflags, Rights, WasiError, Whenc import { size, u64 } from './baseTypes'; import { BigInts } from './converter'; import * as fs from './fileSystem'; +import * as buffer from './buffer'; import { ReadableStream, WritableStream } from './streams'; const paths = RAL().path; @@ -158,18 +159,18 @@ export class MemoryFileSystem extends fs.BaseFileSystem { const content = await this.getContent(node); - return this.read(content, offset, buffers); + return buffer.read(content, BigInts.asNumber(offset), buffers); } public async readCharacterDevice(node: CharacterDeviceNode & { writable: WritableStream }, buffers: Uint8Array[]): Promise { const maxBytes = buffers.reduce((previousValue, current) => { return previousValue + current.byteLength; }, 0); const content = await node.writable.read('max', maxBytes); - return this.read(content, 0n, buffers); + return buffer.read(content, 0, buffers); } public async writeFile(node: FileNode, offset: bigint, buffers: Uint8Array[]): Promise { const content = await this.getContent(node); - const [newContent, bytesWritten] = this.write(content, offset, buffers); + const [newContent, bytesWritten] = buffer.write(content, BigInts.asNumber(offset), buffers); node.content = newContent; return bytesWritten; } @@ -195,43 +196,6 @@ export class MemoryFileSystem extends fs.BaseFileSystem content.byteLength) { - const newContent = new Uint8Array(offset + bytesToWrite); - newContent.set(content); - content = newContent; - } - - for (const bytes of buffers) { - content.set(bytes, offset); - offset += bytes.length; - } - - return [content, bytesToWrite]; - } } // When mounted the file system is readonly for now. We need to invest to make this writable and we need a use case first. diff --git a/wasm-wasi-core/src/common/vscodeFileSystemDriver.ts b/wasm-wasi-core/src/common/vscodeFileSystemDriver.ts index 5879fa55..ce07ce59 100644 --- a/wasm-wasi-core/src/common/vscodeFileSystemDriver.ts +++ b/wasm-wasi-core/src/common/vscodeFileSystemDriver.ts @@ -5,6 +5,7 @@ import { FileStat, FileType, workspace, Uri } from 'vscode'; import RAL from './ral'; +import * as buffer from './buffer'; import { LRUCache } from './linkedMap'; import { u64, size } from './baseTypes'; import { @@ -520,42 +521,6 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal return BigInt(timeInMilliseconds) * 1000000n; } - function read(content: Uint8Array, offset: number, buffers: Uint8Array[]): size { - let totalBytesRead = 0; - for (const buffer of buffers) { - const toRead = Math.min(buffer.length, content.byteLength - offset); - buffer.set(content.subarray(offset, offset + toRead)); - totalBytesRead += toRead; - if (toRead < buffer.length) { - break; - } - offset += toRead; - } - return totalBytesRead; - } - - function write(content: Uint8Array, offset: number, buffers: Uint8Array[]): [Uint8Array, size] { - let bytesToWrite: size = 0; - for (const bytes of buffers) { - bytesToWrite += bytes.byteLength; - } - - // Do we need to increase the buffer - if (offset + bytesToWrite > content.byteLength) { - const newContent = new Uint8Array(offset + bytesToWrite); - newContent.set(content); - content = newContent; - } - - for (const bytes of buffers) { - content.set(bytes, offset); - offset += bytes.length; - } - - return [content, bytesToWrite]; - } - - async function createOrTruncate(fileDescriptor: FileFileDescriptor): Promise { const content = new Uint8Array(0); const inode = fs.getNode(fileDescriptor.inode, NodeKind.File); @@ -674,12 +639,12 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal async fd_pread(fileDescriptor: FileDescriptor, _offset: filesize, buffers: Uint8Array[]): Promise { const offset = BigInts.asNumber(_offset); const content = await fs.getContent(fs.getNode(fileDescriptor.inode, NodeKind.File), vscode_fs); - return read(content, offset, buffers); + return buffer.read(content, offset, buffers); }, async fd_pwrite(fileDescriptor: FileDescriptor, _offset: filesize, buffers: Uint8Array[]): Promise { const offset = BigInts.asNumber(_offset); const inode = fs.getNode(fileDescriptor.inode, NodeKind.File); - const [newContent, bytesWritten] = write(await fs.getContent(inode, vscode_fs), offset, buffers); + const [newContent, bytesWritten] = buffer.write(await fs.getContent(inode, vscode_fs), offset, buffers); await writeContent(inode, newContent); return bytesWritten; }, @@ -691,7 +656,7 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal const content = await fs.getContent(fs.getNode(fileDescriptor.inode, NodeKind.File), vscode_fs); const offset = fileDescriptor.cursor; - const totalBytesRead = read(content, offset, buffers); + const totalBytesRead = buffer.read(content, offset, buffers); fileDescriptor.cursor = fileDescriptor.cursor + totalBytesRead; return totalBytesRead; }, @@ -754,7 +719,7 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal if (Fdflags.appendOn(fileDescriptor.fdflags)) { fileDescriptor.cursor = content.byteLength; } - const [newContent, bytesWritten] = write(content, fileDescriptor.cursor, buffers); + const [newContent, bytesWritten] = buffer.write(content, fileDescriptor.cursor, buffers); await writeContent(inode,newContent); fileDescriptor.cursor = fileDescriptor.cursor + bytesWritten; return bytesWritten;