From 89fb68b1c6689eacce4b44095b0aa2bd10245119 Mon Sep 17 00:00:00 2001 From: liyou Date: Mon, 23 Jun 2025 09:33:53 +0800 Subject: [PATCH] interop/src/arkts: switch to fast intrinsics Signed-off-by: liyou Change-Id: I9099ca1ee4d615558d048ac9bee275f0c896cc98 --- .../interop/src/arkts/DeserializerBase.ts | 211 ++++++------ .../interop/src/arkts/NativeBuffer.ts | 16 +- .../interop/src/arkts/ResourceManager.ts | 4 + .../interop/src/arkts/SerializerBase.ts | 303 ++++++++++-------- 4 files changed, 284 insertions(+), 250 deletions(-) diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/DeserializerBase.ts b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/DeserializerBase.ts index d55e0d9f585..51a2e228d7d 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/DeserializerBase.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/DeserializerBase.ts @@ -14,16 +14,19 @@ */ import { float32, int32, int64, float32FromBits, uint8 } from "@koalaui/common" -import { pointer, KUint8ArrayPtr, KSerializerBuffer } from "./InteropTypes" +import { pointer, KUint8ArrayPtr, KSerializerBuffer, nullptr } from "./InteropTypes" import { NativeBuffer } from "./NativeBuffer" import { InteropNativeModule } from "./InteropNativeModule" import { Tags, CallbackResource } from "./SerializerBase"; -import { ResourceHolder } from "./ResourceManager" +import { ResourceHolder, Disposable } from "./ResourceManager" +import { unsafeMemory } from "std/core" -export class DeserializerBase { - private position = 0 - private readonly _buffer: KSerializerBuffer +export class DeserializerBase implements Disposable { + private _position : int64 = 0 + private _buffer: KSerializerBuffer + private readonly _isOwnBuffer: boolean; private readonly _length: int32 + private readonly _end: int64 private static customDeserializers: CustomDeserializer | undefined = new DateDeserializer() static registerCustomDeserializer(deserializer: CustomDeserializer) { @@ -40,116 +43,125 @@ export class DeserializerBase { constructor(buffer: KUint8ArrayPtr|KSerializerBuffer, length: int32) { if (buffer instanceof KUint8ArrayPtr) { - this._buffer = InteropNativeModule._Malloc(length) + const newBuffer = InteropNativeModule._Malloc(length) + this._isOwnBuffer = true for (let i = 0; i < length; i++) { - DeserializerBase.writeu8(this._buffer, i, length, buffer[i]) + unsafeMemory.writeInt8(newBuffer + i, buffer[i] as byte) } + this._buffer = newBuffer } else { this._buffer = buffer } + + const newBuffer = this._buffer; this._length = length + this._position = newBuffer + this._end = newBuffer + length; } - // TODO: get rid of length. - private static writeu8(buffer: KSerializerBuffer, offset: int32, length: int32, value: int32): void { - InteropNativeModule._WriteByte(buffer, offset as int64, length as int64, value as uint8) - } - // TODO: get rid of length. - private static readu8(buffer: KSerializerBuffer, offset: int32, length: int32): int32 { - return (InteropNativeModule._ReadByte(buffer, offset as int64, length as int64) as byte) & 0xff + public final dispose() { + if (this._isOwnBuffer) { + InteropNativeModule._Free(this._buffer) + this._buffer = 0 + this._position = 0 + } } final asBuffer(): KSerializerBuffer { return this._buffer } - final currentPosition(): int32 { - return this.position + final currentPosition(): int64 { + return this._position } final resetCurrentPosition(): void { - this.position = 0 + this._position = this._buffer } - private checkCapacity(value: int32) { - if (value > this._length) { - throw new Error(`${value} is less than remaining buffer length`) + final readInt8(): int32 { + const pos = this._position + const newPos = pos + 1 + + if (newPos > this._end) { + throw new Error(`value size(1) is less than remaining buffer length`) } - } - final readInt8(): int32 { - this.checkCapacity(1) - const value = DeserializerBase.readu8(this._buffer, this.position, this._length) - this.position += 1 - return value + this._position = newPos + return unsafeMemory.readInt8(pos) } final readInt32(): int32 { - this.checkCapacity(4) - let res: int32 = 0; - for (let i = 0; i < 4; i++) { - let byteVal = DeserializerBase.readu8(this._buffer, this.position + i, this._length) as int32 - byteVal &= 0xff - res = (res | byteVal << (8 * i)) as int32 + const pos = this._position + const newPos = pos + 4 + + if (newPos > this._end) { + throw new Error(`value size(4) is less than remaining buffer length`) } - this.position += 4 - return res + + this._position = newPos + return unsafeMemory.readInt32(pos) } final readPointer(): pointer { - this.checkCapacity(8) - let res: int64 = 0; - for (let i = 0; i < 8; i++) { - let byteVal = DeserializerBase.readu8(this._buffer, this.position + i, this._length) as int64; - byteVal &= 0xff - res = (res | byteVal << (8 * i)) as int64; + const pos = this._position + const newPos = pos + 8 + + if (newPos > this._end) { + throw new Error(`value size(8) is less than remaining buffer length`) } - this.position += 8 - return res + + this._position = newPos + return unsafeMemory.readInt64(pos) } final readInt64(): int64 { - this.checkCapacity(8) - let res: int64 = 0; - for (let i = 0; i < 8; i++) { - let byteVal = DeserializerBase.readu8(this._buffer, this.position + i, this._length) as int64; - byteVal &= 0xff - res = (res | byteVal << (8 * i)) as int64; + const pos = this._position + const newPos = pos + 8 + + if (newPos > this._end) { + throw new Error(`value size(8) is less than remaining buffer length`) } - this.position += 8 - return res + + this._position = newPos + return unsafeMemory.readInt64(pos) } final readFloat32(): float32 { - this.checkCapacity(4) - let res: int32 = 0; - for (let i = 0; i < 4; i++) { - let byteVal = DeserializerBase.readu8(this._buffer, this.position + i, this._length) as int32; - byteVal &= 0xff - res = (res | byteVal << (8 * i)) as int32; + const pos = this._position + const newPos = pos + 4 + + if (newPos > this._end) { + throw new Error(`value size(4) is less than remaining buffer length`) } - this.position += 4 - return float32FromBits(res) + + + this._position = newPos + return unsafeMemory.readFloat32(pos) } final readBoolean(): boolean { - this.checkCapacity(1) - const value = DeserializerBase.readu8(this._buffer, this.position, this._length) - this.position += 1 + const pos = this._position + const newPos = pos + 1 + + if (newPos > this._end) { + throw new Error(`value size(1) is less than remaining buffer length`) + } + + + this._position = newPos + const value = unsafeMemory.readInt8(pos); + if (value == 5) + return false; + return value == 1 } - readFunction(): int32 { + final readFunction(): int32 { // TODO: not exactly correct. - const id = this.readInt32() - return id + return this.readInt32() } - // readMaterialized(): object { - // const ptr = this.readPointer() - // return { ptr: ptr } - // } - final readCallbackResource(): CallbackResource { return ({ resourceId: this.readInt32(), @@ -159,12 +171,17 @@ export class DeserializerBase { } final readString(): string { - const length = this.readInt32() - this.checkCapacity(length) - // read without null-terminated byte - const value = InteropNativeModule._Utf8ToString(this._buffer, this.position, length) - this.position += length - return value + const encodedLength = this.readInt32(); + const pos = this._position + const newPos = pos + encodedLength + + if (newPos > this._end) { + throw new Error(`value size(${encodedLength}) is less than remaining buffer length`) + } + + this._position = newPos + // NOTE: skip null-terminated byte + return unsafeMemory.readString(pos, encodedLength - 1) } final readCustomObject(kind: string): object { @@ -181,46 +198,26 @@ export class DeserializerBase { } final readNumber(): number | undefined { - const tag = this.readInt8() - if (tag == Tags.UNDEFINED) { - return undefined - } else if (tag == Tags.INT32) { - return this.readInt32() - } else if (tag == Tags.FLOAT32) { - return this.readFloat32() - } else { - throw new Error(`Unknown number tag: ${tag}`) + const pos = this._position + const tag = this.readInt8() as int + switch (tag) { + case Tags.UNDEFINED as int: + return undefined; + case Tags.INT32 as int: + return this.readInt32() + case Tags.FLOAT32 as int: + return this.readFloat32() + default: + throw new Error(`Unknown number tag: ${tag}`) } } - readObject():object { + final readObject():object { const resource = this.readCallbackResource() return ResourceHolder.instance().get(resource.resourceId) } - static lengthUnitFromInt(unit: int32): string { - let suffix: string - switch (unit) { - case 0: - suffix = "px" - break - case 1: - suffix = "vp" - break - case 3: - suffix = "%" - break - case 4: - suffix = "lpx" - break - default: - suffix = "" - } - return suffix - } - final readBuffer(): NativeBuffer { - /* not implemented */ const resource = this.readCallbackResource() const data = this.readPointer() const length = this.readInt64() diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/NativeBuffer.ts b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/NativeBuffer.ts index baf10326cc0..c3beb12eb83 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/NativeBuffer.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/NativeBuffer.ts @@ -16,6 +16,8 @@ import { pointer, KSerializerBuffer, nullptr } from './InteropTypes' import { int32, int64 } from '@koalaui/common' import { InteropNativeModule } from "./InteropNativeModule" +import { Disposable } from "./ResourceManager" +import { unsafeMemory } from "std/core" // stub wrapper for KInteropBuffer export final class NativeBuffer { @@ -33,12 +35,12 @@ export final class NativeBuffer { this.release = release } - public readByte(index:int32): int32 { - return InteropNativeModule._ReadByte(this.data, index, this.length) + public readByte(index:int64): int32 { + return unsafeMemory.readInt8(this.data + index) } - public writeByte(index:int32, value: int32): void { - InteropNativeModule._WriteByte(this.data, index, this.length, value) + public writeByte(index:int64, value: int32): void { + unsafeMemory.writeInt8(this.data + index, value as byte) } static wrap(data:pointer, length: int64, resourceId: int32, hold:pointer, release: pointer): NativeBuffer { @@ -46,7 +48,7 @@ export final class NativeBuffer { } } -export class KBuffer { +export class KBuffer implements Disposable { private _buffer: KSerializerBuffer private readonly _length: int64 private readonly _owned: boolean @@ -77,9 +79,9 @@ export class KBuffer { } public get(index: int64): byte { - return InteropNativeModule._ReadByte(this._buffer, index, this._length) as byte + return unsafeMemory.readInt8(this._buffer + index) } public set(index: int64, value: byte): void { - InteropNativeModule._WriteByte(this._buffer, index, this._length, value) + unsafeMemory.writeInt8(this._buffer + index, value) } } \ No newline at end of file diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/ResourceManager.ts b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/ResourceManager.ts index fca2c6eea66..b6ca49f3f3c 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/ResourceManager.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/ResourceManager.ts @@ -22,6 +22,10 @@ interface ResourceInfo { holdersCount: int32 } +export interface Disposable { + dispose(): void; +} + export class ResourceHolder { private static nextResourceId: ResourceId = 100 private resources: Map = new Map() diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/SerializerBase.ts b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/SerializerBase.ts index 7342ad5a265..dc8424eb6f4 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/SerializerBase.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/arkts/SerializerBase.ts @@ -14,54 +14,73 @@ */ import { float32, float64, int8, int32, int64, uint8, int32BitsFromFloat } from "@koalaui/common" import { pointer, nullptr, KSerializerBuffer } from "./InteropTypes" -import { ResourceId, ResourceHolder } from "./ResourceManager" +import { ResourceId, ResourceHolder, Disposable } from "./ResourceManager" import { NativeBuffer } from "./NativeBuffer" import { InteropNativeModule } from "./InteropNativeModule" import { MaterializedBase } from "./MaterializedBase" +import {unsafeMemory} from "std/core" /** * Value representing possible JS runtime object type. * Must be synced with "enum RuntimeType" in C++. */ -export class RuntimeType { - static UNEXPECTED = -1 - static NUMBER = 1 - static STRING = 2 - static OBJECT = 3 - static BOOLEAN = 4 - static UNDEFINED = 5 - static BIGINT = 6 - static FUNCTION = 7 - static SYMBOL = 8 - static MATERIALIZED = 9 +export final class RuntimeType { + static readonly UNEXPECTED = -1 + static readonly NUMBER = 1 + static readonly STRING = 2 + static readonly OBJECT = 3 + static readonly BOOLEAN = 4 + static readonly UNDEFINED = 5 + static readonly BIGINT = 6 + static readonly FUNCTION = 7 + static readonly SYMBOL = 8 + static readonly MATERIALIZED = 9 } /** * Value representing object type in serialized data. * Must be synced with "enum Tags" in C++. */ -export class Tags { - static UNDEFINED = 101 - static INT32 = 102 - static FLOAT32 = 103 - static STRING = 104 - static LENGTH = 105 - static RESOURCE = 106 - static OBJECT = 107 +export enum Tags { + UNDEFINED = 101, + INT32 = 102, + FLOAT32 = 103, + STRING = 104, + LENGTH = 105, + RESOURCE = 106, + OBJECT = 107, } -export function runtimeType(value: Object|String|number|undefined|null): int32 { - let type = typeof value - if (type == "number") return RuntimeType.NUMBER - if (type == "string") return RuntimeType.STRING - if (type == "undefined") return RuntimeType.UNDEFINED - if (type == "object") return RuntimeType.OBJECT - if (type == "boolean") return RuntimeType.BOOLEAN - if (type == "bigint") return RuntimeType.BIGINT - if (type == "function") return RuntimeType.FUNCTION - if (type == "symbol") return RuntimeType.SYMBOL - - throw new Error(`bug: ${value} is ${type}`) +const VALUE_UNDEFINED: number = 5 +const VALUE_TRUE: number = 1 +const VALUE_FALSE: number = 0 + +export function runtimeType(value: T): int32 { + if (value === undefined) + return RuntimeType.UNDEFINED; + + if (value === null) + return RuntimeType.OBJECT; + + if (value instanceof String) + return RuntimeType.STRING + + if (value instanceof Numeric) + return RuntimeType.NUMBER + + if (value instanceof Boolean) + return RuntimeType.BOOLEAN + + if (value instanceof BigInt) + return RuntimeType.BIGINT + + if (value instanceof Function) + return RuntimeType.FUNCTION + + if (value instanceof Object) + return RuntimeType.OBJECT + + throw new Error(`bug: ${value} is ${typeof value}`) } export function registerCallback(value: object): int32 { @@ -97,7 +116,7 @@ export abstract class CustomSerializer { class DateSerializer extends CustomSerializer { constructor() { - super(Array.of("Date" as string)) + super(new Array("Date" as string)) } serialize(serializer: SerializerBase, value: object, kind: string): void { @@ -106,10 +125,11 @@ class DateSerializer extends CustomSerializer { } SerializerBase.registerCustomSerializer(new DateSerializer()) -export class SerializerBase { - private position: int32 = 0 +export class SerializerBase implements Disposable { + private _position: int64 = 0 private _buffer: KSerializerBuffer private _length: int32 + private _last: int64 private static customSerializers: CustomSerializer | undefined = new DateSerializer() static registerCustomSerializer(serializer: CustomSerializer) { @@ -128,83 +148,62 @@ export class SerializerBase { let length = 96 this._buffer = InteropNativeModule._Malloc(length as int64) this._length = length + this._position = this._buffer + this._last = this._buffer + length - 1; } + public release() { this.releaseResources() - this.position = 0 + this._position = this._buffer + } + public final dispose() { + InteropNativeModule._Free(this._buffer) + this._buffer = nullptr } + final asBuffer(): KSerializerBuffer { return this._buffer } final length(): int32 { - return this.position - } - final currentPosition(): int32 { - return this.position - } - // TODO: get rid of length. - private static writeu8(buffer: KSerializerBuffer, offset: int32, length: int32, value: int32) { - InteropNativeModule._WriteByte(buffer, offset as int64, length as int64, value as uint8) - } - // TODO: get rid of length. - private static readu8(buffer: KSerializerBuffer, offset: int32, length: int32): int32 { - return InteropNativeModule._ReadByte(buffer, offset as int64, length as int64) - } - private static writeu32(buffer: KSerializerBuffer, offset: int32, length: int32, value: int32) { - InteropNativeModule._WriteByte(buffer, offset, length as int64, (value & 0xff) as uint8) - InteropNativeModule._WriteByte(buffer, offset + 1, length as int64, ((value >> 8) & 0xff) as uint8) - InteropNativeModule._WriteByte(buffer, offset + 2, length as int64, ((value >> 16) & 0xff) as uint8) - InteropNativeModule._WriteByte(buffer, offset + 3, length as int64, ((value >> 24) & 0xff) as uint8) - } - private writeu32(position: int32, value: int32): void { - SerializerBase.writeu8(this._buffer, position + 0, this._length, ((value ) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, position + 1, this._length, ((value >> 8) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, position + 2, this._length, ((value >> 16) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, position + 3, this._length, ((value >> 24) & 0xff) as int8) - } - // TODO: get rid of length. - private static readu32(buffer: KSerializerBuffer, offset: int32, length: int32): int32 { - return InteropNativeModule._ReadByte(buffer, offset as int64, length as int64) + return (this._position - this._buffer) as int32 } - final getByte(offset: int32): byte { - return SerializerBase.readu8(this._buffer, offset, this._length) as byte - } final toArray(): byte[] { - let result = new byte[this.currentPosition()] - for (let i = 0; i < this.currentPosition(); i++) { - result[i] = this.getByte(i) as byte + const len = this.length() + let result = new byte[len] + for (let i = 0; i < len; i++) { + result[i] = unsafeMemory.readInt8(this._buffer + i) } return result } - private checkCapacity(value: int32) { - if (value < 1) { - throw new Error(`${value} is less than 1`) - } + + private final updateCapacity(value: int32) { let buffSize = this._length - if (this.position > buffSize - value) { - const minSize = this.position + value - const resizedSize = Math.max(minSize, Math.round(3 * buffSize / 2)) as int32 - let resizedBuffer = InteropNativeModule._Malloc(resizedSize) - let oldBuffer = this._buffer - for (let i = 0; i < this.position; i++) { - SerializerBase.writeu8(resizedBuffer, i, resizedSize, SerializerBase.readu8(oldBuffer, i, this.position)) - } - this._buffer = resizedBuffer - this._length = resizedSize - InteropNativeModule._Free(oldBuffer) + const minSize = buffSize + value + const resizedSize = Math.max(minSize, Math.round(3 * buffSize / 2)) as int32 + let resizedBuffer = InteropNativeModule._Malloc(resizedSize) + let oldBuffer = this._buffer + for (let i = 0; i < this._position; i++) { + let val = unsafeMemory.readInt8(oldBuffer + i); + unsafeMemory.writeInt8(resizedBuffer + i, val) } + this._buffer = resizedBuffer + this._position = this._position - oldBuffer + resizedBuffer + this._length = resizedSize + this._last = resizedBuffer + resizedSize - 1; + InteropNativeModule._Free(oldBuffer) } + private heldResources: Array = new Array() private heldResourcesCount: int32 = 0 - private addHeldResource(resourceId: ResourceId) { + private final addHeldResource(resourceId: ResourceId) { if (this.heldResourcesCount == this.heldResources.length) this.heldResources.push(resourceId) else this.heldResources[this.heldResourcesCount] = resourceId this.heldResourcesCount++ } - holdAndWriteCallback(callback: object, hold: pointer = 0, release: pointer = 0, call: pointer = 0, callSync: pointer = 0): ResourceId { + final holdAndWriteCallback(callback: object, hold: pointer = 0, release: pointer = 0, call: pointer = 0, callSync: pointer = 0): ResourceId { const resourceId = ResourceHolder.instance().registerAndHold(callback) this.addHeldResource(resourceId) this.writeInt32(resourceId) @@ -214,8 +213,8 @@ export class SerializerBase { this.writePointer(callSync) return resourceId } - holdAndWriteCallbackForPromiseVoid(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { - let resourceId: ResourceId + final holdAndWriteCallbackForPromiseVoid(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { + let resourceId: ResourceId = 0 const promise = new Promise((resolve: (value: PromiseLike) => void, reject: (err: Error) => void) => { const callback = (err: Error|undefined) => { if (err !== undefined) @@ -227,8 +226,8 @@ export class SerializerBase { }) return [promise, resourceId] } - holdAndWriteCallbackForPromise(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { - let resourceId: ResourceId + final holdAndWriteCallbackForPromise(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { + let resourceId: ResourceId = 0 const promise = new Promise((resolve: (value: T|PromiseLike) => void, reject: (err: Error) => void) => { const callback = (value?: T|undefined, err?: Error|undefined) => { if (err !== undefined) @@ -240,7 +239,7 @@ export class SerializerBase { }) return [promise, resourceId] } - holdAndWriteObject(obj:object, hold: pointer = 0, release: pointer = 0): ResourceId { + final holdAndWriteObject(obj:object, hold: pointer = 0, release: pointer = 0): ResourceId { const resourceId = ResourceHolder.instance().registerAndHold(obj) this.addHeldResource(resourceId) this.writeInt32(resourceId) @@ -258,7 +257,7 @@ export class SerializerBase { this.addHeldResource(resourceId) this.writeInt32(resourceId) } - private releaseResources() { + private final releaseResources() { if (this.heldResourcesCount == 0) return for (let i = 0; i < this.heldResourcesCount; i++) { InteropNativeModule._ReleaseCallbackResource(this.heldResources[i]) @@ -274,80 +273,112 @@ export class SerializerBase { } current = current!.next } - // console.log(`Unsupported custom serialization for ${kind}, write undefined`) this.writeInt8(Tags.UNDEFINED as int32) } - writeFunction(value: Object) { + final writeFunction(value: Object) { this.writeInt32(registerCallback(value)) } final writeTag(tag: int32): void { - SerializerBase.writeu8(this._buffer, this.position, this._length, tag as int8) - this.position++ + this.writeInt8(tag) } final writeNumber(value: number|undefined) { - this.checkCapacity(5) if (value == undefined) { this.writeTag(Tags.UNDEFINED) - this.position++ return } - if ((value as float64) == Math.round(value)) { + if (value == Math.round(value)) { this.writeTag(Tags.INT32) this.writeInt32(value as int32) - return } else { - this.writeTag(Tags.FLOAT32) - this.writeFloat32(value as float32) + this.writeInt8(Tags.FLOAT32) + this.writeFloat32(value as float) } } + final writeInt8(value: int32) { - this.checkCapacity(1) - SerializerBase.writeu8(this._buffer, this.position, this._length, value as int8) - this.position += 1 - } - private setInt32(position: int32, value: int32): void { - SerializerBase.writeu32(this._buffer, this.position, this._length, value) + let pos = this._position + let newPos = pos + 1 + if (newPos > this._last) { + this.updateCapacity(1) + pos = this._position + newPos = pos + 1 + } + + unsafeMemory.writeInt8(pos, value as byte) + this._position = newPos } + final writeInt32(value: int32) { - this.checkCapacity(4) - this.setInt32(this.position, value) - this.position += 4 + let pos = this._position + let newPos = pos + 4 + if (newPos > this._last) { + this.updateCapacity(4) + pos = this._position + newPos = pos + 4 + } + + unsafeMemory.writeInt32(pos, value) + this._position = newPos } final writeInt64(value: int64) { - this.checkCapacity(8) - SerializerBase.writeu8(this._buffer, this.position + 0, this._length, ((value ) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 1, this._length, ((value >> 8) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 2, this._length, ((value >> 16) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 3, this._length, ((value >> 24) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 4, this._length, ((value >> 32) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 5, this._length, ((value >> 40) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 6, this._length, ((value >> 48) & 0xff) as int8) - SerializerBase.writeu8(this._buffer, this.position + 7, this._length, ((value >> 56) & 0xff) as int8) - this.position += 8 + let pos = this._position + let newPos = pos + 8 + if (newPos > this._last) { + this.updateCapacity(8) + pos = this._position + newPos = pos + 8 + } + + unsafeMemory.writeInt64(pos, value) + this._position = newPos } final writeFloat32(value: float32) { - let bits = int32BitsFromFloat(value) - this.checkCapacity(4) - SerializerBase.writeu32(this._buffer, this.position + 0, this._length, bits) - this.position += 4 + let pos = this._position + let newPos = pos + 4 + if (newPos > this._last) { + this.updateCapacity(4) + pos = this._position + newPos = pos + 4 + } + + unsafeMemory.writeFloat32(pos, value) + this._position = newPos } final writePointer(value: pointer) { this.writeInt64(value) } final writeBoolean(value: boolean|undefined) { - this.checkCapacity(1) - if (value == undefined) { - SerializerBase.writeu8(this._buffer, this.position, this._length, RuntimeType.UNDEFINED as int32 as int8) - } else { - SerializerBase.writeu8(this._buffer, this.position, this._length, (value ? 1 : 0) as int8) + let pos = this._position + let newPos = pos + 1 + if (newPos > this._last) { + this.updateCapacity(1) + pos = this._position + newPos = pos + 1 } - this.position++ + this._position = newPos + + if (value == undefined) + unsafeMemory.writeInt8(pos, VALUE_UNDEFINED as byte); + else if (value == true) + unsafeMemory.writeInt8(pos, VALUE_TRUE as byte); + else if (value == false) + unsafeMemory.writeInt8(pos, VALUE_FALSE as byte); } final writeString(value: string) { - this.checkCapacity((4 + value.length * 4 + 1) as int32) // length, data - let encodedLength = InteropNativeModule._ManagedStringWrite(value, this.asBuffer(), this.position + 4) - this.setInt32(this.position, encodedLength) - this.position += encodedLength + 4 + const encodedCapacity = unsafeMemory.getStringSizeInBytes(value) + 1 + + let pos = this._position + if (pos + encodedCapacity + 4 > this._last) { + this.updateCapacity(encodedCapacity + 4) + pos = this._position + } + + const encodedLength = unsafeMemory.writeString(pos + 4, value) + // NOTE: add \0 for supporting C char* reading from buffer for utf8-strings, + // need check native part fot utf16 cases and probably change this solution. + unsafeMemory.writeInt8(pos + encodedLength + 4, 0 as byte) + unsafeMemory.writeInt32(pos, encodedLength + 1) + this._position = pos + encodedLength + 4 + 1 } //TODO: Needs to be implemented final writeBuffer(value: NativeBuffer) { -- Gitee