From 7904aa21db38d25caf4251b8215386f4d39fd4ed Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:13:51 +0000 Subject: [PATCH 1/2] perf: Zero-copy decoding from SharedArrayBuffer - Implemented zero-copy decoding for `ShareableMap` and `ShareableArray` reads when supported by the environment. - Added feature detection `SUPPORTS_SAB_VIEW` to safely fallback to copy-based decoding if SAB view decoding is not supported. - Fixed `NumberEncoder` to correctly respect `Uint8Array` byteOffset, which is required when decoding views into `SharedArrayBuffer`. - Removed unnecessary temporary buffer allocation in hot paths. --- src/TransferableDataStructure.ts | 13 +++++++++++++ src/array/ShareableArray.ts | 4 ++++ src/encoding/NumberEncoder.ts | 2 +- src/map/ShareableMap.ts | 8 ++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/TransferableDataStructure.ts b/src/TransferableDataStructure.ts index 20f757d..d92627a 100644 --- a/src/TransferableDataStructure.ts +++ b/src/TransferableDataStructure.ts @@ -7,6 +7,19 @@ export default abstract class TransferableDataStructure { private decoderBuffer: ArrayBuffer = new ArrayBuffer(TransferableDataStructure.DECODER_BUFFER_SIZE); private currentDecoderBufferSize: number = TransferableDataStructure.DECODER_BUFFER_SIZE; + // Check if the current environment supports decoding directly from a SharedArrayBuffer view. + protected static readonly SUPPORTS_SAB_VIEW = (() => { + try { + if (typeof SharedArrayBuffer === "undefined") return false; + const sab = new SharedArrayBuffer(0); + const view = new Uint8Array(sab); + new TextDecoder().decode(view); + return true; + } catch { + return false; + } + })(); + protected allocateMemory(byteSize: number): SharedArrayBuffer | ArrayBuffer { try { return new SharedArrayBuffer(byteSize); diff --git a/src/array/ShareableArray.ts b/src/array/ShareableArray.ts index dcea152..bb50b58 100644 --- a/src/array/ShareableArray.ts +++ b/src/array/ShareableArray.ts @@ -887,6 +887,10 @@ export class ShareableArray extends TransferableDataStructure { // Copy from shared memory to a temporary private buffer (since we cannot directly decode from shared memory) const sourceView = new Uint8Array(this.dataView.buffer, dataPos + ShareableArray.DATA_OBJECT_OFFSET, valueLength); + if (ShareableArray.SUPPORTS_SAB_VIEW) { + return encoder.decode(sourceView); + } + const targetView = new Uint8Array(this.getFittingDecoderBuffer(valueLength), 0, valueLength); targetView.set(sourceView); diff --git a/src/encoding/NumberEncoder.ts b/src/encoding/NumberEncoder.ts index 51e2228..0404d18 100644 --- a/src/encoding/NumberEncoder.ts +++ b/src/encoding/NumberEncoder.ts @@ -2,7 +2,7 @@ import Serializable from "./Serializable"; export default class NumberEncoder implements Serializable { decode(buffer: Uint8Array): number { - const bufferView = new DataView(buffer.buffer); + const bufferView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); // First byte indicates if we did store a float or an int const numberType = bufferView.getUint8(0); diff --git a/src/map/ShareableMap.ts b/src/map/ShareableMap.ts index d3ca305..b4c19c5 100644 --- a/src/map/ShareableMap.ts +++ b/src/map/ShareableMap.ts @@ -730,6 +730,10 @@ export class ShareableMap extends TransferableDataStructure { const sourceView = new Uint8Array(this.dataView.buffer, startPos + ShareableMap.DATA_OBJECT_OFFSET, keyLength); + if (ShareableMap.SUPPORTS_SAB_VIEW) { + return this.textDecoder.decode(sourceView); + } + const targetView = new Uint8Array(this.getFittingDecoderBuffer(keyLength), 0, keyLength); targetView.set(sourceView); @@ -762,6 +766,10 @@ export class ShareableMap extends TransferableDataStructure { // Copy from shared memory to a temporary private buffer (since we cannot directly decode from shared memory) const sourceView = new Uint8Array(this.dataView.buffer, startPos + ShareableMap.DATA_OBJECT_OFFSET + keyLength, valueLength); + if (ShareableMap.SUPPORTS_SAB_VIEW) { + return encoder.decode(sourceView); + } + const targetView = new Uint8Array(this.getFittingDecoderBuffer(valueLength), 0, valueLength); targetView.set(sourceView); From ebabaa00e252c1a480dcd3b54f88314475c30645 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:25:18 +0000 Subject: [PATCH 2/2] perf: Zero-copy decoding from SharedArrayBuffer - Implemented zero-copy decoding for `ShareableMap` and `ShareableArray` reads when supported by the environment. - Added feature detection `SUPPORTS_SAB_VIEW` to safely fallback to copy-based decoding if SAB view decoding is not supported. - Fixed `NumberEncoder` to correctly respect `Uint8Array` byteOffset, which is required when decoding views into `SharedArrayBuffer`. - Removed unnecessary temporary buffer allocation in hot paths when optimization is active.