aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/generate-jssink.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
commit729d445b6885f69dd2c6355f38707bd42851c791 (patch)
treef87a7c408929ea3f57bbb7ace380cf869da83c0e /src/bun.js/generate-jssink.js
parent25f820c6bf1d8ec6d444ef579cc036b8c0607b75 (diff)
downloadbun-729d445b6885f69dd2c6355f38707bd42851c791.tar.gz
bun-729d445b6885f69dd2c6355f38707bd42851c791.tar.zst
bun-729d445b6885f69dd2c6355f38707bd42851c791.zip
change the directory structurejarred/rename
Diffstat (limited to 'src/bun.js/generate-jssink.js')
-rw-r--r--src/bun.js/generate-jssink.js770
1 files changed, 770 insertions, 0 deletions
diff --git a/src/bun.js/generate-jssink.js b/src/bun.js/generate-jssink.js
new file mode 100644
index 000000000..1d20be64f
--- /dev/null
+++ b/src/bun.js/generate-jssink.js
@@ -0,0 +1,770 @@
+const classes = ["ArrayBufferSink"];
+const SINK_COUNT = 5;
+
+function names(name) {
+ return {
+ constructor: `JS${name}Constructor`,
+ className: `JS${name}`,
+ controller: `JSReadable${name}Controller`,
+ controllerName: `Readable${name}Controller`,
+ prototypeName: `JS${name}Prototype`,
+ controllerPrototypeName: `JSReadable${name}ControllerPrototype`,
+ };
+}
+function header() {
+ function classTemplate(name) {
+ const { constructor, className, controller } = names(name);
+
+ return `class ${constructor} final : public JSC::InternalFunction {
+ public:
+ using Base = JSC::InternalFunction;
+ static ${constructor}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype);
+ static constexpr SinkID Sink = SinkID::${name};
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<${constructor}, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForJSSinkConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSSinkConstructor = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForJSSinkConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForJSSinkConstructor = WTFMove(space); });
+ }
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype);
+
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+
+ private:
+ ${constructor}(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype);
+ };
+
+ class ${className} final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static ${className}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
+ static constexpr SinkID Sink = SinkID::${name};
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<${className}, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForJSSink.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSSink = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForJSSink.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForJSSink = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ ~${className}();
+
+ void* wrapped() const { return m_sinkPtr; }
+
+ void detach() {
+ m_sinkPtr = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+
+ void* m_sinkPtr;
+
+ ${className}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_sinkPtr = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+ };
+
+ class ${controller} final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static ${controller}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
+ static constexpr SinkID Sink = SinkID::${name};
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<${controller}, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForJSSinkController.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSSinkController = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForJSSinkController.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForJSSinkController = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ ~${controller}();
+
+
+ void* wrapped() const { return m_sinkPtr; }
+ void detach() {
+ m_sinkPtr = nullptr;
+ }
+
+ void start(JSC::JSGlobalObject *globalObject, JSC::JSValue readableStream, JSC::JSFunction *onPull, JSC::JSFunction *onClose);
+ DECLARE_VISIT_CHILDREN;
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+
+ void* m_sinkPtr;
+ mutable WriteBarrier<JSC::JSFunction> m_onPull;
+ mutable WriteBarrier<JSC::JSFunction> m_onClose;
+ mutable JSC::Weak<JSObject> m_weakReadableStream;
+
+ ${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_sinkPtr = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+ };
+
+JSC_DECLARE_CUSTOM_GETTER(function${name}__getter);
+
+
+
+ `;
+ }
+
+ const outer = `
+// AUTO-GENERATED FILE. DO NOT EDIT.
+// Generated by ${import.meta.path} at ${new Date().toISOString()}
+//
+#pragma once
+
+#include "root.h"
+
+#include "JSDOMWrapper.h"
+#include "wtf/NeverDestroyed.h"
+
+#include "Sink.h"
+
+extern "C" bool JSSink_isSink(JSC::JSGlobalObject*, JSC::EncodedJSValue);
+
+namespace WebCore {
+using namespace JSC;
+
+JSC_DECLARE_HOST_FUNCTION(functionStartDirectStream);
+`;
+
+ const bottom = `
+JSObject* createJSSinkPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WebCore::SinkID sinkID);
+JSObject* createJSSinkControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WebCore::SinkID sinkID);
+
+} // namespace WebCore
+`;
+ var templ = outer;
+ for (let name of classes) {
+ templ += classTemplate(name) + "\n";
+ }
+ templ += bottom;
+ return templ;
+}
+
+async function implementation() {
+ const head = `
+// AUTO-GENERATED FILE. DO NOT EDIT.
+// Generated by ${import.meta.path} at ${new Date().toISOString()}
+// To regenerate this file, run:
+//
+// bun src/bun.js/generate-jssink.js
+//
+#include "root.h"
+#include "JSSink.h"
+
+#include "ActiveDOMObject.h"
+#include "ExtendedDOMClientIsoSubspaces.h"
+#include "ExtendedDOMIsoSubspaces.h"
+#include "IDLTypes.h"
+// #include "JSBlob.h"
+#include "JSDOMAttribute.h"
+#include "JSDOMBinding.h"
+#include "JSDOMConstructor.h"
+#include "JSDOMConvertBase.h"
+#include "JSDOMConvertInterface.h"
+#include "JSDOMConvertStrings.h"
+#include "JSDOMExceptionHandling.h"
+#include "JSDOMGlobalObject.h"
+#include "JSDOMGlobalObjectInlines.h"
+#include "JSDOMOperation.h"
+#include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "WebCoreJSClientData.h"
+#include "JavaScriptCore/FunctionPrototype.h"
+#include "JavaScriptCore/HeapAnalyzer.h"
+
+#include "JavaScriptCore/JSDestructibleObjectHeapCellType.h"
+#include "JavaScriptCore/SlotVisitorMacros.h"
+#include "JavaScriptCore/SubspaceInlines.h"
+#include "wtf/GetPtr.h"
+#include "wtf/PointerPreparations.h"
+#include "wtf/URL.h"
+#include "JavaScriptCore/BuiltinNames.h"
+
+#include "JSBufferEncodingType.h"
+#include "JSBufferPrototypeBuiltins.h"
+#include "JSBufferConstructorBuiltins.h"
+#include "JavaScriptCore/JSBase.h"
+#if ENABLE(MEDIA_SOURCE)
+#include "BufferMediaSource.h"
+#include "JSMediaSource.h"
+#endif
+
+// #include "JavaScriptCore/JSTypedArrayViewPrototype.h"
+#include "JavaScriptCore/JSArrayBufferViewInlines.h"
+
+#include "JSReadableStream.h"
+#include "BunClientData.h"
+#include "JavaScriptCore/Weak.h"
+#include "JavaScriptCore/WeakInlines.h"
+
+namespace WebCore {
+using namespace JSC;
+
+
+
+
+JSC_DEFINE_HOST_FUNCTION(functionStartDirectStream, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame))
+{
+
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+
+ JSC::JSValue readableStream = callFrame->argument(0);
+ JSC::JSValue onPull = callFrame->argument(1);
+ JSC::JSValue onClose = callFrame->argument(2);
+ if (!readableStream.isObject()) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected ReadableStream"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ if (!onPull.isObject() || !onPull.isCallable()) {
+ onPull = JSC::jsUndefined();
+ }
+
+ if (!onClose.isObject() || !onClose.isCallable()) {
+ onClose = JSC::jsUndefined();
+ }
+
+ JSC::JSFunction *onPullFunction = JSC::jsDynamicCast<JSC::JSFunction*>(onPull);
+ JSC::JSFunction *onCloseFunction = JSC::jsDynamicCast<JSC::JSFunction*>(onClose);
+
+`;
+ var templ = head;
+
+ var isFirst = true;
+ for (let name of classes) {
+ const {
+ className,
+ controller,
+ prototypeName,
+ controllerPrototypeName,
+ constructor,
+ } = names(name);
+
+ templ += `
+
+ ${
+ isFirst ? "" : "else"
+ } if (WebCore::${controller}* ${name}Controller = JSC::jsDynamicCast<WebCore::${controller}*>(callFrame->thisValue())) {
+ if (${name}Controller->wrapped() == nullptr) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Controller is already closed"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ ${name}Controller->start(globalObject, readableStream, onPullFunction, onCloseFunction);
+ }
+`;
+ isFirst = false;
+ }
+
+ templ += `
+ else {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Unknown direct controller. This is a bug in Bun."_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::jsUndefined()));
+}
+`;
+
+ for (let name of classes) {
+ const {
+ className,
+ controller,
+ prototypeName,
+ controllerName,
+ controllerPrototypeName,
+ constructor,
+ } = names(name);
+
+ templ += `
+JSC_DEFINE_CUSTOM_GETTER(function${name}__getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+
+ return JSC::JSValue::encode(globalObject->${name}());
+}
+
+
+JSC_DECLARE_HOST_FUNCTION(${controller}__close);
+JSC_DEFINE_HOST_FUNCTION(${controller}__close, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame))
+{
+
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ WebCore::${controller}* controller = JSC::jsDynamicCast<WebCore::${controller}*>(callFrame->thisValue());
+ if (!controller) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected ${controller}"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ void *ptr = controller->wrapped();
+ if (ptr == nullptr) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Controller is already closed"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ controller->detach();
+ ${name}__close(lexicalGlobalObject, ptr);
+ return JSC::JSValue::encode(JSC::jsUndefined());
+}
+
+JSC_DECLARE_HOST_FUNCTION(${name}__doClose);
+JSC_DEFINE_HOST_FUNCTION(${name}__doClose, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame))
+{
+
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ WebCore::${className}* sink = JSC::jsDynamicCast<WebCore::${className}*>(callFrame->thisValue());
+ if (!sink) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected ${name}"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ void *ptr = sink->wrapped();
+ if (ptr == nullptr) {
+ scope.throwException(globalObject, JSC::createTypeError(globalObject, "Controller is already closed"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+
+ sink->detach();
+ ${name}__close(lexicalGlobalObject, ptr);
+ return JSC::JSValue::encode(JSC::jsUndefined());
+}
+
+
+
+
+static const HashTableValue JS${name}PrototypeTableValues[]
+ = {
+ { "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__doClose), (intptr_t)(0) } },
+ { "drain"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__drain), (intptr_t)(1) } },
+ { "end"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__end), (intptr_t)(0) } },
+ { "start"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__start), (intptr_t)(1) } },
+ { "write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__write), (intptr_t)(1) } },
+ };
+
+static const HashTableValue ${controllerPrototypeName}TableValues[]
+ = {
+ { "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${controller}__close), (intptr_t)(0) } },
+ { "drain"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__drain), (intptr_t)(1) } },
+ { "end"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__end), (intptr_t)(0) } },
+ { "start"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__start), (intptr_t)(1) } },
+ { "write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(${name}__write), (intptr_t)(1) } },
+ };
+
+`;
+ }
+
+ templ += `
+${(await Bun.file(import.meta.dir + "/bindings/JSSink+custom.h").text()).trim()}
+`;
+
+ const footer = `
+} // namespace WebCore
+
+`;
+
+ for (let name of classes) {
+ const {
+ className,
+ controller,
+ prototypeName,
+ controllerPrototypeName,
+ constructor,
+ controllerName,
+ } = names(name);
+ templ += `
+#pragma mark - ${name}
+
+class ${prototypeName} final : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+
+ static ${prototypeName}* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ ${prototypeName}* ptr = new (NotNull, JSC::allocateCell<${prototypeName}>(vm)) ${prototypeName}(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ ${prototypeName}(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(${prototypeName}, ${prototypeName}::Base);
+
+class ${controllerPrototypeName} final : public JSC::JSNonFinalObject {
+ public:
+ using Base = JSC::JSNonFinalObject;
+
+ static ${controllerPrototypeName}* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ ${controllerPrototypeName}* ptr = new (NotNull, JSC::allocateCell<${controllerPrototypeName}>(vm)) ${controllerPrototypeName}(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ private:
+ ${controllerPrototypeName}(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+ };
+ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(${controllerPrototypeName}, ${controllerPrototypeName}::Base);
+
+const ClassInfo ${prototypeName}::s_info = { "${name}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${prototypeName}) };
+const ClassInfo ${className}::s_info = { "${name}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${className}) };
+const ClassInfo ${constructor}::s_info = { "${name}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${constructor}) };
+
+
+const ClassInfo ${controllerPrototypeName}::s_info = { "${controllerName}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${controllerPrototypeName}) };
+const ClassInfo ${controller}::s_info = { "${controllerName}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${controller}) };
+
+${className}::~${className}()
+{
+ if (m_sinkPtr) {
+ ${name}__finalize(m_sinkPtr);
+ }
+}
+
+
+${controller}::~${controller}()
+{
+ if (m_sinkPtr) {
+ ${name}__finalize(m_sinkPtr);
+ }
+}
+
+
+`;
+
+ templ += `
+
+${constructor}* ${constructor}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSObject* prototype)
+{
+ ${constructor}* ptr = new (NotNull, JSC::allocateCell<${constructor}>(vm)) ${constructor}(vm, structure, ${name}__construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+${className}* ${className}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
+{
+ ${className}* ptr = new (NotNull, JSC::allocateCell<${className}>(vm)) ${className}(vm, structure, sinkPtr);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+${controller}* ${controller}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
+{
+ ${controller}* ptr = new (NotNull, JSC::allocateCell<${controller}>(vm)) ${controller}(vm, structure, sinkPtr);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+void ${constructor}::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSObject* prototype)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ initializeProperties(vm, globalObject, prototype);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES ${constructor}::construct(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) {
+ return ${name}__construct(globalObject, callFrame);
+}
+
+
+void ${constructor}::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSObject* prototype)
+{
+ putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ JSString* nameString = jsNontrivialString(vm, "${name}"_s);
+ m_originalName.set(vm, this, nameString);
+ putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+}
+
+void ${prototypeName}::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, ${className}::info(), ${className}PrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void ${controllerPrototypeName}::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, ${controller}::info(), ${controller}PrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void ${className}::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+void ${controller}::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+
+void ${className}::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<${className}*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ analyzer.setWrappedObjectForCell(cell, wrapped);
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+void ${controller}::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<${controller}*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ analyzer.setWrappedObjectForCell(cell, wrapped);
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+
+template<typename Visitor>
+void ${controller}::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ ${controller}* thisObject = jsCast<${controller}*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(thisObject->m_onPull);
+ visitor.append(thisObject->m_onClose);
+ visitor.append(thisObject->m_weakReadableStream);
+}
+
+DEFINE_VISIT_CHILDREN(${controller});
+
+
+void ${controller}::start(JSC::JSGlobalObject *globalObject, JSC::JSValue readableStream, JSC::JSFunction *onPull, JSC::JSFunction *onClose) {
+ this->m_weakReadableStream = JSC::Weak<JSC::JSObject>(readableStream.getObject());
+ this->m_onPull.set(globalObject->vm(), this, onPull);
+ this->m_onClose.set(globalObject->vm(), this, onClose);
+}
+
+void ${className}::destroy(JSCell* cell)
+{
+ static_cast<${className}*>(cell)->${className}::~${className}();
+}
+
+
+void ${controller}::destroy(JSCell* cell)
+{
+ static_cast<${controller}*>(cell)->${controller}::~${controller}();
+}
+
+
+`;
+ }
+
+ templ += `
+ JSObject* createJSSinkPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, SinkID sinkID)
+ {
+ switch (sinkID) {
+ `;
+ for (let name of classes) {
+ templ += `
+ case ${name}:
+ return JS${name}Prototype::create(vm, globalObject, JS${name}Prototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+`;
+ }
+ templ += `
+default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}`;
+
+ templ += `
+JSObject* createJSSinkControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, SinkID sinkID)
+{
+ switch (sinkID) {
+ `;
+ for (let name of classes) {
+ const { controllerPrototypeName } = names(name);
+ templ += `
+ case ${name}:
+ return ${controllerPrototypeName}::create(vm, globalObject, ${controllerPrototypeName}::createStructure(vm, globalObject, globalObject->objectPrototype()));
+`;
+ }
+ templ += `
+default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}`;
+
+ templ += footer;
+
+ for (let name of classes) {
+ const {
+ className,
+ controller,
+ prototypeName,
+ controllerPrototypeName,
+ constructor,
+ } = names(name);
+
+ templ += `
+extern "C" JSC__JSValue ${name}__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr)
+{
+ auto& vm = arg0->vm();
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
+ JSC::JSValue prototype = globalObject->${name}Prototype();
+ JSC::Structure* structure = WebCore::JS${name}::createStructure(vm, globalObject, prototype);
+ return JSC::JSValue::encode(WebCore::JS${name}::create(vm, globalObject, structure, sinkPtr));
+}
+
+extern "C" void* ${name}__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1)
+{
+ JSC::VM& vm = WebCore::getVM(arg0);
+ if (auto* sink = JSC::jsDynamicCast<WebCore::JS${name}*>(JSC::JSValue::decode(JSValue1)))
+ return sink->wrapped();
+
+ if (auto* controller = JSC::jsDynamicCast<WebCore::${controller}*>(JSC::JSValue::decode(JSValue1)))
+ return controller->wrapped();
+
+ return nullptr;
+}
+
+extern "C" JSC__JSValue ${name}__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue stream, void* sinkPtr, int32_t *bunNativeTag, void** bunNativePtr)
+{
+ auto& vm = arg0->vm();
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
+ auto clientData = WebCore::clientData(vm);
+ JSC::JSObject *readableStream = JSC::JSValue::decode(stream).getObject();
+
+ if (JSC::JSValue tag = readableStream->get(globalObject, clientData->builtinNames().bunNativeTypePrivateName())) {
+ if (tag.isInt32()) {
+ int32_t tagNumber = tag.toInt32(arg0);
+ if (tagNumber > 0 && tagNumber < 5) {
+ *bunNativeTag = tagNumber;
+ *bunNativePtr = reinterpret_cast<void*>(bitwise_cast<uintptr_t>(readableStream->get(globalObject, clientData->builtinNames().bunNativePtrPrivateName()).asNumber()));
+ return JSC::JSValue::encode(JSC::jsNull());
+ }
+ }
+ }
+
+ JSC::JSValue prototype = globalObject->${controllerPrototypeName}();
+ JSC::Structure* structure = WebCore::${controller}::createStructure(vm, globalObject, prototype);
+ WebCore::${controller} *controller = WebCore::${controller}::create(vm, globalObject, structure, sinkPtr);
+
+ JSC::JSObject *function = globalObject->getDirect(vm, clientData->builtinNames().assignDirectStreamPrivateName()).getObject();
+ auto callData = JSC::getCallData(function);
+ JSC::MarkedArgumentBuffer arguments;
+ arguments.append(JSC::JSValue::decode(stream));
+ arguments.append(controller);
+
+ auto result = JSC::call(arg0, function, callData, JSC::jsUndefined(), arguments);
+ return JSC::JSValue::encode(result);
+}
+
+
+
+`;
+ return templ;
+ }
+}
+
+await Bun.write(import.meta.dir + "/bindings/JSSink.h", header());
+await Bun.write(
+ import.meta.dir + "/bindings/JSSink.cpp",
+ await implementation()
+);