diff options
author | 2022-09-22 23:44:53 -0700 | |
---|---|---|
committer | 2022-09-22 23:45:02 -0700 | |
commit | 2c1926993bc4d94f9e7bc4d171217a707efd385c (patch) | |
tree | 827148c57920e40ad48c4c6d73ceec68a9b21c96 /src | |
parent | e14a3af491ece8d1b0309e76ae3022b4fad91f16 (diff) | |
download | bun-2c1926993bc4d94f9e7bc4d171217a707efd385c.tar.gz bun-2c1926993bc4d94f9e7bc4d171217a707efd385c.tar.zst bun-2c1926993bc4d94f9e7bc4d171217a707efd385c.zip |
Faster `Blob` + begin to implement `FileSink`
Diffstat (limited to 'src')
29 files changed, 2165 insertions, 279 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index e01868af6..8a75c3653 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -282,8 +282,8 @@ pub fn getStdin( blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr()); return ctx.ptr().putCachedObject( - &ZigString.init("BunSTDIN"), - JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)), + ZigString.static("BunSTDIN"), + blob.toJS(ctx), ).asObjectRef(); } @@ -305,8 +305,8 @@ pub fn getStderr( blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr()); return ctx.ptr().putCachedObject( - &ZigString.init("BunSTDERR"), - JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)), + ZigString.static("BunSTDERR"), + blob.toJS(ctx), ).asObjectRef(); } @@ -329,7 +329,7 @@ pub fn getStdout( return ctx.ptr().putCachedObject( &ZigString.init("BunSTDOUT"), - JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)), + blob.toJS(ctx), ).asObjectRef(); } diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 2410b5e7c..d7cfbe4c1 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -1933,7 +1933,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { } if (opts.fastGet(ctx.ptr(), .body)) |body__| { - if (Blob.fromJS(ctx.ptr(), body__, true, false)) |new_blob| { + if (Blob.get(ctx.ptr(), body__, true, false)) |new_blob| { body = .{ .Blob = new_blob }; } else |_| { return JSPromise.rejectedPromiseValue(globalThis, ZigString.init("fetch() received invalid body").toErrorInstance(globalThis)).asRef(); diff --git a/src/bun.js/bindings/JSSink.cpp b/src/bun.js/bindings/JSSink.cpp index fbb8b56fb..47bb2cac3 100644 --- a/src/bun.js/bindings/JSSink.cpp +++ b/src/bun.js/bindings/JSSink.cpp @@ -1,6 +1,6 @@ // AUTO-GENERATED FILE. DO NOT EDIT. -// Generated by 'make generate-sink' at 2022-08-27T22:18:48.797Z +// Generated by 'make generate-sink' at 2022-09-23T02:14:49.416Z // To regenerate this file, run: // // make generate-sink @@ -101,6 +101,16 @@ JSC_DEFINE_HOST_FUNCTION(functionStartDirectStream, (JSC::JSGlobalObject * lexic } + else if (WebCore::JSReadableFileSinkController* FileSinkController = JSC::jsDynamicCast<WebCore::JSReadableFileSinkController*>(callFrame->thisValue())) { + if (FileSinkController->wrapped() == nullptr) { + scope.throwException(globalObject, JSC::createTypeError(globalObject, "Cannot start stream with closed controller"_s)); + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + FileSinkController->start(globalObject, readableStream, onPullFunction, onCloseFunction); + } + + else if (WebCore::JSReadableHTTPResponseSinkController* HTTPResponseSinkController = JSC::jsDynamicCast<WebCore::JSReadableHTTPResponseSinkController*>(callFrame->thisValue())) { if (HTTPResponseSinkController->wrapped() == nullptr) { scope.throwException(globalObject, JSC::createTypeError(globalObject, "Cannot start stream with closed controller"_s)); @@ -210,6 +220,88 @@ JSC_DEFINE_HOST_FUNCTION(ArrayBufferSink__doClose, (JSC::JSGlobalObject * lexica +JSC_DEFINE_CUSTOM_GETTER(functionFileSink__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->FileSink()); +} + + +JSC_DECLARE_HOST_FUNCTION(JSReadableFileSinkController__close); +JSC_DEFINE_HOST_FUNCTION(JSReadableFileSinkController__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::JSReadableFileSinkController* controller = JSC::jsDynamicCast<WebCore::JSReadableFileSinkController*>(callFrame->thisValue()); + if (!controller) { + scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected JSReadableFileSinkController"_s)); + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + void *ptr = controller->wrapped(); + if (ptr == nullptr) { + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + controller->detach(); + FileSink__close(lexicalGlobalObject, ptr); + // Release the controller right before close. + controller->m_hasPendingActivity = false; + return JSC::JSValue::encode(JSC::jsUndefined()); +} + +JSC_DECLARE_HOST_FUNCTION(JSReadableFileSinkController__end); +JSC_DEFINE_HOST_FUNCTION(JSReadableFileSinkController__end, (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::JSReadableFileSinkController* controller = JSC::jsDynamicCast<WebCore::JSReadableFileSinkController*>(callFrame->thisValue()); + if (!controller) { + scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected JSReadableFileSinkController"_s)); + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + void *ptr = controller->wrapped(); + if (ptr == nullptr) { + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + controller->detach(); + return FileSink__endWithSink(ptr, lexicalGlobalObject); +} + + +JSC_DECLARE_HOST_FUNCTION(FileSink__doClose); +JSC_DEFINE_HOST_FUNCTION(FileSink__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::JSFileSink* sink = JSC::jsDynamicCast<WebCore::JSFileSink*>(callFrame->thisValue()); + if (!sink) { + scope.throwException(globalObject, JSC::createTypeError(globalObject, "Expected FileSink"_s)); + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + void *ptr = sink->wrapped(); + if (ptr == nullptr) { + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + sink->detach(); + FileSink__close(lexicalGlobalObject, ptr); + return JSC::JSValue::encode(JSC::jsUndefined()); +} + + + JSC_DEFINE_CUSTOM_GETTER(functionHTTPResponseSink__getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { auto& vm = lexicalGlobalObject->vm(); @@ -398,6 +490,28 @@ JSC_DEFINE_HOST_FUNCTION(HTTPSResponseSink__doClose, (JSC::JSGlobalObject * lexi */ +/* Source for JSFileSinkPrototypeTableValues.lut.h +@begin JSFileSinkPrototypeTable + close FileSink__doClose ReadOnly|DontDelete|Function 0 + flush FileSink__flush ReadOnly|DontDelete|Function 1 + end FileSink__end ReadOnly|DontDelete|Function 0 + start FileSink__start ReadOnly|DontDelete|Function 1 + write FileSink__write ReadOnly|DontDelete|Function 1 +@end +*/ + + +/* Source for JSReadableFileSinkControllerPrototypeTableValues.lut.h +@begin JSReadableFileSinkControllerPrototypeTable + close JSReadableFileSinkController__close ReadOnly|DontDelete|Function 0 + flush FileSink__flush ReadOnly|DontDelete|Function 1 + end JSReadableFileSinkController__end ReadOnly|DontDelete|Function 0 + start FileSink__start ReadOnly|DontDelete|Function 1 + write FileSink__write ReadOnly|DontDelete|Function 1 +@end +*/ + + /* Source for JSHTTPResponseSinkPrototypeTableValues.lut.h @begin JSHTTPResponseSinkPrototypeTable close HTTPResponseSink__doClose ReadOnly|DontDelete|Function 0 @@ -688,6 +802,252 @@ void JSReadableArrayBufferSinkController::destroy(JSCell* cell) +#pragma mark - FileSink + +class JSFileSinkPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSFileSinkPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + { + JSFileSinkPrototype* ptr = new (NotNull, JSC::allocateCell<JSFileSinkPrototype>(vm)) JSFileSinkPrototype(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: + JSFileSinkPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFileSinkPrototype, JSFileSinkPrototype::Base); + +class JSReadableFileSinkControllerPrototype final : public JSC::JSNonFinalObject { + public: + using Base = JSC::JSNonFinalObject; + + static JSReadableFileSinkControllerPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + { + JSReadableFileSinkControllerPrototype* ptr = new (NotNull, JSC::allocateCell<JSReadableFileSinkControllerPrototype>(vm)) JSReadableFileSinkControllerPrototype(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: + JSReadableFileSinkControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); + }; + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableFileSinkControllerPrototype, JSReadableFileSinkControllerPrototype::Base); + +const ClassInfo JSFileSinkPrototype::s_info = { "FileSink"_s, &Base::s_info, &JSFileSinkPrototypeTable, nullptr, CREATE_METHOD_TABLE(JSFileSinkPrototype) }; +const ClassInfo JSFileSink::s_info = { "FileSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFileSink) }; +const ClassInfo JSFileSinkConstructor::s_info = { "FileSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFileSinkConstructor) }; + + +const ClassInfo JSReadableFileSinkControllerPrototype::s_info = { "ReadableFileSinkController"_s, &Base::s_info, &JSReadableFileSinkControllerPrototypeTable, nullptr, CREATE_METHOD_TABLE(JSReadableFileSinkControllerPrototype) }; +const ClassInfo JSReadableFileSinkController::s_info = { "ReadableFileSinkController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableFileSinkController) }; + +JSFileSink::~JSFileSink() +{ + if (m_sinkPtr) { + FileSink__finalize(m_sinkPtr); + } +} + + +JSReadableFileSinkController::~JSReadableFileSinkController() +{ + if (m_sinkPtr) { + FileSink__finalize(m_sinkPtr); + } +} + +JSObject* JSFileSink::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) +{ + return JSFileSinkPrototype::create(vm, &globalObject, JSFileSinkPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype())); +} + +JSObject* JSReadableFileSinkController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) +{ + return JSReadableFileSinkControllerPrototype::create(vm, &globalObject, JSReadableFileSinkControllerPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype())); +} + +void JSReadableFileSinkController::detach() { + m_sinkPtr = nullptr; + m_onPull.clear(); + + auto readableStream = m_weakReadableStream.get(); + auto onClose = m_onClose.get(); + m_onClose.clear(); + + if (readableStream && onClose) { + JSC::JSGlobalObject *globalObject = this->globalObject(); + auto callData = JSC::getCallData(onClose); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + JSC::call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } + + m_weakReadableStream.clear(); +} + + +JSFileSinkConstructor* JSFileSinkConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSObject* prototype) +{ + JSFileSinkConstructor* ptr = new (NotNull, JSC::allocateCell<JSFileSinkConstructor>(vm)) JSFileSinkConstructor(vm, structure, FileSink__construct); + ptr->finishCreation(vm, globalObject, prototype); + return ptr; +} + +JSFileSink* JSFileSink::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr) +{ + JSFileSink* ptr = new (NotNull, JSC::allocateCell<JSFileSink>(vm)) JSFileSink(vm, structure, sinkPtr); + ptr->finishCreation(vm); + return ptr; +} + +JSReadableFileSinkController* JSReadableFileSinkController::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr) +{ + JSReadableFileSinkController* ptr = new (NotNull, JSC::allocateCell<JSReadableFileSinkController>(vm)) JSReadableFileSinkController(vm, structure, sinkPtr); + ptr->finishCreation(vm); + return ptr; +} + +void JSFileSinkConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSObject* prototype) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + initializeProperties(vm, globalObject, prototype); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSFileSinkConstructor::construct(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) { + return FileSink__construct(globalObject, callFrame); +} + + +void JSFileSinkConstructor::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, "FileSink"_s); + m_originalName.set(vm, this, nameString); + putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); +} + +void JSFileSinkPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSFileSink::info(), JSFileSinkPrototypeTableValues, *this); + putDirect(vm, JSC::Identifier::fromString(vm, "sinkId"_s), JSC::jsNumber(JSFileSink::Sink), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +void JSReadableFileSinkControllerPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSReadableFileSinkController::info(), JSReadableFileSinkControllerPrototypeTableValues, *this); + putDirect(vm, JSC::Identifier::fromString(vm, "sinkId"_s), JSC::jsNumber(JSFileSink::Sink), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +void JSFileSink::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +void JSReadableFileSinkController::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + + +void JSFileSink::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) +{ + auto* thisObject = jsCast<JSFileSink*>(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 JSReadableFileSinkController::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) +{ + auto* thisObject = jsCast<JSReadableFileSinkController*>(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 JSReadableFileSinkController::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSReadableFileSinkController* thisObject = jsCast<JSReadableFileSinkController*>(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(JSReadableFileSinkController); + + +void JSReadableFileSinkController::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 JSFileSink::destroy(JSCell* cell) +{ + static_cast<JSFileSink*>(cell)->JSFileSink::~JSFileSink(); +} + + +void JSReadableFileSinkController::destroy(JSCell* cell) +{ + static_cast<JSReadableFileSinkController*>(cell)->JSReadableFileSinkController::~JSReadableFileSinkController(); +} + + + #pragma mark - HTTPResponseSink class JSHTTPResponseSinkPrototype final : public JSC::JSNonFinalObject { @@ -1187,6 +1547,9 @@ void JSReadableHTTPSResponseSinkController::destroy(JSCell* cell) case ArrayBufferSink: return JSArrayBufferSinkPrototype::create(vm, globalObject, JSArrayBufferSinkPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); + case FileSink: + return JSFileSinkPrototype::create(vm, globalObject, JSFileSinkPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); + case HTTPResponseSink: return JSHTTPResponseSinkPrototype::create(vm, globalObject, JSHTTPResponseSinkPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); @@ -1204,6 +1567,9 @@ JSObject* createJSSinkControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject* glob case ArrayBufferSink: return JSReadableArrayBufferSinkControllerPrototype::create(vm, globalObject, JSReadableArrayBufferSinkControllerPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); + case FileSink: + return JSReadableFileSinkControllerPrototype::create(vm, globalObject, JSReadableFileSinkControllerPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); + case HTTPResponseSink: return JSReadableHTTPResponseSinkControllerPrototype::create(vm, globalObject, JSReadableHTTPResponseSinkControllerPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); @@ -1223,6 +1589,11 @@ Structure* createJSSinkControllerStructure(JSC::VM& vm, JSC::JSGlobalObject* glo return JSReadableArrayBufferSinkController::createStructure(vm, globalObject, prototype); } + case FileSink: { + auto* prototype = createJSSinkControllerPrototype(vm, globalObject, sinkID); + return JSReadableFileSinkController::createStructure(vm, globalObject, prototype); + } + case HTTPResponseSink: { auto* prototype = createJSSinkControllerPrototype(vm, globalObject, sinkID); return JSReadableHTTPResponseSinkController::createStructure(vm, globalObject, prototype); @@ -1330,6 +1701,96 @@ extern "C" void ArrayBufferSink__onClose(JSC__JSValue controllerValue, JSC__JSVa } +extern "C" JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr) +{ + auto& vm = arg0->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0); + JSC::JSValue prototype = globalObject->FileSinkPrototype(); + JSC::Structure* structure = WebCore::JSFileSink::createStructure(vm, globalObject, prototype); + return JSC::JSValue::encode(WebCore::JSFileSink::create(vm, globalObject, structure, sinkPtr)); +} + +extern "C" void* FileSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1) +{ + JSC::VM& vm = WebCore::getVM(arg0); + if (auto* sink = JSC::jsDynamicCast<WebCore::JSFileSink*>(JSC::JSValue::decode(JSValue1))) + return sink->wrapped(); + + if (auto* controller = JSC::jsDynamicCast<WebCore::JSReadableFileSinkController*>(JSC::JSValue::decode(JSValue1))) + return controller->wrapped(); + + return nullptr; +} + +extern "C" void FileSink__detachPtr(JSC__JSValue JSValue0) +{ + if (auto* sink = JSC::jsDynamicCast<WebCore::JSFileSink*>(JSC::JSValue::decode(JSValue0))) { + sink->detach(); + return; + } + + + if (auto* controller = JSC::jsDynamicCast<WebCore::JSReadableFileSinkController*>(JSC::JSValue::decode(JSValue0))) { + controller->detach(); + return; + } +} + +extern "C" JSC__JSValue FileSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue stream, void* sinkPtr, void **controllerValue) +{ + auto& vm = arg0->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0); + + JSC::Structure* structure = WebCore::getDOMStructure<WebCore::JSReadableFileSinkController>(vm, *globalObject); + WebCore::JSReadableFileSinkController *controller = WebCore::JSReadableFileSinkController::create(vm, globalObject, structure, sinkPtr); + *controllerValue = reinterpret_cast<void*>(JSC::JSValue::encode(controller)); + return globalObject->assignToStream(JSC::JSValue::decode(stream), controller); +} + +extern "C" void FileSink__onReady(JSC__JSValue controllerValue, JSC__JSValue amt, JSC__JSValue offset) +{ + WebCore::JSReadableFileSinkController* controller = JSC::jsCast<WebCore::JSReadableFileSinkController*>(JSC::JSValue::decode(controllerValue).getObject()); + + JSC::JSFunction *function = controller->m_onPull.get(); + if (function == nullptr) + return; + JSC::JSGlobalObject *globalObject = controller->globalObject(); + + auto callData = JSC::getCallData(function); + JSC::MarkedArgumentBuffer arguments; + arguments.append(controller); + arguments.append(JSC::JSValue::decode(amt)); + arguments.append(JSC::JSValue::decode(offset)); + + JSC::call(globalObject, function, callData, JSC::jsUndefined(), arguments); +} + +extern "C" void FileSink__onStart(JSC__JSValue controllerValue) +{ + +} + +extern "C" void FileSink__onClose(JSC__JSValue controllerValue, JSC__JSValue reason) +{ + WebCore::JSReadableFileSinkController* controller = JSC::jsCast<WebCore::JSReadableFileSinkController*>(JSC::JSValue::decode(controllerValue).getObject()); + + JSC::JSFunction *function = controller->m_onClose.get(); + if (function == nullptr) + return; + // only call close once + controller->m_onClose.clear(); + JSC::JSGlobalObject *globalObject = controller->globalObject(); + + auto callData = JSC::getCallData(function); + JSC::MarkedArgumentBuffer arguments; + auto readableStream = controller->m_weakReadableStream.get(); + arguments.append(readableStream ? readableStream : JSC::jsUndefined()); + + arguments.append(JSC::JSValue::decode(reason)); + JSC::call(globalObject, function, callData, JSC::jsUndefined(), arguments); +} + + extern "C" JSC__JSValue HTTPResponseSink__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr) { auto& vm = arg0->vm(); diff --git a/src/bun.js/bindings/JSSink.h b/src/bun.js/bindings/JSSink.h index 0cf046ffa..e55545302 100644 --- a/src/bun.js/bindings/JSSink.h +++ b/src/bun.js/bindings/JSSink.h @@ -1,6 +1,6 @@ // AUTO-GENERATED FILE. DO NOT EDIT. -// Generated by 'make generate-sink' at 2022-08-27T22:18:48.793Z +// Generated by 'make generate-sink' at 2022-09-23T02:14:49.415Z // #pragma once @@ -108,6 +108,8 @@ class JSArrayBufferSinkConstructor final : public JSC::InternalFunction { void finishCreation(JSC::VM&); }; + + class JSReadableArrayBufferSinkController final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; @@ -184,6 +186,175 @@ class JSArrayBufferSinkConstructor final : public JSC::InternalFunction { JSC_DECLARE_CUSTOM_GETTER(functionArrayBufferSink__getter); +class JSFileSinkConstructor final : public JSC::InternalFunction { + public: + using Base = JSC::InternalFunction; + static JSFileSinkConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype); + static constexpr SinkID Sink = SinkID::FileSink; + + 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<JSFileSinkConstructor, 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: + JSFileSinkConstructor(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 JSFileSink final : public JSC::JSDestructibleObject { + public: + using Base = JSC::JSDestructibleObject; + static JSFileSink* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr); + static constexpr SinkID Sink = SinkID::FileSink; + + 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<JSFileSink, 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()); + } + + static JSObject* createPrototype(VM& vm, JSDOMGlobalObject& globalObject); + + ~JSFileSink(); + + void* wrapped() const { return m_sinkPtr; } + + void detach() { + m_sinkPtr = nullptr; + + } + + static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + + void* m_sinkPtr; + + JSFileSink(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + : Base(vm, structure) + { + m_sinkPtr = sinkPtr; + } + + void finishCreation(JSC::VM&); + }; + + + + class JSReadableFileSinkController final : public JSC::JSDestructibleObject { + public: + using Base = JSC::JSDestructibleObject; + static JSReadableFileSinkController* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr); + static constexpr SinkID Sink = SinkID::FileSink; + + 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<JSReadableFileSinkController, 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()); + } + static JSObject* createPrototype(VM& vm, JSDOMGlobalObject& globalObject); + + ~JSReadableFileSinkController(); + + + void* wrapped() const { return m_sinkPtr; } + void detach(); + + void start(JSC::JSGlobalObject *globalObject, JSC::JSValue readableStream, JSC::JSFunction *onPull, JSC::JSFunction *onClose); + DECLARE_VISIT_CHILDREN; + + static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + + bool hasPendingActivity() { return m_hasPendingActivity; } + + void* m_sinkPtr; + bool m_hasPendingActivity; + mutable WriteBarrier<JSC::JSFunction> m_onPull; + mutable WriteBarrier<JSC::JSFunction> m_onClose; + mutable JSC::Weak<JSObject> m_weakReadableStream; + JSC::Weak<JSReadableFileSinkController> m_weakThis; + + JSReadableFileSinkController(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + : Base(vm, structure) + { + m_sinkPtr = sinkPtr; + m_hasPendingActivity = true; + m_weakThis = JSC::Weak<JSReadableFileSinkController>(this, getOwner()); + } + + void finishCreation(JSC::VM&); + + class Owner final : public JSC::WeakHandleOwner { + public: + bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, JSC::AbstractSlotVisitor&, const char**) final + { + auto* controller = JSC::jsCast<JSReadableFileSinkController*>(handle.slot()->asCell()); + return controller->hasPendingActivity(); + } + void finalize(JSC::Handle<JSC::Unknown>, void* context) final {} + }; + + static JSC::WeakHandleOwner* getOwner() + { + static NeverDestroyed<Owner> m_owner; + return &m_owner.get(); + } + }; + +JSC_DECLARE_CUSTOM_GETTER(functionFileSink__getter); + + class JSHTTPResponseSinkConstructor final : public JSC::InternalFunction { public: using Base = JSC::InternalFunction; @@ -275,6 +446,8 @@ class JSHTTPResponseSinkConstructor final : public JSC::InternalFunction { void finishCreation(JSC::VM&); }; + + class JSReadableHTTPResponseSinkController final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; @@ -442,6 +615,8 @@ class JSHTTPSResponseSinkConstructor final : public JSC::InternalFunction { void finishCreation(JSC::VM&); }; + + class JSReadableHTTPSResponseSinkController final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; diff --git a/src/bun.js/bindings/JSSinkLookupTable.h b/src/bun.js/bindings/JSSinkLookupTable.h index 8d0f8cde5..14d547708 100644 --- a/src/bun.js/bindings/JSSinkLookupTable.h +++ b/src/bun.js/bindings/JSSinkLookupTable.h @@ -82,6 +82,84 @@ static const struct HashTable JSReadableArrayBufferSinkControllerPrototypeTable +static const struct CompactHashIndex JSFileSinkPrototypeTableIndex[19] = { + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 0, 16 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 4, -1 }, + { 1, 17 }, + { 2, 18 }, + { 3, -1 }, +}; + +static const struct HashTableValue JSFileSinkPrototypeTableValues[5] = { + { "close"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__doClose, 0 } }, + { "flush"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__flush, 1 } }, + { "end"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__end, 0 } }, + { "start"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__start, 1 } }, + { "write"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__write, 1 } }, +}; + +static const struct HashTable JSFileSinkPrototypeTable = + { 5, 15, false, nullptr, JSFileSinkPrototypeTableValues, JSFileSinkPrototypeTableIndex }; + + + + + + + +static const struct CompactHashIndex JSReadableFileSinkControllerPrototypeTableIndex[19] = { + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 0, 16 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 4, -1 }, + { 1, 17 }, + { 2, 18 }, + { 3, -1 }, +}; + +static const struct HashTableValue JSReadableFileSinkControllerPrototypeTableValues[5] = { + { "close"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, JSReadableFileSinkController__close, 0 } }, + { "flush"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__flush, 1 } }, + { "end"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, JSReadableFileSinkController__end, 0 } }, + { "start"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__start, 1 } }, + { "write"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::DontDelete|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, FileSink__write, 1 } }, +}; + +static const struct HashTable JSReadableFileSinkControllerPrototypeTable = + { 5, 15, false, nullptr, JSReadableFileSinkControllerPrototypeTableValues, JSReadableFileSinkControllerPrototypeTableIndex }; + + + + + + + static const struct CompactHashIndex JSHTTPResponseSinkPrototypeTableIndex[19] = { { -1, -1 }, { -1, -1 }, diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h index 03282a16a..b4d389d46 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h @@ -9,4 +9,5 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256Constructor;std: std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoder; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoderConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequest; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequestConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForResponse; -std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForResponseConstructor;
\ No newline at end of file +std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForResponseConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBlob; +std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBlobConstructor;
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h index 0cbf0776c..b23b98853 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h @@ -9,4 +9,5 @@ std::unique_ptr<IsoSubspace> m_subspaceForSHA256Constructor;std::unique_ptr<IsoS std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForTextDecoder; std::unique_ptr<IsoSubspace> m_subspaceForTextDecoderConstructor;std::unique_ptr<IsoSubspace> m_subspaceForRequest; std::unique_ptr<IsoSubspace> m_subspaceForRequestConstructor;std::unique_ptr<IsoSubspace> m_subspaceForResponse; -std::unique_ptr<IsoSubspace> m_subspaceForResponseConstructor;
\ No newline at end of file +std::unique_ptr<IsoSubspace> m_subspaceForResponseConstructor;std::unique_ptr<IsoSubspace> m_subspaceForBlob; +std::unique_ptr<IsoSubspace> m_subspaceForBlobConstructor;
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h index c7b1fa75a..31100e3a4 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h @@ -63,4 +63,10 @@ JSC::Structure* JSResponseStructure() { return m_JSResponse.getInitializedOnMain JSC::JSValue JSResponsePrototype() { return m_JSResponse.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSResponse; bool hasJSResponseSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSResponseSetterValue;
\ No newline at end of file + mutable JSC::WriteBarrier<JSC::Unknown> m_JSResponseSetterValue; +JSC::Structure* JSBlobStructure() { return m_JSBlob.getInitializedOnMainThread(this); } + JSC::JSObject* JSBlobConstructor() { return m_JSBlob.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBlobPrototype() { return m_JSBlob.prototypeInitializedOnMainThread(this); } + JSC::LazyClassStructure m_JSBlob; + bool hasJSBlobSetterValue { false }; + mutable JSC::WriteBarrier<JSC::Unknown> m_JSBlobSetterValue;
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h index 695424897..d5d28ec81 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h @@ -65,6 +65,12 @@ void GlobalObject::initGeneratedLazyClasses() { init.setStructure(WebCore::JSResponse::createStructure(init.vm, init.global, init.prototype)); init.setConstructor(WebCore::JSResponseConstructor::create(init.vm, init.global, WebCore::JSResponseConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSResponsePrototype*>(init.prototype))); }); + m_JSBlob.initLater( + [](LazyClassStructure::Initializer& init) { + init.setPrototype(WebCore::JSBlob::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); + init.setStructure(WebCore::JSBlob::createStructure(init.vm, init.global, init.prototype)); + init.setConstructor(WebCore::JSBlobConstructor::create(init.vm, init.global, WebCore::JSBlobConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSBlobPrototype*>(init.prototype))); + }); } template<typename Visitor> void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& visitor) @@ -80,4 +86,5 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& thisObject->m_JSTextDecoder.visit(visitor); visitor.append(thisObject->m_JSTextDecoderSetterValue); thisObject->m_JSRequest.visit(visitor); visitor.append(thisObject->m_JSRequestSetterValue); thisObject->m_JSResponse.visit(visitor); visitor.append(thisObject->m_JSResponseSetterValue); + thisObject->m_JSBlob.visit(visitor); visitor.append(thisObject->m_JSBlobSetterValue); }
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 12db35785..90c628c01 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -192,9 +192,9 @@ void JSSHA1Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* global const ClassInfo JSSHA1Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA1Constructor) }; -extern "C" EncodedJSValue SHA1__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA1Constructor()); -} + extern "C" EncodedJSValue SHA1__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA1Constructor()); + } JSSHA1::~JSSHA1() { @@ -424,9 +424,9 @@ void JSMD5Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalO const ClassInfo JSMD5Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMD5Constructor) }; -extern "C" EncodedJSValue MD5__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSMD5Constructor()); -} + extern "C" EncodedJSValue MD5__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSMD5Constructor()); + } JSMD5::~JSMD5() { @@ -656,9 +656,9 @@ void JSMD4Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalO const ClassInfo JSMD4Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMD4Constructor) }; -extern "C" EncodedJSValue MD4__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSMD4Constructor()); -} + extern "C" EncodedJSValue MD4__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSMD4Constructor()); + } JSMD4::~JSMD4() { @@ -888,9 +888,9 @@ void JSSHA224Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* glob const ClassInfo JSSHA224Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA224Constructor) }; -extern "C" EncodedJSValue SHA224__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA224Constructor()); -} + extern "C" EncodedJSValue SHA224__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA224Constructor()); + } JSSHA224::~JSSHA224() { @@ -1120,9 +1120,9 @@ void JSSHA512Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* glob const ClassInfo JSSHA512Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA512Constructor) }; -extern "C" EncodedJSValue SHA512__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA512Constructor()); -} + extern "C" EncodedJSValue SHA512__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA512Constructor()); + } JSSHA512::~JSSHA512() { @@ -1352,9 +1352,9 @@ void JSSHA384Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* glob const ClassInfo JSSHA384Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA384Constructor) }; -extern "C" EncodedJSValue SHA384__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA384Constructor()); -} + extern "C" EncodedJSValue SHA384__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA384Constructor()); + } JSSHA384::~JSSHA384() { @@ -1584,9 +1584,9 @@ void JSSHA256Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* glob const ClassInfo JSSHA256Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA256Constructor) }; -extern "C" EncodedJSValue SHA256__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA256Constructor()); -} + extern "C" EncodedJSValue SHA256__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA256Constructor()); + } JSSHA256::~JSSHA256() { @@ -1816,9 +1816,9 @@ void JSSHA512_256Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* const ClassInfo JSSHA512_256Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA512_256Constructor) }; -extern "C" EncodedJSValue SHA512_256__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSSHA512_256Constructor()); -} + extern "C" EncodedJSValue SHA512_256__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSSHA512_256Constructor()); + } JSSHA512_256::~JSSHA512_256() { @@ -2042,9 +2042,9 @@ void JSTextDecoderConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* const ClassInfo JSTextDecoderConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTextDecoderConstructor) }; -extern "C" EncodedJSValue TextDecoder__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSTextDecoderConstructor()); -} + extern "C" EncodedJSValue TextDecoder__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSTextDecoderConstructor()); + } JSTextDecoder::~JSTextDecoder() { @@ -2554,9 +2554,9 @@ void JSRequestConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* glo const ClassInfo JSRequestConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequestConstructor) }; -extern "C" EncodedJSValue Request__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSRequestConstructor()); -} + extern "C" EncodedJSValue Request__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSRequestConstructor()); + } JSRequest::~JSRequest() { @@ -2995,9 +2995,9 @@ void JSResponseConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* gl const ClassInfo JSResponseConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSResponseConstructor) }; -extern "C" EncodedJSValue Response__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSResponseConstructor()); -} + extern "C" EncodedJSValue Response__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSResponseConstructor()); + } JSResponse::~JSResponse() { @@ -3071,7 +3071,352 @@ void JSResponse::visitChildrenImpl(JSCell* cell, Visitor& visitor) visitor.append(thisObject->m_url); } -DEFINE_VISIT_CHILDREN(JSResponse); +DEFINE_VISIT_CHILDREN(JSResponse);extern "C" void* BlobClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*); +JSC_DECLARE_CUSTOM_GETTER(jsBlobConstructor); +extern "C" void BlobClass__finalize(void*); + +extern "C" EncodedJSValue BlobPrototype__getArrayBuffer(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__arrayBufferCallback); + + +extern "C" EncodedJSValue BlobPrototype__getJSON(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__jsonCallback); + + +extern "C" JSC::EncodedJSValue BlobPrototype__getSize(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(BlobPrototype__sizeGetterWrap); + + +extern "C" EncodedJSValue BlobPrototype__getSlice(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__sliceCallback); + + +extern "C" EncodedJSValue BlobPrototype__getStream(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__streamCallback); + + +extern "C" EncodedJSValue BlobPrototype__getText(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__textCallback); + + +extern "C" JSC::EncodedJSValue BlobPrototype__getType(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(BlobPrototype__typeGetterWrap); + + +extern "C" bool BlobPrototype__setType(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value); +JSC_DECLARE_CUSTOM_SETTER(BlobPrototype__typeSetterWrap); + + +extern "C" EncodedJSValue BlobPrototype__getWriter(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__writerCallback); + + +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBlobPrototype, JSBlobPrototype::Base); + + + static const HashTableValue JSBlobPrototypeTableValues[] = { +{ "arrayBuffer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__arrayBufferCallback, 0 } } , +{ "json"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__jsonCallback, 0 } } , +{ "size"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, BlobPrototype__sizeGetterWrap, 0 } } , +{ "slice"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__sliceCallback, 2 } } , +{ "stream"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__streamCallback, 1 } } , +{ "text"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__textCallback, 0 } } , +{ "type"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, BlobPrototype__typeGetterWrap, BlobPrototype__typeSetterWrap } } , +{ "writer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__writerCallback, 1 } } + }; + + +const ClassInfo JSBlobPrototype::s_info = { "Blob"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBlobPrototype) }; + + + +JSC_DEFINE_CUSTOM_GETTER(jsBlobConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto* prototype = jsDynamicCast<JSBlobPrototype*>(JSValue::decode(thisValue)); + + if (UNLIKELY(!prototype)) + return throwVMTypeError(lexicalGlobalObject, throwScope); + return JSValue::encode(globalObject->JSBlobConstructor()); +} + + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__arrayBufferCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getArrayBuffer(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__jsonCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getJSON(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +JSC_DEFINE_CUSTOM_GETTER(BlobPrototype__sizeGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSBlob* thisObject = jsCast<JSBlob*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + JSC::EncodedJSValue result = BlobPrototype__getSize(thisObject->wrapped(), globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, result); +} + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__sliceCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getSlice(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__streamCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getStream(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__textCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getText(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +JSC_DEFINE_CUSTOM_GETTER(BlobPrototype__typeGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSBlob* thisObject = jsCast<JSBlob*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + JSC::EncodedJSValue result = BlobPrototype__getType(thisObject->wrapped(), globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, result); +} + + +JSC_DEFINE_CUSTOM_SETTER(BlobPrototype__typeSetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSBlob* thisObject = jsCast<JSBlob*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + auto result = BlobPrototype__setType(thisObject->wrapped(), lexicalGlobalObject, encodedValue); + + RELEASE_AND_RETURN(throwScope, result); +} + + +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__writerCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return BlobPrototype__getWriter(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + + +void JSBlobPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSBlob::info(), JSBlobPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +void JSBlobConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSBlobPrototype* prototype) +{ + Base::finishCreation(vm, 0, "Blob"_s, PropertyAdditionMode::WithoutStructureTransition); + + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + ASSERT(inherits(info())); +} + +JSBlobConstructor* JSBlobConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSBlobPrototype* prototype) { + JSBlobConstructor* ptr = new (NotNull, JSC::allocateCell<JSBlobConstructor>(vm)) JSBlobConstructor(vm, structure, construct); + ptr->finishCreation(vm, globalObject, prototype); + return ptr; +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSBlobConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + JSC::VM &vm = globalObject->vm(); + JSObject* newTarget = asObject(callFrame->newTarget()); + auto* constructor = globalObject->JSBlobConstructor(); + Structure* structure = globalObject->JSBlobStructure(); + if (constructor != newTarget) { + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>( + // ShadowRealm functions belong to a different global object. + getFunctionRealm(globalObject, newTarget) + ); + RETURN_IF_EXCEPTION(scope, {}); + structure = InternalFunction::createSubclassStructure( + globalObject, + newTarget, + functionGlobalObject->JSBlobStructure() + ); + } + + void* ptr = BlobClass__construct(globalObject, callFrame); + + if (UNLIKELY(!ptr)) { + return JSValue::encode(JSC::jsUndefined()); + } + + JSBlob* instance = JSBlob::create(vm, globalObject, structure, ptr); + + return JSValue::encode(instance); +} + +extern "C" EncodedJSValue Blob__create(Zig::GlobalObject* globalObject, void* ptr) { + auto &vm = globalObject->vm(); + JSC::Structure* structure = globalObject->JSBlobStructure(); + JSBlob* instance = JSBlob::create(vm, globalObject, structure, ptr); + return JSValue::encode(instance); +} + +void JSBlobConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSBlobPrototype* prototype) +{ + +} + +const ClassInfo JSBlobConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBlobConstructor) }; + + + extern "C" EncodedJSValue Blob__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->JSBlobConstructor()); + } + +JSBlob::~JSBlob() +{ + if (m_ctx) { + BlobClass__finalize(m_ctx); + } +} +void JSBlob::destroy(JSCell* cell) +{ + static_cast<JSBlob*>(cell)->JSBlob::~JSBlob(); +} + +const ClassInfo JSBlob::s_info = { "Blob"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBlob) }; + +void JSBlob::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +JSBlob* JSBlob::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) { + JSBlob* ptr = new (NotNull, JSC::allocateCell<JSBlob>(vm)) JSBlob(vm, structure, ctx); + ptr->finishCreation(vm); + return ptr; +} + + +extern "C" void* Blob__fromJS(JSC::EncodedJSValue value) { + JSBlob* object = JSC::jsDynamicCast<JSBlob*>(JSValue::decode(value)); + if (!object) + return nullptr; + + return object->wrapped(); +} + +extern "C" bool Blob__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) { + JSBlob* object = JSC::jsDynamicCast<JSBlob*>(JSValue::decode(value)); + if (!object) + return false; + + object->m_ctx = ptr; + return true; +} + + +extern "C" const size_t Blob__ptrOffset = JSBlob::offsetOfWrapped(); + +void JSBlob::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) +{ + auto* thisObject = jsCast<JSBlob*>(cell); + if (void* wrapped = thisObject->wrapped()) { + // if (thisObject->scriptExecutionContext()) + // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string()); + } + Base::analyzeHeap(cell, analyzer); +} + +JSObject* JSBlob::createPrototype(VM& vm, JSDOMGlobalObject* globalObject) +{ + return JSBlobPrototype::create(vm, globalObject, JSBlobPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); +} } // namespace WebCore diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index bc0a2ec6f..e315093c7 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -1382,6 +1382,130 @@ class JSResponsePrototype final : public JSC::JSNonFinalObject { void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSResponsePrototype* prototype); }; +class JSBlob final : public JSC::JSDestructibleObject { + public: + using Base = JSC::JSDestructibleObject; + static JSBlob* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx); + + 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<JSBlob, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForBlob.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBlob = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForBlob.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForBlob = 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(static_cast<JSC::JSType>(0b11101110), StructureFlags), info()); + } + + static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject); + + ~JSBlob(); + + void* wrapped() const { return m_ctx; } + + void detach() + { + m_ctx = nullptr; + } + + static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSBlob, m_ctx); } + + void* m_ctx { nullptr }; + + + JSBlob(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + : Base(vm, structure) + { + m_ctx = sinkPtr; + } + + void finishCreation(JSC::VM&); + + + + + }; +class JSBlobPrototype final : public JSC::JSNonFinalObject { + public: + using Base = JSC::JSNonFinalObject; + + static JSBlobPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + { + JSBlobPrototype* ptr = new (NotNull, JSC::allocateCell<JSBlobPrototype>(vm)) JSBlobPrototype(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: + JSBlobPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); + }; + + class JSBlobConstructor final : public JSC::InternalFunction { + public: + using Base = JSC::InternalFunction; + static JSBlobConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSBlobPrototype* prototype); + + static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr bool needsDestruction = false; + + 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()); + } + + template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl<JSBlobConstructor, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForBlobConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBlobConstructor = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForBlobConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForBlobConstructor = WTFMove(space); }); + } + + + void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSBlobPrototype* prototype); + + // Must be defined for each specialization class. + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); + DECLARE_EXPORT_INFO; + private: + JSBlobConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction) + : Base(vm, structure, nativeFunction, nativeFunction) + + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSBlobPrototype* prototype); + }; } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 706d38135..33828f7ee 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -532,6 +532,9 @@ GENERATED_CONSTRUCTOR_SETTER(JSResponse); GENERATED_CONSTRUCTOR_GETTER(JSRequest); GENERATED_CONSTRUCTOR_SETTER(JSRequest); +GENERATED_CONSTRUCTOR_GETTER(JSBlob); +GENERATED_CONSTRUCTOR_SETTER(JSBlob); + WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessageEvent); WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessageEvent); @@ -1917,6 +1920,12 @@ void GlobalObject::finishCreation(VM& vm) init.set(prototype); }); + m_JSFileSinkControllerPrototype.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { + auto* prototype = createJSSinkControllerPrototype(init.vm, init.owner, WebCore::SinkID::FileSink); + init.set(prototype); + }); + m_JSHTTPResponseController.initLater( [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) { auto* structure = createJSSinkControllerStructure(init.vm, init.owner, WebCore::SinkID::HTTPResponseSink); @@ -1980,6 +1989,16 @@ void GlobalObject::finishCreation(VM& vm) init.set(object); }); + m_JSFileSinkClassStructure.initLater( + [](LazyClassStructure::Initializer& init) { + auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::FileSink); + auto* structure = JSFileSink::createStructure(init.vm, init.global, prototype); + auto* constructor = JSFileSinkConstructor::create(init.vm, init.global, JSFileSinkConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<JSObject*>(prototype)); + init.setPrototype(prototype); + init.setStructure(structure); + init.setConstructor(constructor); + }); + m_JSArrayBufferSinkClassStructure.initLater( [](LazyClassStructure::Initializer& init) { auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::ArrayBufferSink); @@ -2288,6 +2307,9 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "TextDecoder"_s), JSC::CustomGetterSetter::create(vm, JSTextDecoder_getter, JSTextDecoder_setter), JSC::PropertyAttribute::DontDelete | 0); + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Blob"_s), JSC::CustomGetterSetter::create(vm, JSBlob_getter, JSBlob_setter), + JSC::PropertyAttribute::DontDelete | 0); + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "DOMException"_s), JSC::CustomGetterSetter::create(vm, JSDOMException_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); @@ -2317,7 +2339,6 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessageEvent"_s, JSMessageEvent); PUT_WEBCORE_GENERATED_CONSTRUCTOR("WebSocket"_s, JSWebSocket); PUT_WEBCORE_GENERATED_CONSTRUCTOR("Headers"_s, JSFetchHeaders); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("TextEncoder"_s, JSTextEncoder); PUT_WEBCORE_GENERATED_CONSTRUCTOR("URLSearchParams"_s, JSURLSearchParams); putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().TransformStreamPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); @@ -2582,6 +2603,10 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_performanceObject.visit(visitor); thisObject->m_navigatorObject.visit(visitor); + thisObject->m_JSHTTPResponseSinkClassStructure.visit(visitor); + thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor); + thisObject->m_JSFileSinkClassStructure.visit(visitor); + visitor.append(thisObject->m_JSBufferSetterValue); visitor.append(thisObject->m_JSTextEncoderSetterValue); visitor.append(thisObject->m_JSMessageEventSetterValue); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 17aee4645..37c9c492c 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -177,6 +177,11 @@ public: JSC::Structure* FFIFunctionStructure() { return m_JSFFIFunctionStructure.getInitializedOnMainThread(this); } JSC::Structure* NapiClassStructure() { return m_NapiClassStructure.getInitializedOnMainThread(this); } + JSC::Structure* FileSinkStructure() { return m_JSFileSinkClassStructure.getInitializedOnMainThread(this); } + JSC::JSObject* FileSink() { return m_JSFileSinkClassStructure.constructorInitializedOnMainThread(this); } + JSC::JSValue FileSinkPrototype() { return m_JSFileSinkClassStructure.prototypeInitializedOnMainThread(this); } + JSC::JSValue JSReadableFileSinkControllerPrototype() { return m_JSFileSinkControllerPrototype.getInitializedOnMainThread(this); } + JSC::Structure* ArrayBufferSinkStructure() { return m_JSArrayBufferSinkClassStructure.getInitializedOnMainThread(this); } JSC::JSObject* ArrayBufferSink() { return m_JSArrayBufferSinkClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue ArrayBufferSinkPrototype() { return m_JSArrayBufferSinkClassStructure.prototypeInitializedOnMainThread(this); } @@ -380,6 +385,7 @@ private: LazyClassStructure m_JSArrayBufferSinkClassStructure; LazyClassStructure m_JSHTTPResponseSinkClassStructure; LazyClassStructure m_JSHTTPSResponseSinkClassStructure; + LazyClassStructure m_JSFileSinkClassStructure; LazyClassStructure m_JSBufferListClassStructure; LazyClassStructure m_JSStringDecoderClassStructure; LazyClassStructure m_JSReadableStateClassStructure; @@ -388,7 +394,10 @@ private: LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype; + LazyProperty<JSGlobalObject, JSObject> m_JSFileSinkControllerPrototype; + LazyProperty<JSGlobalObject, Structure> m_JSHTTPResponseController; + LazyProperty<JSGlobalObject, JSObject> m_processObject; LazyProperty<JSGlobalObject, JSObject> m_processEnvObject; LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap; diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index cf16a0934..45f95a617 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -140,6 +140,10 @@ pub const ZigString = extern struct { else try strings.allocateLatin1IntoUTF8WithList(list, 0, []const u8, this.slice()); + if (list.capacity > list.items.len) { + list.items.ptr[list.items.len] = 0; + } + return list.items; } @@ -221,6 +225,24 @@ pub const ZigString = extern struct { return std.meta.assumeSentinel(this.ptr[0..this.len], 0); } + pub fn toSliceZ(this: Slice, buf: []u8) [:0]const u8 { + if (this.len == 0) { + return ""; + } + + if (this.ptr[this.len] == 0) { + return this.sliceZ(); + } + + if (this.len >= buf.len) { + return ""; + } + + std.mem.copy(u8, buf[0..this.len], this.slice()); + buf[this.len] = 0; + return std.meta.assumeSentinel(buf[0..this.len], 0); + } + pub fn mut(this: Slice) []u8 { return @intToPtr([*]u8, @ptrToInt(this.ptr))[0..this.len]; } @@ -1789,6 +1811,10 @@ pub const JSGlobalObject = extern struct { pub const name = "JSC::JSGlobalObject"; pub const namespace = "JSC"; + pub fn allocator(this: *JSGlobalObject) std.mem.Allocator { + return this.bunVM().allocator; + } + pub fn throwInvalidArguments( this: *JSGlobalObject, comptime fmt: string, diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 16a7c0468..113160a7e 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -185,6 +185,7 @@ pub const JSReadableStreamFile = JSC.WebCore.FileBlobLoader.Source.JSReadableStr pub const JSArrayBufferSink = JSC.WebCore.ArrayBufferSink.JSSink; pub const JSHTTPSResponseSink = JSC.WebCore.HTTPSResponseSink.JSSink; pub const JSHTTPResponseSink = JSC.WebCore.HTTPResponseSink.JSSink; +pub const JSFileSink = JSC.WebCore.FileSink.JSSink; // WebSocket pub const WebSocketHTTPClient = @import("../../http/websocket_http_client.zig").WebSocketHTTPClient; @@ -1795,6 +1796,9 @@ pub const ZigConsoleClient = struct { } else if (value.as(JSC.WebCore.Request)) |request| { request.writeFormat(this, writer_, enable_ansi_colors) catch {}; return; + } else if (value.as(JSC.WebCore.Blob)) |blob| { + blob.writeFormat(this, writer_, enable_ansi_colors) catch {}; + return; } else if (jsType != .DOMWrapper) { if (CAPI.JSObjectGetPrivate(value.asRef())) |private_data_ptr| { const priv_data = JSPrivateDataPtr.from(private_data_ptr); @@ -1809,11 +1813,6 @@ pub const ZigConsoleClient = struct { resolve_error.msg.writeFormat(writer_, enable_ansi_colors) catch {}; return; }, - .Blob => { - var request = priv_data.as(JSC.WebCore.Blob); - request.writeFormat(this, writer_, enable_ansi_colors) catch {}; - return; - }, else => {}, } } @@ -2777,6 +2776,7 @@ comptime { JSArrayBufferSink.shim.ref(); JSHTTPResponseSink.shim.ref(); JSHTTPSResponseSink.shim.ref(); + JSFileSink.shim.ref(); JSReadableStreamFile.shim.ref(); _ = ZigString__free; diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index 0bc48964c..494ad1270 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -929,6 +929,95 @@ pub const JSResponse = struct { } } }; +pub const JSBlob = struct { + const Blob = Classes.Blob; + const GetterType = fn (*Blob, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + const SetterType = fn (*Blob, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; + const CallbackType = fn (*Blob, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue; + + /// Return the pointer to the wrapped object. + /// If the object does not match the type, return null. + pub fn fromJS(value: JSC.JSValue) ?*Blob { + JSC.markBinding(); + return Blob__fromJS(value); + } + + /// Get the Blob constructor value. + /// This loads lazily from the global object. + pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue { + JSC.markBinding(); + return Blob__getConstructor(globalObject); + } + + /// Create a new instance of Blob + pub fn toJS(this: *Blob, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + JSC.markBinding(); + if (comptime Environment.allow_assert) { + const value__ = Blob__create(globalObject, this); + std.debug.assert(value__.as(Blob).? == this); // If this fails, likely a C ABI issue. + return value__; + } else { + return Blob__create(globalObject, this); + } + } + + /// Modify the internal ptr to point to a new instance of Blob. + pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*Blob) bool { + JSC.markBinding(); + return Blob__dangerouslySetPtr(value, ptr); + } + + extern fn Blob__fromJS(JSC.JSValue) ?*Blob; + extern fn Blob__getConstructor(*JSC.JSGlobalObject) JSC.JSValue; + + extern fn Blob__create(globalObject: *JSC.JSGlobalObject, ptr: ?*Blob) JSC.JSValue; + + extern fn Blob__dangerouslySetPtr(JSC.JSValue, ?*Blob) bool; + + comptime { + if (@TypeOf(Blob.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*Blob)) { + @compileLog("Blob.constructor is not a constructor"); + } + + if (@TypeOf(Blob.finalize) != (fn (*Blob) callconv(.C) void)) { + @compileLog("Blob.finalize is not a finalizer"); + } + + if (@TypeOf(Blob.getArrayBuffer) != CallbackType) + @compileLog("Expected Blob.getArrayBuffer to be a callback"); + if (@TypeOf(Blob.getJSON) != CallbackType) + @compileLog("Expected Blob.getJSON to be a callback"); + if (@TypeOf(Blob.getSize) != GetterType) + @compileLog("Expected Blob.getSize to be a getter"); + + if (@TypeOf(Blob.getSlice) != CallbackType) + @compileLog("Expected Blob.getSlice to be a callback"); + if (@TypeOf(Blob.getStream) != CallbackType) + @compileLog("Expected Blob.getStream to be a callback"); + if (@TypeOf(Blob.getText) != CallbackType) + @compileLog("Expected Blob.getText to be a callback"); + if (@TypeOf(Blob.getType) != GetterType) + @compileLog("Expected Blob.getType to be a getter"); + + if (@TypeOf(Blob.setType) != SetterType) + @compileLog("Expected Blob.setType to be a setter"); + if (@TypeOf(Blob.getWriter) != CallbackType) + @compileLog("Expected Blob.getWriter to be a callback"); + if (!JSC.is_bindgen) { + @export(Blob.constructor, .{ .name = "BlobClass__construct" }); + @export(Blob.finalize, .{ .name = "BlobClass__finalize" }); + @export(Blob.getArrayBuffer, .{ .name = "BlobPrototype__getArrayBuffer" }); + @export(Blob.getJSON, .{ .name = "BlobPrototype__getJSON" }); + @export(Blob.getSize, .{ .name = "BlobPrototype__getSize" }); + @export(Blob.getSlice, .{ .name = "BlobPrototype__getSlice" }); + @export(Blob.getStream, .{ .name = "BlobPrototype__getStream" }); + @export(Blob.getText, .{ .name = "BlobPrototype__getText" }); + @export(Blob.getType, .{ .name = "BlobPrototype__getType" }); + @export(Blob.getWriter, .{ .name = "BlobPrototype__getWriter" }); + @export(Blob.setType, .{ .name = "BlobPrototype__setType" }); + } + } +}; comptime { _ = JSSHA1; @@ -942,4 +1031,5 @@ comptime { _ = JSTextDecoder; _ = JSRequest; _ = JSResponse; + _ = JSBlob; } diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index f491b52a0..f90cc95d4 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -12,4 +12,5 @@ pub const Classes = struct { pub const SHA256 = JSC.API.Bun.Crypto.SHA256; pub const SHA512_256 = JSC.API.Bun.Crypto.SHA512_256; pub const TextDecoder = JSC.WebCore.TextDecoder; + pub const Blob = JSC.WebCore.Blob; }; diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h index 550379eef..93b878c94 100644 --- a/src/bun.js/bindings/headers-cpp.h +++ b/src/bun.js/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1663152297 +//-- AUTOGENERATED FILE -- 1663900299 // clang-format off #pragma once @@ -240,8 +240,8 @@ extern "C" const size_t Zig__ConsoleClient_object_align_ = alignof(Zig::ConsoleC extern "C" const size_t Bun__Timer_object_size_ = sizeof(Bun__Timer); extern "C" const size_t Bun__Timer_object_align_ = alignof(Bun__Timer); -const size_t sizes[47] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(WebCore::FetchHeaders), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(FFI__ptr), sizeof(Reader__u8), sizeof(Reader__u16), sizeof(Reader__u32), sizeof(Reader__ptr), sizeof(Reader__i8), sizeof(Reader__i16), sizeof(Reader__i32), sizeof(Reader__f32), sizeof(Reader__f64), sizeof(Reader__i64), sizeof(Reader__u64), sizeof(Reader__intptr), sizeof(Crypto__getRandomValues), sizeof(Crypto__randomUUID), sizeof(Zig::GlobalObject), sizeof(Bun__Path), sizeof(ArrayBufferSink), sizeof(HTTPSResponseSink), sizeof(HTTPResponseSink)}; +const size_t sizes[48] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(WebCore::FetchHeaders), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(FFI__ptr), sizeof(Reader__u8), sizeof(Reader__u16), sizeof(Reader__u32), sizeof(Reader__ptr), sizeof(Reader__i8), sizeof(Reader__i16), sizeof(Reader__i32), sizeof(Reader__f32), sizeof(Reader__f64), sizeof(Reader__i64), sizeof(Reader__u64), sizeof(Reader__intptr), sizeof(Crypto__getRandomValues), sizeof(Crypto__randomUUID), sizeof(Zig::GlobalObject), sizeof(Bun__Path), sizeof(ArrayBufferSink), sizeof(HTTPSResponseSink), sizeof(HTTPResponseSink), sizeof(FileSink)}; -const char* names[47] = {"JSC__JSObject", "WebCore__DOMURL", "WebCore__FetchHeaders", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "FFI__ptr", "Reader__u8", "Reader__u16", "Reader__u32", "Reader__ptr", "Reader__i8", "Reader__i16", "Reader__i32", "Reader__f32", "Reader__f64", "Reader__i64", "Reader__u64", "Reader__intptr", "Crypto__getRandomValues", "Crypto__randomUUID", "Zig__GlobalObject", "Bun__Path", "ArrayBufferSink", "HTTPSResponseSink", "HTTPResponseSink"}; +const char* names[48] = {"JSC__JSObject", "WebCore__DOMURL", "WebCore__FetchHeaders", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "FFI__ptr", "Reader__u8", "Reader__u16", "Reader__u32", "Reader__ptr", "Reader__i8", "Reader__i16", "Reader__i32", "Reader__f32", "Reader__f64", "Reader__i64", "Reader__u64", "Reader__intptr", "Crypto__getRandomValues", "Crypto__randomUUID", "Zig__GlobalObject", "Bun__Path", "ArrayBufferSink", "HTTPSResponseSink", "HTTPResponseSink", "FileSink"}; -const size_t aligns[47] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(WebCore::FetchHeaders), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(FFI__ptr), alignof(Reader__u8), alignof(Reader__u16), alignof(Reader__u32), alignof(Reader__ptr), alignof(Reader__i8), alignof(Reader__i16), alignof(Reader__i32), alignof(Reader__f32), alignof(Reader__f64), alignof(Reader__i64), alignof(Reader__u64), alignof(Reader__intptr), alignof(Crypto__getRandomValues), alignof(Crypto__randomUUID), alignof(Zig::GlobalObject), alignof(Bun__Path), alignof(ArrayBufferSink), alignof(HTTPSResponseSink), alignof(HTTPResponseSink)}; +const size_t aligns[48] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(WebCore::FetchHeaders), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(FFI__ptr), alignof(Reader__u8), alignof(Reader__u16), alignof(Reader__u32), alignof(Reader__ptr), alignof(Reader__i8), alignof(Reader__i16), alignof(Reader__i32), alignof(Reader__f32), alignof(Reader__f64), alignof(Reader__i64), alignof(Reader__u64), alignof(Reader__intptr), alignof(Crypto__getRandomValues), alignof(Crypto__randomUUID), alignof(Zig::GlobalObject), alignof(Bun__Path), alignof(ArrayBufferSink), alignof(HTTPSResponseSink), alignof(HTTPResponseSink), alignof(FileSink)}; diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 293abf53f..b251568f9 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1663152297 +//-- AUTOGENERATED FILE -- 1663900299 #pragma once #include <stddef.h> @@ -879,6 +879,25 @@ ZIG_DECL JSC__JSValue HTTPResponseSink__start(JSC__JSGlobalObject* arg0, JSC__Ca ZIG_DECL JSC__JSValue HTTPResponseSink__write(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); #endif +CPP_DECL JSC__JSValue FileSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3); +CPP_DECL JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* arg1); +CPP_DECL void FileSink__detachPtr(JSC__JSValue JSValue0); +CPP_DECL void* FileSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1); +CPP_DECL void FileSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1); +CPP_DECL void FileSink__onReady(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSValue JSValue2); + +#ifdef __cplusplus + +ZIG_DECL JSC__JSValue FileSink__close(JSC__JSGlobalObject* arg0, void* arg1); +ZIG_DECL JSC__JSValue FileSink__construct(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); +ZIG_DECL JSC__JSValue FileSink__end(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); +ZIG_DECL JSC__JSValue FileSink__endWithSink(void* arg0, JSC__JSGlobalObject* arg1); +ZIG_DECL void FileSink__finalize(void* arg0); +ZIG_DECL JSC__JSValue FileSink__flush(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); +ZIG_DECL JSC__JSValue FileSink__start(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); +ZIG_DECL JSC__JSValue FileSink__write(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); + +#endif #ifdef __cplusplus diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 819b39ad9..606ae64a4 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -447,4 +447,10 @@ pub extern fn HTTPResponseSink__detachPtr(JSValue0: JSC__JSValue) void; pub extern fn HTTPResponseSink__fromJS(arg0: ?*JSC__JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; pub extern fn HTTPResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; pub extern fn HTTPResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; +pub extern fn FileSink__assignToStream(arg0: ?*JSC__JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; +pub extern fn FileSink__createObject(arg0: ?*JSC__JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; +pub extern fn FileSink__detachPtr(JSValue0: JSC__JSValue) void; +pub extern fn FileSink__fromJS(arg0: ?*JSC__JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; +pub extern fn FileSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; +pub extern fn FileSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; pub extern fn ZigException__fromException(arg0: [*c]JSC__Exception) ZigException; diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index fc072d95e..ff3dfa9e7 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -475,12 +475,13 @@ pub const Poller = struct { const linux = std.os.linux; const FileBlobLoader = JSC.WebCore.FileBlobLoader; - + const FileSink = JSC.WebCore.FileSink; /// epoll only allows one pointer /// We unfortunately need two pointers: one for a function call and one for the context /// We use a tagged pointer union and then call the function with the context pointer pub const Pollable = TaggedPointerUnion(.{ FileBlobLoader, + FileSink, AsyncIO.Waker, }); const Kevent = std.os.Kevent; @@ -599,8 +600,6 @@ pub const Poller = struct { pub const Flag = enum { read, write }; comptime { - if (!JSC.is_bindgen) { - @export(onTick, .{ .name = "Bun__internal_dispatch_ready_poll" }); - } + @export(onTick, .{ .name = "Bun__internal_dispatch_ready_poll" }); } }; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index eb3a5a455..08aa7b418 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -88,7 +88,6 @@ const Bun = JSC.API.Bun; const EventLoop = JSC.EventLoop; const ThreadSafeFunction = JSC.napi.ThreadSafeFunction; pub const GlobalConstructors = [_]type{ - WebCore.Blob.Constructor, JSC.Cloudflare.HTMLRewriter.Constructor, }; diff --git a/src/bun.js/scripts/class-definitions.ts b/src/bun.js/scripts/class-definitions.ts index 4b202f8a5..67e4cf475 100644 --- a/src/bun.js/scripts/class-definitions.ts +++ b/src/bun.js/scripts/class-definitions.ts @@ -19,6 +19,7 @@ export interface ClassDefinition { klass: Record<string, Field>; proto: Record<string, Field>; JSType?: string; + noConstructor?: boolean; } export function define( diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts index 0b0bc700e..558ba5a31 100644 --- a/src/bun.js/scripts/generate-classes.ts +++ b/src/bun.js/scripts/generate-classes.ts @@ -401,9 +401,13 @@ void ${name}::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, ${ const ClassInfo ${name}::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${name}) }; - -extern "C" EncodedJSValue ${typeName}__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->${className(typeName)}Constructor()); +${ + !obj.noConstructor + ? ` + extern "C" EncodedJSValue ${typeName}__getConstructor(Zig::GlobalObject* globalObject) { + return JSValue::encode(globalObject->${className(typeName)}Constructor()); + }` + : "" } @@ -451,18 +455,16 @@ function renderDecls(symbolName, typeName, proto) { "setter" in proto[name] || ("accessor" in proto[name] && proto[name].setter) ) { - rows - .push( - `extern "C" bool ${symbolName( - typeName, - proto[name].setter || proto[name].accessor.setter - )}(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, EncoedJSValue value);`, - ` + rows.push( + `extern "C" bool ${symbolName( + typeName, + proto[name].setter || proto[name].accessor.setter + )}(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value);`, + ` JSC_DECLARE_CUSTOM_SETTER(${symbolName(typeName, name)}SetterWrap); - `, - "\n" - ) - .trim(); + `.trim(), + "\n" + ); } if ("fn" in proto[name]) { @@ -620,7 +622,7 @@ JSC_DEFINE_CUSTOM_SETTER(${symbolName( name )}SetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) { - auto& vm = lexicalGlobalObject> + auto& vm = lexicalGlobalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); ${className(typeName)}* thisObject = jsCast<${className( typeName @@ -628,7 +630,7 @@ JSC_DEFINE_CUSTOM_SETTER(${symbolName( JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); auto result = ${symbolName( typeName, - roto[name].setter || proto[name].accessor.setter + proto[name].setter || proto[name].accessor.setter )}(thisObject->wrapped(), lexicalGlobalObject, encodedValue); RELEASE_AND_RETURN(throwScope, result); @@ -871,7 +873,7 @@ function generateHeader(typeName, obj) { return ( generateClassHeader(typeName, obj).trim() + "\n" + - generateConstructorHeader(typeName).trim() + + (!obj.noConstructor ? generateConstructorHeader(typeName).trim() : "") + "\n" ); } @@ -880,7 +882,7 @@ function generateImpl(typeName, obj) { const proto = obj.proto; return [ Object.keys(proto).length > 0 && generatePrototype(typeName, obj).trim(), - generateConstructorImpl(typeName, obj).trim(), + !obj.noConstructor ? generateConstructorImpl(typeName, obj).trim() : null, Object.keys(proto).length > 0 && generateClassImpl(typeName, obj).trim(), ] .filter(Boolean) @@ -889,7 +891,13 @@ function generateImpl(typeName, obj) { function generateZig( typeName, - { klass = {}, proto = {}, construct, finalize } = {} as ClassDefinition + { + klass = {}, + proto = {}, + construct, + finalize, + noConstructor, + } = {} as ClassDefinition ) { const exports: [string, string][] = []; @@ -1009,13 +1017,18 @@ pub const ${className(typeName)} = struct { return ${symbolName(typeName, "fromJS")}(value); } + ${ + !noConstructor + ? ` /// Get the ${typeName} constructor value. /// This loads lazily from the global object. pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(); return ${symbolName(typeName, "getConstructor")}(globalObject); } - + ` + : "" + } /// Create a new instance of ${typeName} pub fn toJS(this: *${typeName}, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(); @@ -1092,6 +1105,32 @@ function generateLazyClassStructureHeader( `.trim(); } +function generateLazyStructureHeader(typeName, { klass = {}, proto = {} }) { + return ` + JSC::Structure* ${className( + typeName + )}Structure() { return m_${className(typeName)}.get(this); } + JSC::LazyProperty<Zig::GlobalObject, Structure> m_${className(typeName)}; + bool has${className(typeName)}SetterValue { false }; + mutable JSC::WriteBarrier<JSC::Unknown> m_${className(typeName)}SetterValue; + `.trim(); +} + +function generateLazyStructureImpl(typeName, { klass = {}, proto = {} }) { + return ` + m_${className(typeName)}.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { + auto *prototype = WebCore::${className( + typeName + )}::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.owner)); + init.set(WebCore::${className( + typeName + )}::createStructure(init.vm, init.owner, prototype)); + }); + + `.trim(); +} + function generateLazyClassStructureImpl(typeName, { klass = {}, proto = {} }) { return ` m_${className(typeName)}.initLater( @@ -1273,7 +1312,13 @@ await writeAndUnlink(`${import.meta.dir}/../bindings/ZigGeneratedClasses.cpp`, [ ]); await writeAndUnlink( `${import.meta.dir}/../bindings/ZigGeneratedClasses+lazyStructureHeader.h`, - classes.map((a) => generateLazyClassStructureHeader(a.name, a)).join("\n") + classes + .map((a) => + !a.noConstructor + ? generateLazyClassStructureHeader(a.name, a) + : generateLazyStructureHeader(a.name, a) + ) + .join("\n") ); await writeAndUnlink( @@ -1281,9 +1326,11 @@ await writeAndUnlink( classes.map((a) => [ `std::unique_ptr<GCClient::IsoSubspace> ${clientSubspaceFor(a.name)};`, - `std::unique_ptr<GCClient::IsoSubspace> ${clientSubspaceFor( - a.name - )}Constructor;`, + !a.noConstructor + ? `std::unique_ptr<GCClient::IsoSubspace> ${clientSubspaceFor( + a.name + )}Constructor;` + : "", ].join("\n") ) ); @@ -1293,7 +1340,9 @@ await writeAndUnlink( classes.map((a) => [ `std::unique_ptr<IsoSubspace> ${subspaceFor(a.name)};`, - `std::unique_ptr<IsoSubspace> ${subspaceFor(a.name)}Constructor;`, + !a.noConstructor + ? `std::unique_ptr<IsoSubspace> ${subspaceFor(a.name)}Constructor;` + : ``, ].join("\n") ) ); @@ -1301,7 +1350,11 @@ await writeAndUnlink( await writeAndUnlink( `${import.meta.dir}/../bindings/ZigGeneratedClasses+lazyStructureImpl.h`, initLazyClasses( - classes.map((a) => generateLazyClassStructureImpl(a.name, a)) + classes.map((a) => + !a.noConstructor + ? generateLazyClassStructureImpl(a.name, a) + : generateLazyStructureImpl(a.name, a) + ) ) + "\n" + visitLazyClasses(classes) diff --git a/src/bun.js/scripts/generate-jssink.js b/src/bun.js/scripts/generate-jssink.js index 1caea3c22..65fc864fb 100644 --- a/src/bun.js/scripts/generate-jssink.js +++ b/src/bun.js/scripts/generate-jssink.js @@ -1,6 +1,11 @@ import { resolve } from "path"; -const classes = ["ArrayBufferSink", "HTTPResponseSink", "HTTPSResponseSink"]; +const classes = [ + "ArrayBufferSink", + "FileSink", + "HTTPResponseSink", + "HTTPSResponseSink", +]; const SINK_COUNT = 5; function names(name) { @@ -11,11 +16,14 @@ function names(name) { controllerName: `Readable${name}Controller`, prototypeName: `JS${name}Prototype`, controllerPrototypeName: `JSReadable${name}ControllerPrototype`, + writableStreamSourcePrototype: `JSWritableStreamSource${name}Prototype`, + writableStreamName: `JSWritableStreamSource${name}`, }; } function header() { function classTemplate(name) { - const { constructor, className, controller } = names(name); + const { constructor, className, controller, writableStreamName } = + names(name); return `class ${constructor} final : public JSC::InternalFunction { public: @@ -108,6 +116,8 @@ function header() { void finishCreation(JSC::VM&); }; + + class ${controller} final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; @@ -360,6 +370,8 @@ JSC_DEFINE_HOST_FUNCTION(functionStartDirectStream, (JSC::JSGlobalObject * lexic controllerName, controllerPrototypeName, constructor, + writableStreamName, + writableStreamSourcePrototype, } = names(name); const protopad = `${controller}__close`.length; const padding = `${name}__doClose`.length; @@ -460,6 +472,8 @@ JSC_DEFINE_HOST_FUNCTION(${name}__doClose, (JSC::JSGlobalObject * lexicalGlobalO controllerName, controllerPrototypeName, constructor, + writableStreamSourcePrototype, + writableStreamName, } = names(name); const protopad = `${controller}__close`.length; const padding = `${name}__doClose`.length; diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index 45df255e1..3cf695f74 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -104,4 +104,32 @@ export default [ }, }, }), + define({ + name: "Blob", + construct: true, + finalize: true, + JSType: "0b11101110", + klass: {}, + proto: { + text: { fn: "getText" }, + json: { fn: "getJSON" }, + arrayBuffer: { fn: "getArrayBuffer" }, + slice: { fn: "getSlice", length: 2 }, + stream: { fn: "getStream", length: 1 }, + + type: { + getter: "getType", + setter: "setType", + }, + + size: { + getter: "getSize", + }, + + writer: { + fn: "getWriter", + length: 1, + }, + }, + }), ]; diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 1028f4aa9..428ef6ab4 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -770,7 +770,7 @@ pub const Fetch = struct { } if (options.fastGet(ctx.ptr(), .body)) |body__| { - if (Blob.fromJS(ctx.ptr(), body__, true, false)) |new_blob| { + if (Blob.get(ctx.ptr(), body__, true, false)) |new_blob| { body = new_blob; } else |_| { return JSPromise.rejectedPromiseValue(globalThis, ZigString.init("fetch() received invalid body").toErrorInstance(globalThis)).asRef(); @@ -905,6 +905,8 @@ const PathOrBlob = union(enum) { }; pub const Blob = struct { + pub usingnamespace JSC.Codegen.JSBlob; + size: SizeType = 0, offset: SizeType = 0, /// When set, the blob will be freed on finalization callbacks @@ -1169,13 +1171,16 @@ pub const Blob = struct { clone.allocator = bun.default_allocator; var cloned = bun.default_allocator.create(Blob) catch unreachable; cloned.* = clone; - return JSPromise.resolvedPromiseValue(ctx.ptr(), JSC.JSValue.fromRef(Blob.Class.make(ctx, cloned))).asObjectRef(); + return JSPromise.resolvedPromiseValue(ctx.ptr(), cloned.toJS(ctx)).asObjectRef(); } else if (destination_type == .bytes and source_type == .file) { + var fake_call_frame: [8]JSC.JSValue = undefined; + @memset(@ptrCast([*]u8, &fake_call_frame), 0, @sizeOf(@TypeOf(fake_call_frame))); + const blob_value = + source_blob.getSlice(ctx, @ptrCast(*JSC.CallFrame, &fake_call_frame)); + return JSPromise.resolvedPromiseValue( ctx.ptr(), - JSC.JSValue.fromRef( - source_blob.getSlice(ctx, undefined, undefined, &.{}, null), - ), + blob_value, ).asObjectRef(); } @@ -1320,7 +1325,7 @@ pub const Blob = struct { } } - break :brk Blob.fromJS( + break :brk Blob.get( ctx.ptr(), data, false, @@ -1534,7 +1539,7 @@ pub const Blob = struct { var ptr = bun.default_allocator.create(Blob) catch unreachable; ptr.* = blob; ptr.allocator = bun.default_allocator; - return Blob.Class.make(ctx, ptr); + return ptr.toJS(ctx).asObjectRef(); } pub fn findOrCreateFileFromPath(path_: JSC.Node.PathOrFileDescriptor, globalThis: *JSGlobalObject) Blob { @@ -2831,62 +2836,27 @@ pub const Blob = struct { } }; - pub const Constructor = JSC.NewConstructor( - Blob, - .{ - .constructor = .{ .rfn = constructor }, - }, - .{}, - ); - - pub const Class = NewClass( - Blob, - .{ .name = "Blob" }, - .{ .finalize = finalize, .text = .{ - .rfn = getText_c, - }, .json = .{ - .rfn = getJSON_c, - }, .arrayBuffer = .{ - .rfn = getArrayBuffer_c, - }, .slice = .{ - .rfn = getSlice, - }, .stream = .{ - .rfn = getStream, - } }, - .{ - .@"type" = .{ - .get = getType, - .set = setType, - }, - .@"size" = .{ - .get = getSize, - .ro = true, - }, - }, - ); - pub fn getStream( this: *Blob, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, - ) JSC.C.JSValueRef { + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { var recommended_chunk_size: SizeType = 0; + var arguments_ = callframe.arguments(2); + var arguments = arguments_.ptr[0..arguments_.len]; if (arguments.len > 0) { - if (!JSValue.c(arguments[0]).isNumber() and !JSValue.c(arguments[0]).isUndefinedOrNull()) { - JSC.throwInvalidArguments("chunkSize must be a number", .{}, ctx, exception); - return null; + if (!arguments[0].isNumber() and !arguments[0].isUndefinedOrNull()) { + globalThis.throwInvalidArguments("chunkSize must be a number", .{}); + return JSValue.jsUndefined(); } - recommended_chunk_size = @intCast(SizeType, @maximum(0, @truncate(i52, JSValue.c(arguments[0]).toInt64()))); + recommended_chunk_size = @intCast(SizeType, @maximum(0, @truncate(i52, arguments[0].toInt64()))); } return JSC.WebCore.ReadableStream.fromBlob( - ctx.ptr(), + globalThis, this, recommended_chunk_size, - ).asObjectRef(); + ); } fn promisified( @@ -2909,7 +2879,8 @@ pub const Blob = struct { pub fn getText( this: *Blob, globalThis: *JSC.JSGlobalObject, - ) JSC.JSValue { + _: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { return promisified(this.toString(globalThis, .clone), globalThis); } @@ -2990,6 +2961,66 @@ pub const Blob = struct { return promisified(this.toArrayBuffer(ctx.ptr(), .clone), ctx.ptr()).asObjectRef(); } + pub fn getWriter( + this: *Blob, + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + var arguments_ = callframe.arguments(1); + var arguments = arguments_.ptr[0..arguments_.len]; + + var store = this.store orelse { + globalThis.throwInvalidArguments("Blob is detached", .{}); + return JSValue.jsUndefined(); + }; + + if (store.data != .file) { + globalThis.throwInvalidArguments("Blob is read-only", .{}); + return JSValue.jsUndefined(); + } + + var sink = JSC.WebCore.FileSink.init(globalThis.allocator(), null) catch |err| { + globalThis.throwInvalidArguments("Failed to create FileSink: {s}", .{@errorName(err)}); + return JSValue.jsUndefined(); + }; + + var input_path: JSC.WebCore.PathOrFileDescriptor = undefined; + if (store.data.file.pathlike == .fd) { + input_path = .{ .fd = store.data.file.pathlike.fd }; + } else { + input_path = .{ + .path = ZigString.Slice{ + .ptr = store.data.file.pathlike.path.slice().ptr, + .len = @truncate(u32, store.data.file.pathlike.path.slice().len), + .allocated = false, + .allocator = bun.default_allocator, + }, + }; + } + + var stream_start: JSC.WebCore.StreamStart = .{ + .FileSink = .{ + .input_path = input_path, + }, + }; + + if (arguments.len > 0) { + stream_start = JSC.WebCore.StreamStart.fromJSWithTag(globalThis, arguments[0], .FileSink); + stream_start.FileSink.input_path = input_path; + } + + switch (sink.start(stream_start)) { + .err => |err| { + globalThis.vm().throwError(globalThis, err.toJSC(globalThis)); + sink.finalize(); + return JSC.JSValue.jsUndefined(); + }, + else => {}, + } + + return sink.toJS(globalThis); + } + /// https://w3c.github.io/FileAPI/#slice-method-algo /// The slice() method returns a new Blob object with bytes ranging from the /// optional start parameter up to but not including the optional end @@ -2997,22 +3028,30 @@ pub const Blob = struct { /// contentType parameter. It must act as follows: pub fn getSlice( this: *Blob, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - args: []const js.JSValueRef, - exception: js.ExceptionRef, - ) JSC.C.JSObjectRef { + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + var allocator = globalThis.allocator(); + var arguments_ = callframe.arguments(2); + var args = arguments_.ptr[0..arguments_.len]; + if (this.size == 0) { - return constructor(ctx, null, &[_]js.JSValueRef{}, exception); + const empty = Blob.initEmpty(globalThis); + var ptr = allocator.create(Blob) catch { + return JSC.JSValue.jsUndefined(); + }; + ptr.* = empty; + ptr.allocator = allocator; + return ptr.toJS(globalThis); } + // If the optional start parameter is not used as a parameter when making this call, let relativeStart be 0. var relativeStart: i64 = 0; // If the optional end parameter is not used as a parameter when making this call, let relativeEnd be size. var relativeEnd: i64 = @intCast(i64, this.size); - var args_iter = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), args); + var args_iter = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), args); if (args_iter.nextEat()) |start_| { const start = start_.toInt64(); if (start < 0) { @@ -3039,11 +3078,11 @@ pub const Blob = struct { var content_type: string = ""; if (args_iter.nextEat()) |content_type_| { if (content_type_.isString()) { - var zig_str = content_type_.getZigString(ctx.ptr()); + var zig_str = content_type_.getZigString(globalThis); var slicer = zig_str.toSlice(bun.default_allocator); defer slicer.deinit(); var slice = slicer.slice(); - var content_type_buf = getAllocator(ctx).alloc(u8, slice.len) catch unreachable; + var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable; content_type = strings.copyLowercase(slice, content_type_buf); } } @@ -3058,31 +3097,25 @@ pub const Blob = struct { blob.content_type = content_type; blob.content_type_allocated = content_type.len > 0; - var blob_ = getAllocator(ctx).create(Blob) catch unreachable; + var blob_ = allocator.create(Blob) catch unreachable; blob_.* = blob; - blob_.allocator = getAllocator(ctx); - return Blob.Class.make(ctx, blob_); + blob_.allocator = allocator; + return blob_.toJS(globalThis); } pub fn getType( this: *Blob, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ZigString.init(this.content_type).toValue(ctx.ptr()).asObjectRef(); + globalThis: *JSC.JSGlobalObject, + ) callconv(.C) JSValue { + return ZigString.init(this.content_type).toValue(globalThis); } pub fn setType( this: *Blob, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSStringRef, - value: js.JSValueRef, - _: js.ExceptionRef, - ) bool { - var zig_str = JSValue.fromRef(value).getZigString(ctx.ptr()); + globalThis: *JSC.JSGlobalObject, + value: JSC.JSValue, + ) callconv(.C) bool { + var zig_str = value.getZigString(globalThis); if (zig_str.is16Bit()) return false; @@ -3093,7 +3126,7 @@ pub const Blob = struct { const prev_content_type = this.content_type; { defer if (this.content_type_allocated) bun.default_allocator.free(prev_content_type); - var content_type_buf = getAllocator(ctx).alloc(u8, slice.len) catch unreachable; + var content_type_buf = globalThis.allocator().alloc(u8, slice.len) catch unreachable; this.content_type = strings.copyLowercase(slice, content_type_buf); } @@ -3101,25 +3134,19 @@ pub const Blob = struct { return true; } - pub fn getSize( - this: *Blob, - _: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { + pub fn getSize(this: *Blob, _: *JSC.JSGlobalObject) callconv(.C) JSValue { if (this.size == Blob.max_size) { this.resolveSize(); if (this.size == Blob.max_size and this.store != null) { - return JSValue.jsNumberFromChar(0).asRef(); + return JSValue.jsNumberFromChar(0); } } if (this.size < std.math.maxInt(i32)) { - return JSValue.jsNumber(this.size).asRef(); + return JSValue.jsNumber(this.size); } - return JSC.JSValue.jsNumberFromUint64(this.size).asRef(); + return JSC.JSValue.jsNumberFromUint64(this.size); } pub fn resolveSize(this: *Blob) void { @@ -3138,40 +3165,42 @@ pub const Blob = struct { } pub fn constructor( - ctx: js.JSContextRef, - _: js.JSObjectRef, - args: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSObjectRef { + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) callconv(.C) ?*Blob { + var allocator = globalThis.allocator(); var blob: Blob = undefined; + var arguments = callframe.arguments(2); + var args = arguments.ptr[0..arguments.len]; + switch (args.len) { 0 => { var empty: []u8 = &[_]u8{}; - blob = Blob.init(empty, getAllocator(ctx), ctx.ptr()); + blob = Blob.init(empty, allocator, globalThis); }, else => { - blob = fromJS(ctx.ptr(), JSValue.fromRef(args[0]), false, true) catch |err| { + blob = get(globalThis, args[0], false, true) catch |err| { if (err == error.InvalidArguments) { - JSC.JSError(getAllocator(ctx), "new Blob() expects an Array", .{}, ctx, exception); + globalThis.throwInvalidArguments("new Blob() expects an Array", .{}); return null; } - JSC.JSError(getAllocator(ctx), "out of memory :(", .{}, ctx, exception); + globalThis.throw("out of memory", .{}); return null; }; if (args.len > 1) { - var options = JSValue.fromRef(args[1]); + var options = args[0]; if (options.isCell()) { // type, the ASCII-encoded string in lower case // representing the media type of the Blob. // Normative conditions for this member are provided // in the § 3.1 Constructors. - if (options.get(ctx.ptr(), "type")) |content_type| { + if (options.get(globalThis, "type")) |content_type| { if (content_type.isString()) { - var content_type_str = content_type.getZigString(ctx.ptr()); + var content_type_str = content_type.getZigString(globalThis); if (!content_type_str.is16Bit()) { var slice = content_type_str.trimmedSlice(); - var content_type_buf = getAllocator(ctx).alloc(u8, slice.len) catch unreachable; + var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable; blob.content_type = strings.copyLowercase(slice, content_type_buf); blob.content_type_allocated = true; } @@ -3186,13 +3215,13 @@ pub const Blob = struct { }, } - var blob_ = getAllocator(ctx).create(Blob) catch unreachable; + var blob_ = allocator.create(Blob) catch unreachable; blob_.* = blob; - blob_.allocator = getAllocator(ctx); - return Blob.Class.make(ctx, blob_); + blob_.allocator = allocator; + return blob_; } - pub fn finalize(this: *Blob) void { + pub fn finalize(this: *Blob) callconv(.C) void { this.deinit(); } @@ -3566,7 +3595,7 @@ pub const Blob = struct { return toArrayBufferWithBytes(this, global, bun.constStrToU8(view_), lifetime); } - pub inline fn fromJS( + pub inline fn get( global: *JSGlobalObject, arg: JSValue, comptime move: bool, @@ -3676,28 +3705,20 @@ pub const Blob = struct { return Blob.init(buf, bun.default_allocator, global); }, - else => |tag| { - if (tag != .DOMWrapper) { - if (JSC.C.JSObjectGetPrivate(top_value.asObjectRef())) |priv| { - var data = JSC.JSPrivateDataPtr.from(priv); - switch (data.tag()) { - .Blob => { - var blob: *Blob = data.as(Blob); - if (comptime move) { - var _blob = blob.*; - _blob.allocator = null; - blob.transfer(); - return _blob; - } else { - return blob.dupe(); - } - }, - - else => return Blob.initEmpty(global), - } + .DOMWrapper => { + if (top_value.as(Blob)) |blob| { + if (comptime move) { + var _blob = blob.*; + _blob.allocator = null; + blob.transfer(); + return _blob; + } else { + return blob.dupe(); } } }, + + else => {}, } } @@ -3778,20 +3799,15 @@ pub const Blob = struct { could_have_non_ascii = true; break; }, - else => { - if (JSC.C.JSObjectGetPrivate(item.asObjectRef())) |priv| { - var data = JSC.JSPrivateDataPtr.from(priv); - switch (data.tag()) { - .Blob => { - var blob: *Blob = data.as(Blob); - could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); - joiner.append(blob.sharedView(), 0, null); - continue; - }, - else => {}, - } + + .DOMWrapper => { + if (item.as(Blob)) |blob| { + could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); + joiner.append(blob.sharedView(), 0, null); + continue; } }, + else => {}, } } @@ -3799,7 +3815,12 @@ pub const Blob = struct { } }, - .DOMWrapper => {}, + .DOMWrapper => { + if (current.as(Blob)) |blob| { + could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); + joiner.append(blob.sharedView(), 0, null); + } + }, JSC.JSValue.JSType.ArrayBuffer, JSC.JSValue.JSType.Int8Array, @@ -3821,28 +3842,13 @@ pub const Blob = struct { }, else => { - outer: { - if (JSC.C.JSObjectGetPrivate(current.asObjectRef())) |priv| { - var data = JSC.JSPrivateDataPtr.from(priv); - switch (data.tag()) { - .Blob => { - var blob: *Blob = data.as(Blob); - could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); - joiner.append(blob.sharedView(), 0, null); - break :outer; - }, - else => {}, - } - } - - var sliced = current.toSlice(global, bun.default_allocator); - could_have_non_ascii = could_have_non_ascii or sliced.allocated; - joiner.append( - sliced.slice(), - 0, - if (sliced.allocated) sliced.allocator else null, - ); - } + var sliced = current.toSlice(global, bun.default_allocator); + could_have_non_ascii = could_have_non_ascii or sliced.allocated; + joiner.append( + sliced.slice(), + 0, + if (sliced.allocated) sliced.allocator else null, + ); }, } current = stack.popOrNull() orelse break; @@ -4101,13 +4107,13 @@ pub const Body = struct { var ptr = bun.default_allocator.create(Blob) catch unreachable; ptr.* = blob; ptr.allocator = bun.default_allocator; - promise.asPromise().?.resolve(global, JSC.JSValue.fromRef(Blob.Class.make(global.ref(), ptr))); + promise.asPromise().?.resolve(global, ptr.toJS(global)); }, else => { var ptr = bun.default_allocator.create(Blob) catch unreachable; ptr.* = blob; ptr.allocator = bun.default_allocator; - promise.asInternalPromise().?.resolve(global, JSC.JSValue.fromRef(Blob.Class.make(global.ref(), ptr))); + promise.asInternalPromise().?.resolve(global, ptr.toJS(global)); }, } JSC.C.JSValueUnprotect(global.ref(), promise.asObjectRef()); @@ -4300,7 +4306,7 @@ pub const Body = struct { } body.value = .{ - .Blob = Blob.fromJS(globalThis, value, true, false) catch |err| { + .Blob = Blob.get(globalThis, value, true, false) catch |err| { if (err == error.InvalidArguments) { globalThis.throwInvalidArguments("Expected an Array", .{}); return null; @@ -4511,7 +4517,7 @@ pub const Request = struct { } if (urlOrObject.fastGet(globalThis, .body)) |body_| { - if (Blob.fromJS(globalThis, body_, true, false)) |blob| { + if (Blob.get(globalThis, body_, true, false)) |blob| { if (blob.size > 0) { request.body = Body.Value{ .Blob = blob }; } @@ -4536,7 +4542,7 @@ pub const Request = struct { } if (arguments[1].fastGet(globalThis, .body)) |body_| { - if (Blob.fromJS(globalThis, body_, true, false)) |blob| { + if (Blob.get(globalThis, body_, true, false)) |blob| { if (blob.size > 0) { request.body = Body.Value{ .Blob = blob }; } @@ -4693,7 +4699,7 @@ fn BlobInterface(comptime Type: type) type { var ptr = getAllocator(ctx).create(Blob) catch unreachable; ptr.* = blob; blob.allocator = getAllocator(ctx); - return JSC.JSPromise.resolvedPromiseValue(ctx.ptr(), JSValue.fromRef(Blob.Class.make(ctx, ptr))).asObjectRef(); + return JSC.JSPromise.resolvedPromiseValue(ctx.ptr(), ptr.toJS(ctx)).asObjectRef(); } // pub fn getBody( @@ -4775,7 +4781,7 @@ fn NewBlobInterface(comptime Type: type) type { var ptr = getAllocator(globalObject).create(Blob) catch unreachable; ptr.* = blob; blob.allocator = getAllocator(globalObject); - return JSC.JSPromise.resolvedPromiseValue(globalObject, JSValue.fromRef(Blob.Class.make(globalObject, ptr))); + return JSC.JSPromise.resolvedPromiseValue(globalObject, ptr.toJS(globalObject)); } // pub fn getBody( diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index b7af9a8df..5c7d08f4f 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -249,6 +249,13 @@ pub const StreamStart = union(Tag) { as_uint8array: bool, stream: bool, }, + FileSink: struct { + chunk_size: Blob.SizeType = 16384, + input_path: PathOrFileDescriptor, + truncate: bool = true, + close: bool = false, + mode: JSC.Node.Mode = 0, + }, HTTPSResponseSink: void, HTTPResponseSink: void, ready: void, @@ -258,6 +265,7 @@ pub const StreamStart = union(Tag) { err, chunk_size, ArrayBufferSink, + FileSink, HTTPSResponseSink, HTTPResponseSink, ready, @@ -334,6 +342,40 @@ pub const StreamStart = union(Tag) { }; } }, + .FileSink => { + var chunk_size: JSC.WebCore.Blob.SizeType = 0; + + if (value.get(globalThis, "highWaterMark")) |chunkSize| { + chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @maximum(0, @truncate(i51, chunkSize.toInt64()))); + } + + if (value.get(globalThis, "path")) |path| { + return .{ + .FileSink = .{ + .chunk_size = chunk_size, + .input_path = .{ + .path = path.toSlice(globalThis, globalThis.bunVM().allocator), + }, + }, + }; + } else if (value.get(globalThis, "fd")) |fd| { + return .{ + .FileSink = .{ + .chunk_size = chunk_size, + .input_path = .{ + .fd = fd.toInt32(), + }, + }, + }; + } + + return .{ + .FileSink = .{ + .input_path = .{ .fd = std.math.maxInt(JSC.Node.FileDescriptor) }, + .chunk_size = chunk_size, + }, + }; + }, .HTTPSResponseSink, .HTTPResponseSink => { var empty = true; var chunk_size: JSC.WebCore.Blob.SizeType = 2048; @@ -406,7 +448,16 @@ pub const StreamResult = union(Tag) { frame: anyframe, result: Writable, consumed: Blob.SizeType = 0, - used: bool = false, + state: StreamResult.Pending.State = .none, + + pub fn run(this: *Writable.Pending) void { + if (this.state != .pending) { + return; + } + + this.state = .used; + resume this.frame; + } }; pub fn toPromised(globalThis: *JSGlobalObject, promise: *JSPromise, pending: *Writable.Pending) void { @@ -424,7 +475,6 @@ pub const StreamResult = union(Tag) { fn toPromisedWrap(globalThis: *JSGlobalObject, promise: *JSPromise, pending: *Writable.Pending) void { suspend {} - pending.used = true; const result: Writable = pending.result; switch (result) { @@ -472,7 +522,19 @@ pub const StreamResult = union(Tag) { pub const Pending = struct { frame: anyframe, result: StreamResult, - used: bool = false, + state: State = .none, + + pub const State = enum { + none, + pending, + used, + }; + + pub fn run(this: *Pending) void { + if (this.state != .pending) return; + this.state = .used; + resume this.frame; + } }; pub fn isDone(this: *const StreamResult) bool { @@ -485,7 +547,6 @@ pub const StreamResult = union(Tag) { fn toPromisedWrap(globalThis: *JSGlobalObject, promise: *JSPromise, pending: *Pending) void { suspend {} - pending.used = true; const result: StreamResult = pending.result; switch (result) { @@ -846,6 +907,360 @@ pub const Sink = struct { } }; +pub const PathOrFileDescriptor = union(enum) { + path: ZigString.Slice, + fd: JSC.Node.FileDescriptor, +}; + +pub const FileSink = struct { + buffer: bun.ByteList, + allocator: std.mem.Allocator, + done: bool = false, + signal: Signal = .{}, + next: ?Sink = null, + auto_close: bool = false, + auto_truncate: bool = false, + opened_fd: JSC.Node.FileDescriptor = std.math.maxInt(JSC.Node.FileDescriptor), + mode: JSC.Node.Mode = 0, + chunk_size: usize = 0, + pending: StreamResult.Writable.Pending = StreamResult.Writable.Pending{ + .frame = undefined, + .result = .{ .done = {} }, + }, + + scheduled_count: u32 = 0, + written: usize = 0, + head: usize = 0, + requested_end: bool = false, + + pub fn prepare(this: *FileSink, input_path: PathOrFileDescriptor, mode: JSC.Node.Mode) JSC.Node.Maybe(void) { + var file_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const auto_close = this.auto_close; + const fd = if (!auto_close) + input_path.fd + else switch (JSC.Node.Syscall.open(input_path.path.toSliceZ(&file_buf), std.os.O.WRONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC | std.os.O.CREAT, mode)) { + .result => |_fd| _fd, + .err => |err| return .{ .err = err.withPath(input_path.path.slice()) }, + }; + + const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) { + .result => |result| result, + .err => |err| { + if (auto_close) { + _ = JSC.Node.Syscall.close(fd); + } + if (input_path == .path) + return .{ .err = err.withPath(input_path.path.slice()) }; + return .{ .err = err }; + }, + }; + + this.mode = stat.mode; + this.opened_fd = fd; + + return .{ .result = {} }; + } + + pub fn connect(this: *FileSink, signal: Signal) void { + std.debug.assert(this.reader == null); + this.signal = signal; + } + + pub fn start(this: *FileSink, stream_start: StreamStart) JSC.Node.Maybe(void) { + if (this.opened_fd != std.math.maxInt(JSC.Node.FileDescriptor)) { + _ = JSC.Node.Syscall.close(this.opened_fd); + this.opened_fd = std.math.maxInt(JSC.Node.FileDescriptor); + } + + this.done = false; + this.written = 0; + this.auto_close = false; + this.auto_truncate = false; + this.requested_end = false; + + this.buffer.len = 0; + + switch (stream_start) { + .FileSink => |config| { + this.chunk_size = config.chunk_size; + this.auto_close = config.close or config.input_path == .path; + this.auto_truncate = config.truncate; + + defer if (config.input_path == .path) config.input_path.path.deinit(); + + switch (this.prepare(config.input_path, config.mode)) { + .err => |err| { + return .{ .err = err }; + }, + .result => {}, + } + }, + else => {}, + } + + this.signal.start(); + return .{ .result = {} }; + } + + pub fn flush(this: *FileSink) StreamResult.Writable { + std.debug.assert(this.opened_fd != std.math.maxInt(JSC.Node.FileDescriptor)); + + var total: usize = this.written; + const initial = total; + defer this.written = total; + const fd = this.opened_fd; + var remain = this.buffer.slice(); + remain = remain[@minimum(this.head, remain.len)..]; + defer { + std.debug.assert(total - initial == @ptrToInt(remain.ptr) - @ptrToInt(this.buffer.ptr)); + + if (remain.len == 0) { + this.head = 0; + this.buffer.len = 0; + } else { + this.head += total - initial; + } + } + while (remain.len > 0) { + const res = JSC.Node.Syscall.write(fd, remain); + if (res == .err) { + const retry = comptime if (Environment.isLinux) + std.os.E.WOULDBLOCK + else + std.os.E.AGAIN; + + switch (res.err.getErrno()) { + retry => { + this.watch(); + return .{ + .pending = &this.pending, + }; + }, + else => {}, + } + this.pending.result = .{ .err = res.err }; + this.pending.consumed = @truncate(Blob.SizeType, total - initial); + + return .{ .err = res.err }; + } + + remain = remain[res.result..]; + total += res.result; + if (res.result == 0) break; + } + + this.pending.result = .{ + .owned = @truncate(Blob.SizeType, total), + }; + this.pending.consumed = @truncate(Blob.SizeType, total - initial); + if (this.requested_end) { + this.done = true; + if (this.auto_truncate) + std.os.ftruncate(this.opened_fd, total) catch {}; + + if (this.auto_close) { + _ = JSC.Node.Syscall.close(this.opened_fd); + this.opened_fd = std.math.maxInt(JSC.Node.FileDescriptor); + } + } + this.pending.run(); + return .{ .owned = @truncate(Blob.SizeType, total - initial) }; + } + + pub fn flushFromJS(this: *FileSink, globalThis: *JSGlobalObject, _: bool) JSC.Node.Maybe(JSValue) { + const result = this.flush(); + + if (result == .err) { + return .{ .err = result.err }; + } + + return JSC.Node.Maybe(JSValue){ + .result = result.toJS(globalThis), + }; + } + + fn cleanup(this: *FileSink) void { + if (this.opened_fd != std.math.maxInt(JSC.Node.FileDescriptor)) { + _ = JSC.Node.Syscall.close(this.opened_fd); + this.opened_fd = std.math.maxInt(JSC.Node.FileDescriptor); + } + + if (this.buffer.len > 0) { + this.buffer.listManaged(this.allocator).deinit(); + this.buffer = bun.ByteList.init(""); + this.done = true; + this.head = 0; + } + } + + pub fn finalize(this: *FileSink) void { + this.cleanup(); + + this.allocator.destroy(this); + } + + pub fn init(allocator: std.mem.Allocator, next: ?Sink) !*FileSink { + var this = try allocator.create(FileSink); + this.* = FileSink{ + .buffer = bun.ByteList.init(&.{}), + .allocator = allocator, + .next = next, + }; + return this; + } + + pub fn construct( + this: *FileSink, + allocator: std.mem.Allocator, + ) void { + this.* = FileSink{ + .buffer = bun.ByteList.init(&.{}), + .allocator = allocator, + .next = null, + }; + } + + pub fn watch(this: *FileSink) void { + std.debug.assert(this.opened_fd != std.math.maxInt(JSC.Node.FileDescriptor)); + _ = JSC.VirtualMachine.vm.poller.watch(this.opened_fd, .write, FileSink, this); + this.scheduled_count += 1; + } + + pub fn toJS(this: *FileSink, globalThis: *JSGlobalObject) JSValue { + return JSSink.createObject(globalThis, this); + } + + pub fn onPoll(this: *FileSink, _: i64, _: u16) void { + this.scheduled_count -= 1; + this.flush(); + } + + pub fn write(this: *@This(), data: StreamResult) StreamResult.Writable { + const input = data.slice(); + + if (!this.isPending() and this.buffer.len == 0 and input.len >= this.chunk_size) { + var temp = this.buffer; + defer this.buffer = temp; + this.buffer = bun.ByteList.init(input); + const result = this.flush(); + if (this.isPending()) { + _ = temp.write(this.allocator, input) catch { + return .{ .err = Syscall.Error.oom }; + }; + } + + return result; + } + + const len = this.buffer.write(this.allocator, input) catch { + return .{ .err = Syscall.Error.oom }; + }; + + if (!this.isPending() and this.buffer.len >= this.chunk_size) { + return this.flush(); + } + + this.signal.ready(null, null); + return .{ .owned = len }; + } + pub const writeBytes = write; + pub fn writeLatin1(this: *@This(), data: StreamResult) StreamResult.Writable { + const input = data.slice(); + + if (!this.isPending() and this.buffer.len == 0 and input.len >= this.chunk_size and strings.isAllASCII(input)) { + var temp = this.buffer; + defer this.buffer = temp; + this.buffer = bun.ByteList.init(input); + const result = this.flush(); + if (this.isPending()) { + _ = temp.write(this.allocator, input) catch { + return .{ .err = Syscall.Error.oom }; + }; + } + + return result; + } + + const len = this.buffer.writeLatin1(this.allocator, input) catch { + return .{ .err = Syscall.Error.oom }; + }; + + if (!this.isPending() and this.buffer.len >= this.chunk_size) { + return this.flush(); + } + + this.signal.ready(null, null); + return .{ .owned = len }; + } + pub fn writeUTF16(this: *@This(), data: StreamResult) StreamResult.Writable { + if (this.next) |*next| { + return next.writeUTF16(data); + } + const len = this.buffer.writeUTF16(this.allocator, @ptrCast([*]const u16, @alignCast(@alignOf(u16), data.slice().ptr))[0..std.mem.bytesAsSlice(u16, data.slice()).len]) catch { + return .{ .err = Syscall.Error.oom }; + }; + if (!this.isPending() and this.buffer.len >= this.chunk_size) { + return this.flush(); + } + this.signal.ready(null, null); + + return .{ .owned = len }; + } + + fn isPending(this: *const FileSink) bool { + return this.scheduled_count > 0; + } + + pub fn end(this: *FileSink, err: ?Syscall.Error) JSC.Node.Maybe(void) { + if (this.next) |*next| { + return next.end(err); + } + this.requested_end = true; + + const flushy = this.flush(); + + if (flushy == .err) { + return .{ .err = flushy.err }; + } + + if (flushy != .pending) { + this.cleanup(); + } + + this.signal.close(err); + return .{ .result = {} }; + } + + pub fn endFromJS(this: *FileSink, globalThis: *JSGlobalObject) JSC.Node.Maybe(JSValue) { + if (this.done) { + return .{ .result = JSValue.jsNumber(this.written) }; + } + + std.debug.assert(this.next == null); + this.requested_end = true; + + const flushed = this.flush(); + + if (flushed == .err) { + return .{ .err = flushed.err }; + } + + if (flushed != .pending) { + this.cleanup(); + } + + this.signal.close(null); + + return .{ .result = flushed.toJS(globalThis) }; + } + + pub fn sink(this: *FileSink) Sink { + return Sink.init(this); + } + + pub const JSSink = NewJSSink(@This(), "FileSink"); +}; + pub const ArrayBufferSink = struct { bytes: bun.ByteList, allocator: std.mem.Allocator, @@ -2302,7 +2717,7 @@ pub const FileBlobLoader = struct { callback: anyframe = undefined, pending: StreamResult.Pending = StreamResult.Pending{ .frame = undefined, - .used = false, + .state = .none, .result = .{ .done = {} }, }, cancelled: bool = false, @@ -2348,7 +2763,7 @@ pub const FileBlobLoader = struct { pub fn taskCallback(task: *NetworkThread.Task) void { var this = @fieldParentPtr(FileBlobLoader, "concurrent", @fieldParentPtr(Concurrent, "task", task)); - var frame = HTTPClient.getAllocator().create(@Frame(runAsync)) catch unreachable; + var frame = bun.default_allocator.create(@Frame(runAsync)) catch unreachable; _ = @asyncCall(std.mem.asBytes(frame), undefined, runAsync, .{this}); } @@ -2430,7 +2845,7 @@ pub const FileBlobLoader = struct { suspend { var _frame = @frame(); - var this_frame = HTTPClient.getAllocator().create(std.meta.Child(@TypeOf(_frame))) catch unreachable; + var this_frame = bun.default_allocator.create(std.meta.Child(@TypeOf(_frame))) catch unreachable; this_frame.* = _frame.*; this.concurrent.read_frame = this_frame; } @@ -2445,9 +2860,7 @@ pub const FileBlobLoader = struct { this.protected_view = JSC.JSValue.zero; if (this.finalized and this.scheduled_count == 0) { - if (!this.pending.used) { - resume this.pending.frame; - } + this.pending.run(); this.scheduled_count -= 1; this.deinit(); @@ -2455,7 +2868,7 @@ pub const FileBlobLoader = struct { return; } - if (!this.pending.used and this.pending.result == .err and this.concurrent.read == 0) { + if (this.pending.state == .pending and this.pending.result == .err and this.concurrent.read == 0) { resume this.pending.frame; this.scheduled_count -= 1; this.finalize(); @@ -2489,7 +2902,7 @@ pub const FileBlobLoader = struct { Concurrent.scheduleRead(this); suspend { - HTTPClient.getAllocator().destroy(@frame()); + bun.default_allocator.destroy(@frame()); } } }; @@ -2742,7 +3155,7 @@ pub const FileBlobLoader = struct { } } if (this.finalized and this.scheduled_count == 0) { - if (!this.pending.used) { + if (this.pending.state == .pending) { // should never be reached this.pending.result = .{ .err = Syscall.Error.todo, @@ -2762,7 +3175,7 @@ pub const FileBlobLoader = struct { } this.pending.result = this.read(this.buf, this.protected_view); - resume this.pending.frame; + this.pending.run(); } pub fn finalize(this: *FileBlobLoader) void { @@ -2783,7 +3196,7 @@ pub const FileBlobLoader = struct { pub fn deinit(this: *FileBlobLoader) void { this.finalize(); - if (this.scheduled_count == 0 and !this.pending.used) { + if (this.scheduled_count == 0 and this.pending.state == .pending) { this.destroy(); } } diff --git a/src/js_ast.zig b/src/js_ast.zig index 7a7afbc68..95b650cef 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -7840,6 +7840,9 @@ pub const Macro = struct { } else if (value.as(JSC.WebCore.Request)) |resp| { mime_type = HTTP.MimeType.init(resp.mimeType()); blob_ = resp.body.use(); + } else if (value.as(JSC.WebCore.Blob)) |resp| { + blob_ = resp.*; + blob_.?.allocator = null; } } else { var private_data = JSCBase.JSPrivateDataPtr.from(JSC.C.JSObjectGetPrivate(value.asObjectRef()).?); @@ -7856,11 +7859,7 @@ pub const Macro = struct { this.macro.vm.runErrorHandler(value, null); return error.MacroFailed; }, - .Blob => { - var blob = private_data.as(JSC.WebCore.Blob); - blob_ = blob.*; - blob.* = JSC.WebCore.Blob.initEmpty(blob.globalThis); - }, + else => {}, } } |