-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Milestone] v1 #1
Comments
Will need too delve into C++ code to figure out how they do the serialization stuff. 😨 Old code from my Gist which attempted to 1:1 convert some C++ V8 serialization logicenum SerializationTag {
version = "\xFF",
padding = "\0",
verifyObjectCount = "?"
// ...
}
enum ArrayBufferViewTag {
int8Array = "b",
uint32Array = "B",
// ...
}
enum ErrorTag {
evalErrorPrototype = "E",
rangeError = "R",
// ...
}
class ValueSerializer {
#buffer = new ArrayBuffer(0, { maxByteLength: 100 * 1024 });
#treatArrayBufferViewsAsHostObjects: boolean;
writeHeader() {
this.writeTag(SerializationTag.version);
this.writeVarint(15);
}
set treatArrayBufferViewsAsHostObjects(mode: boolean) {
this.#treatArrayBufferViewsAsHostObjects = mode;
}
writeTag(tag: string) {
const rawTag = tag.charCodeAt(0);
this.writeRawBytes(Uint8Array.of(rawTag));
}
writeVarint(value: number) {
// Writes an unsigned integer as a base-128 varint.
// The number is written, 7 bits at a time, from the least significant to the
// most significant 7 bits. Each byte, except the last, has the MSB set.
// See also https://developers.google.com/protocol-buffers/docs/encoding
const stackBuffer = new Uint8Array(Number_sizeof(value) * 8 / 7 + 1);
let nextByte = 0
do {
stackBuffer[nextByte] = (value & 0x7f) | 0x80;
nextByte++;
value >>= 7;
} while(value);
stackBuffer[nextByte - 1] &= 0x7f;
this.writeRawBytes(stackBuffer.subarray(0, nextByte));
}
writeZigZag(value: number) {
// Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
// encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
// See also https://developers.google.com/protocol-buffers/docs/encoding
// Note that this implementation relies on the right shift being arithmetic.
this.writeVarint((value << 1) ^ (value >> (8 * Number_sizeof(value) - 1)));
}
writeDouble(value: number) {
this.writeRawBytes(Float64Array.of(value));
}
writeOneByteString(value: string) {
this.writeVarint(value.length);
this.writeRawBytes(Uint8Array.from(value, c => c.charCodeAt(0)));
}
writeTwoByteString(value: string) {
this.writeVarint(value.length);
this.writeRawBytes(Uint16Array.from(value, c => c.charCodeAt(0)));
}
writeBigIntContents(value: bigint) {
const bitField = BigInt_getBitFieldForSerialization(value);
const byteLength = BigInt_digitsByteLengthForSerialization(bitField);
this.writeVarint(bitField);
const bytes = this.reserveRawBytes(byteLength);
BigInt_serializeDigits(value, bytes);
}
writeRawBytes(value: Uint8Array) {
if (length === 0) {
return
}
const bytes = this.reserveRawBytes(value.length);
bytes.set(value);
}
reserveRawBytes(length: number): Uint8Array {
this.#buffer.resize(this.#buffer.byteLength + length);
return new Uint8Array(this.#buffer, this.#buffer.byteLength - length, length);
}
writeByte(value: number) {
const bytes = this.reserveRawBytes(1);
bytes[0] = value;
}
writeUint32(value: number) {
this.writeVarint(value);
}
writeUint64(value: number) {
this.writeVarint(value);
}
release() {
const buffer = this.#buffer;
this.#buffer = new ArrayBuffer(0, { maxByteLength: 100 * 1024 });
}
writeObject(value: object) {
if (isSMI(value)) {
this.writeSMI(value);
return
}
switch(typeof value) {
case
this.writeOddball(value);
return
case "number":
this.writeHeapNumber(value);
return
case "bigint":
this.writeBigInt(value);
return
case ""
}
}
function v8_serialize(value: any): Uint8Array {
} |
So here's the v8.js file for the node:v8 module: https://github.com/nodejs/node/blob/v20.2.0/lib/v8.js This is where the C++ Serializer and Deserializer classes seem to be defined: https://github.com/nodejs/node/blob/v20.2.0/src/node_serdes.cc Then there's ANOTHER layer since those Node.js C++ classes delegate a lot of magic to this: using v8::ValueDeserializer;
using v8::ValueSerializer;
Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate,
Local<Object> input) {
MaybeLocal<Value> ret;
Local<Value> args[1] = { input };
Local<Value> write_host_object =
object()->Get(env()->context(),
env()->write_host_object_string()).ToLocalChecked();
if (!write_host_object->IsFunction()) {
return ValueSerializer::Delegate::WriteHostObject(isolate, input);
}
ret = write_host_object.As<Function>()->Call(env()->context(),
object(),
arraysize(args),
args);
if (ret.IsEmpty())
return Nothing<bool>();
return Just(true);
} |
Then that value serializer is defined in V8! https://github.com/v8/v8/blob/main/src/objects/value-serializer.cc |
Goal: Implement https://nodejs.org/api/v8.html#serialization-api
v8.serialize(value)
v8.deserialize(buffer)
new Serializer()
serializer.writeHeader()
serializer.writeValue(value)
serializer.releaseBuffer()
serializer.transferArrayBuffer(id, arrayBuffer)
serializer.writeUint32(value)
serializer.writeUint64(hi, lo)
serializer.writeDouble(value)
serializer.writeRawBytes(buffer)
serializer._writeHostObject(object)
serializer._getDataCloneError(message)
serializer._getSharedArrayBufferId(sharedArrayBuffer)
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
new Deserializer(buffer)
deserializer.readHeader()
deserializer.readValue()
deserializer.transferArrayBuffer(id, arrayBuffer)
deserializer.getWireFormatVersion()
deserializer.readUint32()
deserializer.readUint64()
deserializer.readDouble()
deserializer.readRawBytes(length)
deserializer._readHostObject()
v8.DefaultSerializer
v8.DefaultDeserializer
The text was updated successfully, but these errors were encountered: