diff options
author | 2023-07-14 19:37:22 -0700 | |
---|---|---|
committer | 2023-07-14 19:37:22 -0700 | |
commit | c39c11e1011b682c2c4e48594c7d6110cfc3343c (patch) | |
tree | 8808ca4cd6684949423f28f3cd4d90aedb605cb7 /src/bun.js/scripts/generate-classes.ts | |
parent | 25512104265aa568ca98e5bd89a977203ee261a6 (diff) | |
download | bun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.tar.gz bun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.tar.zst bun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.zip |
structured clone (#3637)
* copy `SerializedScriptValue`
* format
* make `SerializedScriptValue` compile
* add `transfer` option
* tests
* serialize/deserialize blobs
* tests for blobs
* serialize/deserialize file blobs
* more tests
* small cleanup
* format
* small changes + serialize offset
* slice helper
* map and set test
Diffstat (limited to 'src/bun.js/scripts/generate-classes.ts')
-rw-r--r-- | src/bun.js/scripts/generate-classes.ts | 138 |
1 files changed, 133 insertions, 5 deletions
diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts index ff6954753..fb4419642 100644 --- a/src/bun.js/scripts/generate-classes.ts +++ b/src/bun.js/scripts/generate-classes.ts @@ -345,6 +345,25 @@ ${ JSC_DECLARE_CUSTOM_GETTER(js${typeName}Constructor);` : "" } + +${ + obj.structuredClone + ? `extern "C" void ${symbolName( + typeName, + "onStructuredCloneSerialize", + )}(void*, JSC::JSGlobalObject*, void*, void (*) (CloneSerializer*, const uint8_t*, uint32_t));` + : "" +} + +${ + obj.structuredClone + ? `extern "C" JSC::EncodedJSValue ${symbolName( + typeName, + "onStructuredCloneDeserialize", + )}(JSC::JSGlobalObject*, const uint8_t*, const uint8_t*);` + : "" +} + ${"finalize" in obj ? `extern "C" void ${classSymbolName(typeName, "finalize")}(void*);` : ""} ${obj.call ? `extern "C" JSC_DECLARE_HOST_FUNCTION(${classSymbolName(typeName, "call")});` : ""} @@ -1200,6 +1219,7 @@ function generateZig( call = false, values = [], hasPendingActivity = false, + structuredClone = false, } = {} as ClassDefinition, ) { const exports = new Map<string, string>(); @@ -1226,6 +1246,16 @@ function generateZig( Object.values(klass).map(a => appendSymbols(exports, name => classSymbolName(typeName, name), a)); Object.values(proto).map(a => appendSymbols(exports, name => protoSymbolName(typeName, name), a)); + if (structuredClone) { + exports.set("onStructuredCloneSerialize", symbolName(typeName, "onStructuredCloneSerialize")); + + if (structuredClone === "transferrable") { + exports.set("onStructuredCloneTransfer", symbolName(typeName, "onStructuredCloneTransfer")); + } + + exports.set("onStructuredCloneDeserialize", symbolName(typeName, "onStructuredCloneDeserialize")); + } + const externs = Object.entries({ ...proto, ...Object.fromEntries((values || []).map(a => [a, { internal: true }])), @@ -1269,6 +1299,29 @@ function generateZig( `; } + if (structuredClone) { + output += ` + if (@TypeOf(${typeName}.onStructuredCloneSerialize) != (fn(*${typeName}, globalThis: *JSC.JSGlobalObject, ctx: *anyopaque, writeBytes: *const fn(*anyopaque, ptr: [*]const u8, len: u32) callconv(.C) void) callconv(.C) void)) { + @compileLog("${typeName}.onStructuredCloneSerialize is not a structured clone serialize function"); + } + `; + + if (structuredClone === "transferrable") { + exports.set("structuredClone", symbolName(typeName, "onTransferrableStructuredClone")); + output += ` + if (@TypeOf(${typeName}.onStructuredCloneTransfer) != (fn(*${typeName}, globalThis: *JSC.JSGlobalObject, ctx: *anyopaque, write: *const fn(*anyopaque, ptr: [*]const u8, len: usize) callconv(.C) void) callconv(.C) void)) { + @compileLog("${typeName}.onStructuredCloneTransfer is not a structured clone transfer function"); + } + `; + } + + output += ` + if (@TypeOf(${typeName}.onStructuredCloneDeserialize) != (fn(globalThis: *JSC.JSGlobalObject, ptr: [*]u8, end: [*]u8) callconv(.C) JSC.JSValue)) { + @compileLog("${typeName}.onStructuredCloneDeserialize is not a structured clone deserialize function"); + } + `; + } + if (construct && !noConstructor) { output += ` if (@TypeOf(${typeName}.constructor) != (fn(*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*${typeName})) { @@ -1532,6 +1585,7 @@ namespace Zig { #include "JSDOMWrapper.h" #include <wtf/NeverDestroyed.h> +#include "SerializedScriptValue.h" `, ` @@ -1543,11 +1597,6 @@ using namespace JSC; `, ]; -const GENERATED_CLASSES_FOOTER = ` -} - -`; - const GENERATED_CLASSES_IMPL_HEADER = ` // GENERATED CODE - DO NOT MODIFY BY HAND // Generated by make codegen @@ -1676,6 +1725,84 @@ function writeAndUnlink(path, content) { return Bun.write(path, content); } +const GENERATED_CLASSES_FOOTER = ` + +class StructuredCloneableSerialize { + public: + + void (*cppWriteBytes)(CloneSerializer*, const uint8_t*, uint32_t); + + std::function<void(void*, JSC::JSGlobalObject*, void*, void (*)(CloneSerializer*, const uint8_t*, uint32_t))> zigFunction; + + uint8_t tag; + + // the type from zig + void* impl; + + static std::optional<StructuredCloneableSerialize> fromJS(JSC::JSValue); + void write(CloneSerializer* serializer, JSC::JSGlobalObject* globalObject) + { + zigFunction(impl, globalObject, serializer, cppWriteBytes); + } +}; + +class StructuredCloneableDeserialize { + public: + static std::optional<JSC::EncodedJSValue> fromTagDeserialize(uint8_t tag, JSC::JSGlobalObject*, const uint8_t*, const uint8_t*); +}; + +} + +`; + +function writeCppSerializers() { + var output = ``; + + var structuredClonable = classes + .filter(a => a.structuredClone) + .sort((a, b) => a.structuredClone.tag < b.structuredClone.tag); + + function fromJSForEachClass(klass) { + return ` + if (auto* result = jsDynamicCast<${className(klass.name)}*>(value)) { + return StructuredCloneableSerialize { .cppWriteBytes = SerializedScriptValue::writeBytesForBun, .zigFunction = ${symbolName( + klass.name, + "onStructuredCloneSerialize", + )}, .tag = ${klass.structuredClone.tag}, .impl = result->wrapped() }; + } + `; + } + + function fromTagDeserializeForEachClass(klass) { + return ` + if (tag == ${klass.structuredClone.tag}) { + return ${symbolName(klass.name, "onStructuredCloneDeserialize")}(globalObject, ptr, end); + } + `; + } + + output += ` + std::optional<StructuredCloneableSerialize> StructuredCloneableSerialize::fromJS(JSC::JSValue value) + { + ${structuredClonable.map(fromJSForEachClass).join("\n").trim()} + return std::nullopt; + } + `; + + output += ` + std::optional<JSC::EncodedJSValue> StructuredCloneableDeserialize::fromTagDeserialize(uint8_t tag, JSC::JSGlobalObject* globalObject, const uint8_t* ptr, const uint8_t* end) + { + ${structuredClonable.map(fromTagDeserializeForEachClass).join("\n").trim()} + return std::nullopt; + } + `; + + for (let klass of classes) { + } + + return output; +} + await writeAndUnlink(`${import.meta.dir}/../bindings/generated_classes.zig`, [ ZIG_GENERATED_CLASSES_HEADER, @@ -1699,6 +1826,7 @@ await writeAndUnlink(`${import.meta.dir}/../bindings/ZigGeneratedClasses.h`, [ await writeAndUnlink(`${import.meta.dir}/../bindings/ZigGeneratedClasses.cpp`, [ GENERATED_CLASSES_IMPL_HEADER, ...classes.map(a => generateImpl(a.name, a)), + writeCppSerializers(classes), GENERATED_CLASSES_IMPL_FOOTER, ]); await writeAndUnlink( |