diff --git a/.cursorignore b/.cursorignore index e56b21e52f6de1..50a369268983ad 100644 --- a/.cursorignore +++ b/.cursorignore @@ -1,7 +1,22 @@ +vendor +src/bun.js/bindings/webcore/JSReadableStream.h +src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.h +src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp +src/bun.js/bindings/webcore/JSReadableStreamDefaultController.h +src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp +src/bun.js/bindings/webcore/JSReadableStream.h +src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.h +src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.cpp +src/bun.js/bindings/webcore/JSWritableStreamDefaultController.h +src/bun.js/bindings/webcore/JSWritableStreamDefaultController.cpp +src/bun.js/bindings/webcore/JSTransformStreamDefaultController.h +src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp +src/bun.js/bindings/webcore/JSTransformStream.h +src/bun.js/bindings/webcore/JSTransformStream.cpp # Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv) bench vendor *-fixture.{js,ts} zig-cache packages/bun-uws/fuzzing -build \ No newline at end of file +build diff --git a/bench/snippets/ReadableStream.mjs b/bench/snippets/ReadableStream.mjs new file mode 100644 index 00000000000000..c025888ebd5cbc --- /dev/null +++ b/bench/snippets/ReadableStream.mjs @@ -0,0 +1,91 @@ +import React from "react"; +import { renderToReadableStream } from "react-dom/server.browser"; +import { bench, run } from "../runner.mjs"; + +const reactElement = React.createElement( + "body", + null, + React.createElement("div", null, React.createElement("address", null, "hi")), +); + +bench("ReactDOM.renderToReadableStream", async () => { + const stream = await renderToReadableStream(reactElement); + await stream.allReady; + + const reader = stream.getReader(); + while (true) { + const { value, done } = await reader.read(); + + if (done) { + break; + } + } +}); + +bench("ReadableStream (3 reads)", async () => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue("Hello"); + }, + pull(controller) { + controller.enqueue("World"); + + controller.close(); + }, + }); + + const reader = stream.getReader(); + + var { value, done } = await reader.read(); + ({ value, done } = await reader.read()); + ({ value, done } = await reader.read()); + + if (!done) { + throw new Error("failed"); + } +}); + +bench("ReadableStream (1 read -> 1 pull) x 32 * 1024 ", async () => { + let next = Promise.withResolvers(); + let remaining = 32 * 1024; + const stream = new ReadableStream({ + pull(controller) { + next = Promise.withResolvers(); + controller.enqueue("Hello"); + next.resolve(); + if (remaining-- === 0) { + controller.close(); + } + }, + }); + + const reader = stream.getReader(); + + while (true) { + var { value, done } = await reader.read(); + if (done) { + break; + } + await next.promise; + } +}); +{ + let next = Promise.withResolvers(); + + const stream = new ReadableStream({ + pull(controller) { + next = Promise.withResolvers(); + next.resolve(); + controller.enqueue("Hello"); + }, + }); + + const reader = stream.getReader(); + bench("ReadableStream (1 read -> 1 pull) same instance x 10 times ", async () => { + for (let i = 0; i < 10; i++) { + var { value, done } = await reader.read(); + await next.promise; + } + }); +} +await run(); diff --git a/src/bun.js/bindings/BunPromiseInlines.h b/src/bun.js/bindings/BunPromiseInlines.h new file mode 100644 index 00000000000000..f8818124f318bf --- /dev/null +++ b/src/bun.js/bindings/BunPromiseInlines.h @@ -0,0 +1,12 @@ +#pragma once + +namespace Bun { + +static inline JSC::JSPromise* createFulfilledPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value) +{ + JSC::JSPromise* promise = JSC::JSPromise::create(globalObject->vm(), globalObject->promiseStructure()); + promise->fulfill(globalObject, value); + return promise; +} + +} diff --git a/src/bun.js/bindings/BunReadableStream.cpp b/src/bun.js/bindings/BunReadableStream.cpp new file mode 100644 index 00000000000000..c73b74045481e9 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStream.cpp @@ -0,0 +1,380 @@ +#include "root.h" + +#include +#include +#include "JavaScriptCore/JSCast.h" +#include +#include + +#include +#include "BunStreamInlines.h" +#include "BunTeeState.h" +#include "JSAbortSignal.h" + +#include +#include +#include +#include +#include "BunReadableStreamPipeToOperation.h" + +#include "BunReadableStreamDefaultReader.h" +#include "BunReadableStreamBYOBReader.h" +#include "BunWritableStream.h" +#include "BunWritableStreamDefaultWriter.h" +#include "BunReadableStream.h" +#include "BunReadableStreamDefaultController.h" + +#include "BunPromiseInlines.h" +#include + +namespace Bun { + +using namespace JSC; + +JSC::GCClient::IsoSubspace* JSReadableStream::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForReadableStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStream = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForReadableStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStream = std::forward(space); }); +} + +JSReadableStreamDefaultReader* JSReadableStream::reader() const +{ + return jsCast(m_reader.get()); +} + +JSReadableStreamDefaultController* JSReadableStream::controller() const +{ + return jsCast(m_controller.get()); +} + +JSValue JSReadableStream::getReader(VM& vm, JSGlobalObject* globalObject, JSValue options) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (locked()) { + throwTypeError(globalObject, scope, "ReadableStream is locked"_s); + return {}; + } + + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + + if (!options.isUndefined()) { + JSObject* optionsObject = options.toObject(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + JSValue mode = optionsObject->get(globalObject, Identifier::fromString(vm, "mode"_s)); + RETURN_IF_EXCEPTION(scope, {}); + + if (mode.getString(globalObject) == "byob"_s) { + auto* controller = jsCast(m_controller.get()); + if (!controller || !controller->isByteController()) { + throwTypeError(globalObject, scope, "Cannot get a BYOB reader for a non-byte stream"_s); + return {}; + } + + Structure* readerStructure = streams.structure(domGlobalObject); + auto* reader = JSReadableStreamBYOBReader::create(vm, globalObject, readerStructure, this); + m_reader.set(vm, this, reader); + return reader; + } + } + + Structure* readerStructure = streams.structure(domGlobalObject); + auto* reader = JSReadableStreamDefaultReader::create(vm, globalObject, readerStructure, this); + m_reader.set(vm, this, reader); + return reader; +} + +JSPromise* JSReadableStream::cancel(VM& vm, JSGlobalObject* globalObject, JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (locked()) { + throwTypeError(globalObject, scope, "ReadableStream is locked"_s); + return nullptr; + } + + if (m_state == State::Closed) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + if (m_state == State::Errored) { + return JSPromise::rejectedPromise(globalObject, storedError()); + } + + m_disturbed = true; + + if (!m_controller) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + auto* controller = this->controller(); + JSObject* cancelAlgorithm = controller->cancelAlgorithm(); + m_controller.clear(); + if (!cancelAlgorithm) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + JSC::CallData callData = JSC::getCallData(cancelAlgorithm); + + if (callData.type == JSC::CallData::Type::None) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + MarkedArgumentBuffer args; + args.append(reason); + JSValue result = JSC::profiledCall(globalObject, ProfilingReason::API, cancelAlgorithm, callData, controller->underlyingSource(), args); + + RETURN_IF_EXCEPTION(scope, nullptr); + + if (auto* promise = jsDynamicCast(result)) + return promise; + + return Bun::createFulfilledPromise(globalObject, result); +} + +JSPromise* JSReadableStream::pipeTo(VM& vm, JSGlobalObject* globalObject, JSObject* destination, JSValue options) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!destination) { + throwTypeError(globalObject, scope, "Destination must be a WritableStream"_s); + return nullptr; + } + + JSWritableStream* writableStream = jsDynamicCast(destination); + if (!writableStream) { + throwTypeError(globalObject, scope, "Destination must be a WritableStream"_s); + return nullptr; + } + + if (locked() || writableStream->isLocked()) { + throwTypeError(globalObject, scope, "Cannot pipe to/from a locked stream"_s); + return nullptr; + } + + bool preventClose [[maybe_unused]] = false; + bool preventAbort [[maybe_unused]] = false; + bool preventCancel [[maybe_unused]] = false; + JSObject* signal [[maybe_unused]] = nullptr; + + if (!options.isUndefined()) { + JSObject* optionsObject = options.toObject(globalObject); + RETURN_IF_EXCEPTION(scope, nullptr); + + JSValue preventCloseValue = optionsObject->get(globalObject, Identifier::fromString(vm, "preventClose"_s)); + RETURN_IF_EXCEPTION(scope, nullptr); + preventClose = preventCloseValue.toBoolean(globalObject); + RETURN_IF_EXCEPTION(scope, nullptr); + + JSValue preventAbortValue = optionsObject->get(globalObject, Identifier::fromString(vm, "preventAbort"_s)); + RETURN_IF_EXCEPTION(scope, nullptr); + preventAbort = preventAbortValue.toBoolean(globalObject); + RETURN_IF_EXCEPTION(scope, nullptr); + + JSValue preventCancelValue = optionsObject->get(globalObject, Identifier::fromString(vm, "preventCancel"_s)); + RETURN_IF_EXCEPTION(scope, nullptr); + preventCancel = preventCancelValue.toBoolean(globalObject); + RETURN_IF_EXCEPTION(scope, nullptr); + + JSValue signalValue = optionsObject->get(globalObject, Identifier::fromString(vm, "signal"_s)); + RETURN_IF_EXCEPTION(scope, nullptr); + if (!signalValue.isUndefined()) { + signal = signalValue.toObject(globalObject); + if (!signal) { + throwTypeError(globalObject, scope, "Signal must be an object"_s); + return nullptr; + } + } + } + + m_disturbed = true; + + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + auto* reader = JSReadableStreamDefaultReader::create(vm, globalObject, streams.structure(domGlobalObject), this); + m_reader.set(vm, this, reader); + + auto* writer [[maybe_unused]] = JSWritableStreamDefaultWriter::create(vm, streams.structure(domGlobalObject), writableStream); + JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure()); + + // auto* pipeToOperation = PipeToOperation::create(vm, globalObject, reader, writer, preventClose, preventAbort, preventCancel, signal, promise); + // pipeToOperation->perform(vm, globalObject); + // promise->reject(globalObject, ) + + return promise; +} + +JSValue JSReadableStream::pipeThrough(VM& vm, JSGlobalObject* globalObject, JSObject* transform, JSValue options) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!transform) { + throwTypeError(globalObject, scope, "Transform must be an object"_s); + return {}; + } + + JSValue readableValue = transform->get(globalObject, Identifier::fromString(vm, "readable"_s)); + RETURN_IF_EXCEPTION(scope, {}); + + JSValue writableValue = transform->get(globalObject, Identifier::fromString(vm, "writable"_s)); + RETURN_IF_EXCEPTION(scope, {}); + + JSReadableStream* readable = jsDynamicCast(readableValue); + if (UNLIKELY(!readable)) { + throwTypeError(globalObject, scope, "Transform must have readable property that is a stream"_s); + return {}; + } + + JSWritableStream* writable = jsDynamicCast(writableValue); + if (UNLIKELY(!writable)) { + throwTypeError(globalObject, scope, "Transform must have writable property that is a stream"_s); + return {}; + } + + JSPromise* pipePromise = pipeTo(vm, globalObject, jsCast(writable), options); + RETURN_IF_EXCEPTION(scope, {}); + + // We don't want to expose the pipeTo promise to user code + pipePromise->markAsHandled(globalObject); + + return readable; +} + +void JSReadableStream::tee(VM& vm, JSGlobalObject* globalObject, JSValue& firstStream, JSValue& secondStream) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (locked()) { + throwTypeError(globalObject, scope, "ReadableStream is locked"_s); + return; + } + + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + + if (m_state == State::Errored) { + auto* error = m_storedError.get(); + Structure* streamStructure = streams.structure(domGlobalObject); + auto* stream1 = JSReadableStream::create(vm, globalObject, streamStructure); + auto* stream2 = JSReadableStream::create(vm, globalObject, streamStructure); + stream1->error(globalObject, error); + stream2->error(globalObject, error); + firstStream = stream1; + secondStream = stream2; + return; + } + + m_disturbed = true; + + auto* reader = JSReadableStreamDefaultReader::create(vm, globalObject, streams.structure(domGlobalObject), this); + m_reader.set(vm, this, reader); + + Structure* streamStructure = streams.structure(domGlobalObject); + auto* branch1 = JSReadableStream::create(vm, globalObject, streamStructure); + auto* branch2 = JSReadableStream::create(vm, globalObject, streamStructure); + + firstStream = branch1; + secondStream = branch2; + + TeeState* teeState = TeeState::create(vm, globalObject, reader, branch1, branch2); + teeState->perform(vm, globalObject); +} + +const ClassInfo JSReadableStream::s_info = { "ReadableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStream) }; + +template +void JSReadableStream::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + thisObject->visitAdditionalChildren(visitor); +} + +template +void JSReadableStream::visitAdditionalChildren(Visitor& visitor) +{ + visitor.append(m_reader); + visitor.append(m_controller); + visitor.append(m_storedError); +} + +template +void JSReadableStream::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + Base::visitOutputConstraints(cell, visitor); + + thisObject->visitAdditionalChildren(visitor); +} + +DEFINE_VISIT_CHILDREN(JSReadableStream); +DEFINE_VISIT_ADDITIONAL_CHILDREN(JSReadableStream); +DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSReadableStream); + +bool JSReadableStream::isLocked() const +{ + return locked(); +} + +JSReadableStream* JSReadableStream::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSReadableStream* stream = new (NotNull, allocateCell(vm)) JSReadableStream(vm, structure); + stream->finishCreation(vm); + return stream; +} + +JSReadableStream::JSReadableStream(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSReadableStream::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + m_state = State::Readable; + m_disturbed = false; + m_reader.clear(); + m_controller.clear(); + m_storedError.clear(); +} + +void JSReadableStream::setController(JSC::VM& vm, JSReadableStreamDefaultController* controller) +{ + m_controller.set(vm, this, controller); +} + +Structure* JSReadableStream::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); +} + +void JSReadableStream::close(JSGlobalObject* globalObject) +{ + m_state = State::Closed; + if (auto* reader = this->reader()) + reader->closedPromise()->fulfill(globalObject, jsUndefined()); +} + +void JSReadableStream::error(JSGlobalObject* globalObject, JSValue error) +{ + VM& vm = globalObject->vm(); + m_state = State::Errored; + m_storedError.set(vm, this, error.toObject(globalObject)); + if (auto* reader = this->reader()) + reader->closedPromise()->reject(globalObject, error); +} + +void JSReadableStream::setReader(JSC::VM& vm, JSReadableStreamDefaultReader* reader) +{ + if (reader) { + m_reader.set(vm, this, reader); + } else { + m_reader.clear(); + } +} + +} diff --git a/src/bun.js/bindings/BunReadableStream.h b/src/bun.js/bindings/BunReadableStream.h new file mode 100644 index 00000000000000..2a599b50e36b55 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStream.h @@ -0,0 +1,79 @@ +#pragma once + +#include "root.h" +#include +#include +#include + +namespace Bun { +class JSReadableStreamDefaultController; +class JSReadableStreamDefaultReader; +class JSReadableStreamPrototype; +class JSReadableStreamConstructor; + +using namespace JSC; + +class JSReadableStream final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + static JSReadableStream* create(JSC::VM&, JSC::JSGlobalObject*, JSC::Structure*); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue prototype); + + enum class State { + Readable, + Closed, + Errored, + }; + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + DECLARE_VISIT_OUTPUT_CONSTRAINTS; + + template + void visitAdditionalChildren(Visitor& visitor); + + // Public API for C++ usage + bool isLocked() const; + bool isDisturbed() const { return m_disturbed; } + + JSReadableStreamDefaultController* controller() const; + JSReadableStreamDefaultReader* reader() const; + + bool locked() const { return !!m_reader; } + JSC::JSValue getReader(VM&, JSGlobalObject*, JSValue options = jsUndefined()); + JSC::JSPromise* cancel(VM&, JSGlobalObject*, JSValue reason = jsUndefined()); + JSC::JSPromise* pipeTo(VM&, JSGlobalObject*, JSObject* destination, JSValue options = jsUndefined()); + JSC::JSValue pipeThrough(VM&, JSGlobalObject*, JSObject* transform, JSValue options = jsUndefined()); + void tee(VM&, JSGlobalObject*, JSValue& firstStream, JSValue& secondStream); + + void error(JSGlobalObject*, JSValue); + void close(JSGlobalObject*); + void setReader(JSC::VM& vm, JSReadableStreamDefaultReader*); + void setController(JSC::VM& vm, JSReadableStreamDefaultController*); + State state() const { return m_state; } + JSValue storedError() const { return m_storedError.get(); } + +private: + JSReadableStream(VM&, Structure*); + void finishCreation(VM&); + + mutable JSC::WriteBarrier m_controller; + mutable JSC::WriteBarrier m_reader; + mutable JSC::WriteBarrier m_storedError; + + State m_state { State::Readable }; + bool m_disturbed { false }; +}; + +} diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReader.cpp b/src/bun.js/bindings/BunReadableStreamBYOBReader.cpp new file mode 100644 index 00000000000000..ef2c86b8cf80f9 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReader.cpp @@ -0,0 +1,137 @@ +#include "root.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "BunReadableStreamBYOBReader.h" +#include "BunReadableStream.h" +#include "BunReadableStreamDefaultController.h" +#include "BunReadableStreamDefaultReader.h" +#include "BunStreamInlines.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamBYOBReader::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReader) }; + +JSReadableStreamBYOBReader::JSReadableStreamBYOBReader(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSReadableStreamBYOBReader::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +JSReadableStreamBYOBReader* JSReadableStreamBYOBReader::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSReadableStream* stream) +{ + JSReadableStreamBYOBReader* reader = new (NotNull, allocateCell(vm)) JSReadableStreamBYOBReader(vm, structure); + reader->finishCreation(vm); + reader->setStream(vm, stream); + reader->setReadRequests(vm, constructEmptyArray(globalObject, nullptr)); + reader->setClosedPromise(vm, JSPromise::create(vm, globalObject->promiseStructure())); + reader->setReadyPromise(vm, JSPromise::create(vm, globalObject->promiseStructure())); + return reader; +} + +template +void JSReadableStreamBYOBReader::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSReadableStreamBYOBReader* thisObject = jsCast(cell); + ASSERT(thisObject->inherits(JSReadableStreamBYOBReader::info())); + Base::visitChildren(thisObject, visitor); + + visitor.append(thisObject->m_stream); + visitor.append(thisObject->m_readRequests); + visitor.append(thisObject->m_closedPromise); + visitor.append(thisObject->m_readyPromise); +} + +DEFINE_VISIT_CHILDREN(JSReadableStreamBYOBReader); + +JSValue JSReadableStreamBYOBReader::read(VM& vm, JSGlobalObject* globalObject, JSArrayBufferView* view, uint64_t minRequested) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 5. Check if view's buffer is detached + if (view->isDetached()) { + throwVMTypeError(globalObject, scope, "Cannot read into a detached ArrayBuffer"_s); + return {}; + } + + // 6. Check view's byte length + if (view->byteLength() == 0) { + throwVMTypeError(globalObject, scope, "Cannot read into a zero-length view"_s); + return {}; + } + + // 8. Create a new promise for the read result + JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure()); + + // 9. Create a read-into request + JSObject* readIntoRequest = constructEmptyObject(globalObject); + readIntoRequest->putDirect(vm, Identifier::fromString(vm, "promise"_s), promise); + readIntoRequest->putDirect(vm, Identifier::fromString(vm, "view"_s), view); + readIntoRequest->putDirect(vm, Identifier::fromString(vm, "min"_s), jsNumber(minRequested)); + + // 10. Add to read requests queue + JSArray* readRequests = this->readRequests(); + readRequests->push(globalObject, readIntoRequest); + RETURN_IF_EXCEPTION(scope, {}); + + // 11. Return the promise + return promise; +} + +void JSReadableStreamBYOBReader::releaseLock(VM& vm, JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!stream()) + return; + + auto* readRequests = this->readRequests(); + if (readRequests->length() > 0) { + for (unsigned i = 0; i < readRequests->length(); ++i) { + auto* request = jsCast(readRequests->get(globalObject, i)); + auto* promise = jsCast(request->get(globalObject, Identifier::fromString(vm, "promise"_s))); + promise->reject(globalObject, createTypeError(globalObject, "Reader was released"_s)); + } + } + + if (stream()) { + stream()->setReader(vm, nullptr); + clearStream(); + } + closedPromise()->reject(globalObject, createTypeError(globalObject, "Reader was released"_s)); +} + +JSValue JSReadableStreamBYOBReader::cancel(VM& vm, JSGlobalObject* globalObject, JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!stream()) + return throwTypeError(globalObject, scope, "Cannot cancel a released reader"_s); + + return stream()->cancel(vm, globalObject, reason); +} + +JSC::GCClient::IsoSubspace* JSReadableStreamBYOBReader::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamBYOBReader.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamBYOBReader = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForReadableStreamBYOBReader.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamBYOBReader = std::forward(space); }); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReader.h b/src/bun.js/bindings/BunReadableStreamBYOBReader.h new file mode 100644 index 00000000000000..5ba29c27b521b1 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReader.h @@ -0,0 +1,66 @@ +#pragma once + +#include "root.h" +#include +#include +#include +#include +#include +#include + +namespace Bun { + +class JSReadableStream; + +class JSReadableStreamBYOBReader : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static constexpr bool needsDestruction = false; + + template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + static JSReadableStreamBYOBReader* create(JSC::VM&, JSC::JSGlobalObject*, JSC::Structure*, JSReadableStream*); + 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()); + } + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + static constexpr unsigned StructureFlags = Base::StructureFlags; + + JSReadableStream* stream() const { return m_stream.get(); } + JSC::JSPromise* closedPromise() const { return m_closedPromise.get(); } + JSC::JSPromise* readyPromise() const { return m_readyPromise.get(); } + JSC::JSArray* readRequests() const { return m_readRequests.get(); } + + void setStream(JSC::VM& vm, JSReadableStream* stream) { m_stream.set(vm, this, stream); } + void setClosedPromise(JSC::VM& vm, JSC::JSPromise* promise) { m_closedPromise.set(vm, this, promise); } + void setReadyPromise(JSC::VM& vm, JSC::JSPromise* promise) { m_readyPromise.set(vm, this, promise); } + void setReadRequests(JSC::VM& vm, JSC::JSArray* requests) { m_readRequests.set(vm, this, requests); } + + void clearStream() { m_stream.clear(); } + + JSC::JSValue read(JSC::VM&, JSC::JSGlobalObject*, JSC::JSArrayBufferView*, uint64_t minRequested = 1); + void releaseLock(JSC::VM&, JSC::JSGlobalObject*); + JSC::JSValue cancel(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue reason); + +protected: + JSReadableStreamBYOBReader(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&); + +private: + JSC::WriteBarrier m_stream; + JSC::WriteBarrier m_closedPromise; + JSC::WriteBarrier m_readyPromise; + JSC::WriteBarrier m_readRequests; +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.cpp b/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.cpp new file mode 100644 index 00000000000000..8e97046df34476 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.cpp @@ -0,0 +1,46 @@ +#include "root.h" + +#include "BunReadableStreamBYOBReaderConstructor.h" +#include "BunReadableStreamBYOBReader.h" +#include "BunReadableStream.h" +#include "JavaScriptCore/InternalFunction.h" +#include +#include +#include + +#include "JSDOMConstructorBase.h" +#include "JSDOMConstructorNotConstructable.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamBYOBReaderConstructor::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReaderConstructor) }; + +JSReadableStreamBYOBReaderConstructor::JSReadableStreamBYOBReaderConstructor(VM& vm, Structure* structure) + : Base(vm, structure, WebCore::callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable, WebCore::callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable) +{ +} + +void JSReadableStreamBYOBReaderConstructor::finishCreation(VM& vm, JSObject* prototype) +{ + Base::finishCreation(vm, 1, "ReadableStreamBYOBReader"_s, InternalFunction::PropertyAdditionMode::WithStructureTransition); + ASSERT(inherits(info())); + + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSReadableStreamBYOBReaderConstructor* JSReadableStreamBYOBReaderConstructor::create(VM& vm, JSGlobalObject* globalObject, JSObject* prototype) +{ + auto* structure = createStructure(vm, globalObject, prototype); + JSReadableStreamBYOBReaderConstructor* constructor = new (NotNull, allocateCell(vm)) JSReadableStreamBYOBReaderConstructor(vm, structure); + constructor->finishCreation(vm, prototype); + return constructor; +} + +Structure* JSReadableStreamBYOBReaderConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.h b/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.h new file mode 100644 index 00000000000000..ab34c8596c4f37 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReaderConstructor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "root.h" +#include +#include + +namespace Bun { + +class JSReadableStreamBYOBReaderConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + static JSReadableStreamBYOBReaderConstructor* create(JSC::VM&, JSC::JSGlobalObject*, JSObject* prototype); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue prototype); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + DECLARE_INFO; + +private: + JSReadableStreamBYOBReaderConstructor(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSObject* prototype); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.cpp b/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.cpp new file mode 100644 index 00000000000000..1b98223dc2128f --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.cpp @@ -0,0 +1,166 @@ +#include "root.h" + +#include "BunReadableStreamBYOBReaderPrototype.h" +#include "BunReadableStreamBYOBReader.h" +#include "BunReadableStream.h" +#include "ZigGlobalObject.h" + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamBYOBReaderClosedGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamBYOBReaderConstructor); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamBYOBReaderRead); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamBYOBReaderReleaseLock); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamBYOBReaderCancel); + +/* Hash table for prototype */ + +static const HashTableValue JSReadableStreamBYOBReaderPrototypeTableValues[] = { + { "closed"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamBYOBReaderClosedGetter, 0 } }, + { "read"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamBYOBReaderRead, 0 } }, + { "cancel"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamBYOBReaderCancel, 0 } }, + { "releaseLock"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamBYOBReaderReleaseLock, 0 } }, +}; + +const ClassInfo JSReadableStreamBYOBReaderPrototype::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReaderPrototype) }; + +JSReadableStreamBYOBReaderPrototype* JSReadableStreamBYOBReaderPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + auto* prototype = new (NotNull, allocateCell(vm)) JSReadableStreamBYOBReaderPrototype(vm, structure); + prototype->finishCreation(vm); + return prototype; +} + +Structure* JSReadableStreamBYOBReaderPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); +} + +JSReadableStreamBYOBReaderPrototype::JSReadableStreamBYOBReaderPrototype(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSReadableStreamBYOBReaderPrototype::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + reifyStaticProperties(vm, info(), JSReadableStreamBYOBReaderPrototypeTableValues, *this); + this->structure()->setMayBePrototype(true); +} + +JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamBYOBReaderClosedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + auto* reader = jsDynamicCast(JSValue::decode(thisValue)); + if (!reader) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.closed called on incompatible receiver"_s); + return JSValue::encode(reader->closedPromise()); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamBYOBReaderRead, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Validate the reader + auto* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.read called on incompatible receiver"_s); + + // 2. Check if stream is undefined (released) + if (!reader->stream()) + return throwVMTypeError(globalObject, scope, "Cannot read from a released reader"_s); + + // 3. Validate view argument + if (!callFrame->argumentCount()) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.read requires at least one argument"_s); + + JSValue viewValue = callFrame->argument(0); + if (!viewValue.isObject()) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.read requires an ArrayBufferView argument"_s); + + // 4. Get the ArrayBufferView + JSArrayBufferView* view = jsDynamicCast(viewValue); + if (!view) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.read requires an ArrayBufferView argument"_s); + + // 7. Get read options + uint64_t minRequested = 1; + if (callFrame->argumentCount() > 1) { + JSValue options = callFrame->argument(1); + if (!options.isUndefined()) { + if (!options.isObject()) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader read options must be an object"_s); + + JSObject* optionsObj = jsCast(options); + JSValue minValue = optionsObj->get(globalObject, Identifier::fromString(vm, "min"_s)); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (!minValue.isUndefined()) { + minRequested = minValue.toNumber(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (minRequested == 0) + return throwVMTypeError(globalObject, scope, "min option must be greater than 0"_s); + + if (minRequested > view->byteLength()) + return throwVMRangeError(globalObject, scope, "min option cannot be greater than view's byte length"_s); + } + } + } + + return JSValue::encode(reader->read(vm, globalObject, view, minRequested)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamBYOBReaderReleaseLock, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Validate the reader + auto* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.releaseLock called on incompatible receiver"_s); + + reader->releaseLock(vm, globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamBYOBReaderCancel, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Validate the reader + auto* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) + return throwVMTypeError(globalObject, scope, "ReadableStreamBYOBReader.prototype.cancel called on incompatible receiver"_s); + + // 2. Check if stream is undefined (released) + JSReadableStream* stream = reader->stream(); + if (!stream) + return throwVMTypeError(globalObject, scope, "Cannot cancel a released reader"_s); + + // 3. Get cancel reason + JSValue reason = callFrame->argument(0); + + // 4. Cancel the stream with the given reason + JSPromise* promise = stream->cancel(vm, globalObject, reason); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + return JSValue::encode(promise); +} + +JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamBYOBReaderConstructor, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return JSValue::encode(defaultGlobalObject(globalObject)->streams().constructor(globalObject)); +} +} diff --git a/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.h b/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.h new file mode 100644 index 00000000000000..47e60fda26cf01 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamBYOBReaderPrototype.h @@ -0,0 +1,30 @@ +#pragma once + +#include "root.h" +#include +#include + +namespace Bun { + +class JSReadableStreamBYOBReaderPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + static JSReadableStreamBYOBReaderPrototype* create(JSC::VM&, JSC::JSGlobalObject*, JSC::Structure*); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue prototype); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.plainObjectSpace(); + } + + DECLARE_INFO; + +private: + JSReadableStreamBYOBReaderPrototype(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamConstructor.cpp b/src/bun.js/bindings/BunReadableStreamConstructor.cpp new file mode 100644 index 00000000000000..7a74132c3760f9 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamConstructor.cpp @@ -0,0 +1,175 @@ +#include "root.h" + +#include "BunReadableStreamConstructor.h" +#include "BunReadableStream.h" +#include +#include +#include "ZigGlobalObject.h" +#include +#include "ErrorCode.h" +#include "BunReadableStreamDefaultController.h" +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamConstructor) }; + +JSReadableStreamConstructor* JSReadableStreamConstructor::create(VM& vm, JSGlobalObject* globalObject, JSObject* prototype) +{ + auto* structure = createStructure(vm, globalObject, prototype); + auto* constructor = new (NotNull, allocateCell(vm)) JSReadableStreamConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +Structure* JSReadableStreamConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info()); +} + +JSReadableStreamConstructor::JSReadableStreamConstructor(VM& vm, Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +void JSReadableStreamConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSObject* prototype) +{ + Base::finishCreation(vm, 1, "ReadableStream"_s, PropertyAdditionMode::WithStructureTransition); + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSReadableStreamConstructor::construct(JSGlobalObject* globalObject, CallFrame* callFrame) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* zigGlobalObject = defaultGlobalObject(globalObject); + + JSObject* newTarget = asObject(callFrame->newTarget()); + auto& streams = zigGlobalObject->streams(); + Structure* structure = streams.structure(globalObject); + + auto* constructor = streams.constructor(globalObject); + + if (!(!newTarget || newTarget != constructor)) { + if (newTarget) { + structure = JSC::InternalFunction::createSubclassStructure(getFunctionRealm(globalObject, newTarget), newTarget, structure); + } else { + structure = JSC::InternalFunction::createSubclassStructure(globalObject, constructor, structure); + } + } + + JSValue underlyingSourceDict = callFrame->argument(0); + JSObject* underlyingSourceObj = nullptr; + + if (!underlyingSourceDict.isUndefined() && !underlyingSourceDict.isNull()) { + underlyingSourceObj = underlyingSourceDict.getObject(); + if (!underlyingSourceObj) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "underlyingSource must be an object or undefined"_s); + return {}; + } + } + + double highWaterMark = 1; + JSObject* startFunction = nullptr; + JSC::CallData startCallData; + JSObject* pullFunction = nullptr; + JSObject* cancelFunction = nullptr; + JSObject* sizeFunction = nullptr; + bool isBYOB = false; + auto& builtinNames = WebCore::builtinNames(vm); + + if (underlyingSourceObj) { + JSValue typeValue = underlyingSourceObj->getIfPropertyExists(globalObject, vm.propertyNames->type); + RETURN_IF_EXCEPTION(scope, {}); + + if (typeValue && !typeValue.isNull() && !typeValue.isUndefined()) { + if (!typeValue.isString()) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "ReadableStream 'type' must be a string or undefined"_s); + return {}; + } + + auto typeString = typeValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + + if (typeString == "byob"_s) { + isBYOB = true; + } + } + + JSValue startValue = underlyingSourceObj->getIfPropertyExists(globalObject, builtinNames.startPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + + if (startValue && !startValue.isNull() && !startValue.isUndefined()) { + startFunction = startValue.getObject(); + if (!startFunction) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "ReadableStream 'start' must be a function or undefined"_s); + return {}; + } + startCallData = JSC::getCallData(startFunction); + + if (startCallData.type == CallData::Type::None) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "ReadableStream 'start' must be a function or undefined"_s); + return {}; + } + } + + JSValue pullValue = underlyingSourceObj->getIfPropertyExists(globalObject, builtinNames.pullPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + + if (pullValue && !pullValue.isNull() && !pullValue.isUndefined()) { + pullFunction = pullValue.getObject(); + + if (!pullFunction || !pullFunction->isCallable()) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "ReadableStream 'pull' must be a function or undefined"_s); + return {}; + } + } + + JSValue cancelValue = underlyingSourceObj->getIfPropertyExists(globalObject, builtinNames.cancelPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + + if (cancelValue && !cancelValue.isNull() && !cancelValue.isUndefined()) { + cancelFunction = cancelValue.getObject(); + + if (!cancelFunction || !cancelFunction->isCallable()) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "ReadableStream 'cancel' must be a function or undefined"_s); + return {}; + } + } + + JSValue sizeValue = underlyingSourceObj->getIfPropertyExists(globalObject, vm.propertyNames->size); + RETURN_IF_EXCEPTION(scope, {}); + + if (sizeValue && !sizeValue.isNull() && !sizeValue.isUndefined()) { + sizeFunction = sizeValue.getObject(); + } + } + + if (isBYOB) { + // TODO: Implement BYOB + scope.throwException(globalObject, JSC::createTypeError(globalObject, "BYOB ReadableStream is not implemented"_s)); + return {}; + } + + auto* stream = JSReadableStream::create(vm, globalObject, structure); + RETURN_IF_EXCEPTION(scope, {}); + + JSReadableStreamDefaultController* controller = JSReadableStreamDefaultController::create(vm, globalObject, streams.structure(globalObject), stream); + RETURN_IF_EXCEPTION(scope, {}); + stream->setController(vm, controller); + + controller->setup(vm, globalObject, stream, underlyingSourceObj, startFunction, pullFunction, cancelFunction, highWaterMark, sizeFunction); + + return JSValue::encode(stream); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSReadableStreamConstructor::call(JSGlobalObject* globalObject, CallFrame* callFrame) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + return throwVMTypeError(globalObject, scope, "ReadableStream constructor cannot be called without 'new'"_s); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamConstructor.h b/src/bun.js/bindings/BunReadableStreamConstructor.h new file mode 100644 index 00000000000000..6ce942a87e6d8b --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamConstructor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "root.h" +#include +#include +#include +#include + +namespace Bun { + +using namespace JSC; + +class JSReadableStreamConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + static JSReadableStreamConstructor* create(VM&, JSGlobalObject*, JSObject*); + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(VM& vm) + { + return &vm.internalFunctionSpace(); + } + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSGlobalObject*, CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSGlobalObject*, CallFrame*); + +private: + JSReadableStreamConstructor(VM& vm, Structure* structure); + void finishCreation(VM& vm, JSGlobalObject* globalObject, JSObject* prototype); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultController.cpp b/src/bun.js/bindings/BunReadableStreamDefaultController.cpp new file mode 100644 index 00000000000000..c4ccb3a6310ab2 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultController.cpp @@ -0,0 +1,402 @@ + +#include "JavaScriptCore/SlotVisitorMacros.h" +#include "root.h" + +#include "JavaScriptCore/IteratorOperations.h" +#include "BunReadableStreamDefaultController.h" +#include +#include +#include +#include "BunReadableStream.h" +#include +#include +#include "BunReadableStreamDefaultReader.h" +#include "DOMIsoSubspaces.h" +#include "BunClientData.h" +#include "BunStreamStructures.h" +#include "DOMClientIsoSubspaces.h" +#include +#include + +#include "BunStreamInlines.h" +#include "wtf/Assertions.h" +namespace Bun { + +using namespace JSC; + +template +JSC::GCClient::IsoSubspace* JSReadableStreamDefaultController::subspaceFor(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForJSReadableStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSReadableStreamDefaultController = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForJSReadableStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForJSReadableStreamDefaultController = std::forward(space); }); +} + +JSReadableStreamDefaultController::JSReadableStreamDefaultController(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +template +void JSReadableStreamDefaultController::visitChildrenImpl(JSC::JSCell* cell, Visitor& visitor) +{ + auto* thisObject = static_cast(cell); + Base::visitChildren(cell, visitor); + + thisObject->visitAdditionalChildren(visitor); +} + +template +void JSReadableStreamDefaultController::visitAdditionalChildren(Visitor& visitor) +{ + visitor.append(m_underlyingSource); + visitor.append(m_pullAlgorithm); + visitor.append(m_cancelAlgorithm); + visitor.append(m_stream); + m_queue.visit(this, visitor); +} + +template +void JSReadableStreamDefaultController::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + Base::visitOutputConstraints(cell, visitor); + + thisObject->visitAdditionalChildren(visitor); +} + +DEFINE_VISIT_CHILDREN(JSReadableStreamDefaultController); +DEFINE_VISIT_ADDITIONAL_CHILDREN(JSReadableStreamDefaultController); +DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSReadableStreamDefaultController); + +JSReadableStreamDefaultController* JSReadableStreamDefaultController::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSReadableStream* stream) +{ + JSReadableStreamDefaultController* controller = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultController(vm, structure); + controller->finishCreation(vm, stream); + return controller; +} + +JSReadableStream* JSReadableStreamDefaultController::stream() const +{ + return jsDynamicCast(m_stream.get()); +} + +JSValue JSReadableStreamDefaultController::desiredSizeValue() +{ + if (!canCloseOrEnqueue()) + return jsNull(); + + // According to spec, desiredSize = highWaterMark - queueTotalSize + return jsNumber(queue().desiredSize()); +} + +double JSReadableStreamDefaultController::desiredSize() const +{ + if (!canCloseOrEnqueue()) + return PNaN; + + return queue().desiredSize(); +} + +bool JSReadableStreamDefaultController::canCloseOrEnqueue() const +{ + // If closeRequested, we can no longer enqueue + if (m_closeRequested) + return false; + + // Get stream state + auto* stream = this->stream(); + ASSERT(stream); + + return stream->state() == JSReadableStream::State::Readable; +} + +void JSReadableStreamDefaultController::performPullSteps(VM& vm, JSGlobalObject* globalObject, JSPromise* readRequest) +{ + auto* stream = this->stream(); + ASSERT(stream); + + if (!this->queue().isEmpty()) { + // Let chunk be ! DequeueValue(this). + JSValue chunk = this->queue().dequeueValue(vm, globalObject, this); + ASSERT(!chunk.isEmpty()); + + // Perform readRequest’s chunk steps, given chunk. + readRequest->fulfill(globalObject, JSC::createIteratorResultObject(globalObject, chunk, false)); + return; + } + + if (m_closeRequested) { + // Perform ! ReadableStreamDefaultControllerClearAlgorithms(this). + this->clearAlgorithms(); + + // Perform ! ReadableStreamClose(stream). + stream->close(globalObject); + + readRequest->fulfill(globalObject, createIteratorResultObject(globalObject, jsUndefined(), true)); + return; + } + + stream->reader()->addReadRequest(vm, globalObject, readRequest); + + // Otherwise, perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this). + this->callPullIfNeeded(globalObject); +} + +JSValue JSReadableStreamDefaultController::enqueue(VM& vm, JSGlobalObject* globalObject, JSValue chunk) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!canCloseOrEnqueue()) + return throwTypeError(globalObject, scope, "Cannot enqueue chunk to closed stream"_s); + + if (auto* reader = stream()->reader()) { + if (!reader->isEmpty()) { + // Assert: ! ReadableStreamHasDefaultReader(stream) is true. + // 1. Let reader be stream.[[reader]]. + // 2. Assert: reader.[[readRequests]] is not empty. + // 3. Let readRequest be reader.[[readRequests]][0]. + JSPromise* readRequest = reader->takeFirst(vm, globalObject); + JSObject* result = JSC::createIteratorResultObject(globalObject, chunk, false); + readRequest->fulfill(globalObject, result); + callPullIfNeeded(globalObject); + return jsUndefined(); + } + } + + queue().enqueueValueAndGetSize(vm, globalObject, this, chunk); + RETURN_IF_EXCEPTION(scope, {}); + callPullIfNeeded(globalObject); + return jsUndefined(); +} + +void JSReadableStreamDefaultController::error(VM& vm, JSGlobalObject* globalObject, JSValue error) +{ + auto* stream = jsDynamicCast(m_stream.get()); + ASSERT(stream); + + if (stream->state() != JSReadableStream::State::Readable) + return; + + // Reset queue + queue().resetQueue(vm, globalObject, this); + + // Clear our algorithms so we stop executing them + clearAlgorithms(); + + stream->error(globalObject, error); +} + +void JSReadableStreamDefaultController::close(VM& vm, JSGlobalObject* globalObject) +{ + if (!canCloseOrEnqueue()) + return; + + auto* stream = this->stream(); + ASSERT(stream); + + m_closeRequested = true; + + // If queue is empty, we can close immediately + if (queue().isEmpty()) { + clearAlgorithms(); + stream->close(globalObject); + } +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamDefaultControllerFullfillPull, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSReadableStreamDefaultController* thisObject = jsDynamicCast(callFrame->argument(1)); + if (!thisObject) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.callPullIfNeeded called on incompatible object"_s); + + thisObject->fulfillPull(globalObject); + return JSValue::encode(jsUndefined()); +} + +void JSReadableStreamDefaultController::fulfillPull(JSGlobalObject* globalObject) +{ + m_pulling = false; + + // If pullAgain was set while we were pulling, pull again + if (m_pullAgain) { + m_pullAgain = false; + this->callPullIfNeeded(globalObject); + } +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamDefaultControllerRejectPull, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSReadableStreamDefaultController* thisObject = jsDynamicCast(callFrame->argument(1)); + if (!thisObject) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.rejectPull called on incompatible object"_s); + + thisObject->rejectPull(globalObject, callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +void JSReadableStreamDefaultController::rejectPull(JSGlobalObject* globalObject, JSValue error) +{ + m_pulling = false; + this->error(globalObject, error); +} + +void JSReadableStreamDefaultController::setup( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + Bun::JSReadableStream* stream, + JSC::JSObject* underlyingSource, + JSC::JSObject* startAlgorithm, + JSC::JSObject* pullAlgorithm, + JSC::JSObject* cancelAlgorithm, + double highWaterMark, + JSC::JSObject* sizeAlgorithm) +{ + queue().initialize(vm, globalObject, highWaterMark, this, sizeAlgorithm); + + if (pullAlgorithm) setPullAlgorithm(pullAlgorithm); + if (cancelAlgorithm) setCancelAlgorithm(cancelAlgorithm); + if (underlyingSource) setUnderlyingSource(underlyingSource); + + // 4. Set controller.[[started]], controller.[[closeRequested]], controller.[[pullAgain]], and controller.[[pulling]] to false. + m_started = false; + m_closeRequested = false; + m_pullAgain = false; + m_pulling = false; + + // Set stream's controller to this + stream->setController(vm, this); + + auto scope = DECLARE_THROW_SCOPE(vm); + + // Call start algorithm if provided + if (startAlgorithm) { + MarkedArgumentBuffer args; + args.append(this); + + auto callData = JSC::getCallData(startAlgorithm); + if (callData.type == JSC::CallData::Type::None) { + throwTypeError(globalObject, scope, "Start function is not callable"_s); + return; + } + + JSValue startResult = JSC::profiledCall(globalObject, ProfilingReason::API, startAlgorithm, callData, underlyingSource, args); + RETURN_IF_EXCEPTION(scope, ); + + // Handle promise fulfillment/rejection + if (startResult && !startResult.isUndefined()) { + if (JSPromise* promise = jsDynamicCast(startResult)) { + switch (promise->status(vm)) { + case JSPromise::Status::Fulfilled: + break; + case JSPromise::Status::Rejected: + this->error(globalObject, promise->result(vm)); + return; + case JSPromise::Status::Pending: + // We need to wait for the promise to resolve + ASSERT_NOT_REACHED_WITH_MESSAGE("TODO: handle pending start promise"); + return; + } + } + } + } + + m_started = true; + callPullIfNeeded(globalObject); +} + +void JSReadableStreamDefaultController::callPullIfNeeded(JSGlobalObject* globalObject) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // Return if we can't/shouldn't pull + if (!shouldCallPull()) + return; + + // Already pulling, flag to pull again when done + if (m_pulling) { + m_pullAgain = true; + return; + } + + // Call pull algorithm + JSObject* pullAlgorithm = m_pullAlgorithm.get(); + if (!pullAlgorithm) { + m_pulling = false; + m_pullAgain = false; + return; + } + + m_pulling = true; + + MarkedArgumentBuffer args; + args.append(this); + + EnsureStillAliveScope ensureStillAliveScope(this); + JSValue result = JSC::profiledCall(globalObject, ProfilingReason::API, pullAlgorithm, JSC::getCallData(pullAlgorithm), m_underlyingSource.get(), args); + if (scope.exception()) { + m_pulling = false; + // TODO: is there more we should do here? + return; + } + + // Handle the promise returned by pull + if (JSPromise* promise = jsDynamicCast(result)) { + Bun::then(globalObject, promise, jsReadableStreamDefaultControllerFullfillPull, jsReadableStreamDefaultControllerRejectPull, this); + } else { + // Not a promise, just mark pulling as done + m_pulling = false; + } +} + +bool JSReadableStreamDefaultController::shouldCallPull() const +{ + auto* stream = this->stream(); + ASSERT(stream); + + if (!m_started) + return false; + + if (stream->state() != JSReadableStream::State::Readable) + return false; + + if (m_closeRequested) + return false; + + auto* reader = stream->reader(); + // If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true. + if ((!stream->isLocked() || reader->isEmpty()) && desiredSize() <= 0) + return false; + + return true; +} + +void JSReadableStreamDefaultController::clearAlgorithms() +{ + // m_pullAlgorithm.clear(); + // m_cancelAlgorithm.clear(); + // m_underlyingSource.clear(); + + // queue().clearAlgorithms(); +} + +void JSReadableStreamDefaultController::finishCreation(VM& vm, JSReadableStream* stream) +{ + Base::finishCreation(vm); + m_stream.set(vm, this, stream); + m_pullAlgorithm.clear(); + m_cancelAlgorithm.clear(); + m_underlyingSource.clear(); + queue().resetQueue(vm, globalObject(), this); +} + +const ClassInfo JSReadableStreamDefaultController::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultController) }; +} diff --git a/src/bun.js/bindings/BunReadableStreamDefaultController.h b/src/bun.js/bindings/BunReadableStreamDefaultController.h new file mode 100644 index 00000000000000..c2138e42fa7632 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultController.h @@ -0,0 +1,115 @@ +#pragma once + +#include "root.h" +#include +#include +#include "JavaScriptCore/JSCast.h" +#include +#include "BunStreamQueue.h" + +namespace Bun { + +class JSReadableStream; + +class JSReadableStreamDefaultController final : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + static constexpr bool needsDestruction = true; + + static void destroy(JSC::JSCell* cell) + { + static_cast(cell)->~JSReadableStreamDefaultController(); + } + + ~JSReadableStreamDefaultController() + { + } + + static JSReadableStreamDefaultController* create(JSC::VM&, JSC::JSGlobalObject*, JSC::Structure*, JSReadableStream*); + 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()); + } + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + DECLARE_VISIT_OUTPUT_CONSTRAINTS; + + template + void visitAdditionalChildren(Visitor& visitor); + + void performPullSteps(JSC::VM&, JSC::JSGlobalObject*, JSC::JSPromise* readRequest); + + // SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm) performs the following steps: + void setup( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + Bun::JSReadableStream* stream, + JSC::JSObject* underlyingSource = nullptr, + JSC::JSObject* startAlgorithm = nullptr, + JSC::JSObject* pullAlgorithm = nullptr, + JSC::JSObject* cancelAlgorithm = nullptr, + double highWaterMark = 1, + JSC::JSObject* sizeAlgorithm = nullptr); + + void attach(JSReadableStream* stream); + bool isByteController() const { return false; } + JSC::JSObject* cancelAlgorithm() const { return m_cancelAlgorithm.get(); } + + // Internal slots from the spec + const Bun::StreamQueue& queue() const { return m_queue; } + Bun::StreamQueue& queue() { return m_queue; } + + bool started() const { return m_started; } + bool closeRequested() const { return m_closeRequested; } + bool pullAgain() const { return m_pullAgain; } + bool pulling() const { return m_pulling; } + double desiredSize() const; + JSC::JSValue desiredSizeValue(); + + // API for C++ usage + JSC::JSValue enqueue(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue chunk); + JSC::JSValue enqueue(JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) { return this->enqueue(this->vm(), globalObject, chunk); } + void error(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue error); + void error(JSC::JSGlobalObject* globalObject, JSC::JSValue error) { this->error(this->vm(), globalObject, error); } + void close(JSC::VM&, JSC::JSGlobalObject*); + void close(JSC::JSGlobalObject* globalObject) { this->close(this->vm(), globalObject); } + bool canCloseOrEnqueue() const; + + JSC::JSObject* pullAlgorithm() const { return m_pullAlgorithm.get(); } + + void setPullAlgorithm(JSC::JSObject* callback) { m_pullAlgorithm.set(vm(), this, callback); } + void setCancelAlgorithm(JSC::JSObject* callback) { m_cancelAlgorithm.set(vm(), this, callback); } + void setUnderlyingSource(JSC::JSObject* underlyingSource) { m_underlyingSource.set(vm(), this, underlyingSource); } + + void fulfillPull(JSC::JSGlobalObject*); + void rejectPull(JSC::JSGlobalObject*, JSC::JSValue error); + void callPullIfNeeded(JSC::JSGlobalObject*); + bool shouldCallPull() const; + JSReadableStream* stream() const; + JSC::JSObject* underlyingSource() const { return m_underlyingSource.get(); } + void clearAlgorithms(); + void setHighWaterMark(double highWaterMark) { m_queue.highWaterMark = highWaterMark; } + +private: + JSReadableStreamDefaultController(JSC::VM&, JSC::Structure*); + + void finishCreation(JSC::VM&, JSReadableStream*); + + // Internal slots + Bun::StreamQueue m_queue {}; + mutable JSC::WriteBarrier m_stream; + mutable JSC::WriteBarrier m_pullAlgorithm; + mutable JSC::WriteBarrier m_cancelAlgorithm; + mutable JSC::WriteBarrier m_underlyingSource; + + bool m_started { false }; + bool m_closeRequested { false }; + bool m_pullAgain { false }; + bool m_pulling { false }; +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.cpp b/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.cpp new file mode 100644 index 00000000000000..e739bf7f0d0f8d --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.cpp @@ -0,0 +1,31 @@ +#include "root.h" +#include "BunReadableStreamDefaultControllerConstructor.h" +#include +#include "JSDOMConstructorBase.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamDefaultControllerConstructor::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultControllerConstructor) }; + +JSReadableStreamDefaultControllerConstructor* JSReadableStreamDefaultControllerConstructor::create(VM& vm, JSGlobalObject* globalObject, JSObject* prototype) +{ + auto* structure = createStructure(vm, globalObject, prototype); + JSReadableStreamDefaultControllerConstructor* ptr = new (NotNull, allocateCell(vm)) JSReadableStreamDefaultControllerConstructor(vm, structure); + ptr->finishCreation(vm, globalObject, prototype); + return ptr; +} + +JSReadableStreamDefaultControllerConstructor::JSReadableStreamDefaultControllerConstructor(VM& vm, Structure* structure) + : Base(vm, structure, WebCore::callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable, WebCore::callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable) +{ +} + +void JSReadableStreamDefaultControllerConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSObject* prototype) +{ + Base::finishCreation(vm, 0, "ReadableStreamDefaultController"_s, PropertyAdditionMode::WithStructureTransition); + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.h b/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.h new file mode 100644 index 00000000000000..f4935515c2c5ba --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultControllerConstructor.h @@ -0,0 +1,34 @@ +#pragma once + +#include "root.h" +#include +#include +#include + +namespace Bun { + +class JSReadableStreamDefaultControllerConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSReadableStreamDefaultControllerConstructor* create(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject* prototype); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + 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()); + } + +private: + JSReadableStreamDefaultControllerConstructor(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject* prototype); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.cpp b/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.cpp new file mode 100644 index 00000000000000..7a1c5ab2f30654 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.cpp @@ -0,0 +1,94 @@ +#include "root.h" +#include "BunReadableStreamDefaultControllerPrototype.h" +#include "BunReadableStreamDefaultController.h" +#include + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamDefaultControllerPrototype::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultControllerPrototype) }; + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamDefaultControllerPrototypeClose, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultController* controller = jsDynamicCast(callFrame->thisValue()); + if (!controller) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.close called on incompatible object"_s); + + controller->close(globalObject); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamDefaultControllerPrototypeEnqueue, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultController* controller = jsDynamicCast(callFrame->thisValue()); + if (!controller) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.enqueue called on incompatible object"_s); + + JSValue chunk = callFrame->argument(0); + return JSValue::encode(controller->enqueue(vm, globalObject, chunk)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamDefaultControllerPrototypeError, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultController* controller = jsDynamicCast(callFrame->thisValue()); + if (!controller) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.error called on incompatible object"_s); + + JSValue error = callFrame->argument(0); + controller->error(globalObject, error); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamDefaultControllerPrototypeDesiredSizeGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultController* controller = jsDynamicCast(JSValue::decode(thisValue)); + if (!controller) + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultController.prototype.desiredSize called on incompatible object"_s); + + return JSValue::encode(controller->desiredSizeValue()); +} + +static const HashTableValue JSReadableStreamDefaultControllerPrototypeTableValues[] = { + { "close"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamDefaultControllerPrototypeClose, 0 } }, + { "enqueue"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamDefaultControllerPrototypeEnqueue, 1 } }, + { "error"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamDefaultControllerPrototypeError, 1 } }, + { "desiredSize"_s, static_cast(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, + { HashTableValue::GetterSetterType, jsReadableStreamDefaultControllerPrototypeDesiredSizeGetter, nullptr } } +}; + +JSReadableStreamDefaultControllerPrototype* JSReadableStreamDefaultControllerPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + JSReadableStreamDefaultControllerPrototype* ptr = new (NotNull, allocateCell(vm)) JSReadableStreamDefaultControllerPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +JSReadableStreamDefaultControllerPrototype::JSReadableStreamDefaultControllerPrototype(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSReadableStreamDefaultControllerPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, info(), JSReadableStreamDefaultControllerPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.h b/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.h new file mode 100644 index 00000000000000..6d6ce9292554f5 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultControllerPrototype.h @@ -0,0 +1,36 @@ +#pragma once + +#include "root.h" +#include +#include + +namespace Bun { + +class JSReadableStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSReadableStreamDefaultControllerPrototype* create(JSC::VM&, JSC::JSGlobalObject*, JSC::Structure*); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultControllerPrototype, Base); + return &vm.plainObjectSpace(); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + auto* structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + structure->setMayBePrototype(true); + return structure; + } + +private: + JSReadableStreamDefaultControllerPrototype(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReader.cpp b/src/bun.js/bindings/BunReadableStreamDefaultReader.cpp new file mode 100644 index 00000000000000..532547fa223752 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReader.cpp @@ -0,0 +1,171 @@ +#include "root.h" + +#include "JavaScriptCore/ArrayAllocationProfile.h" +#include "JavaScriptCore/JSGlobalObject.h" + +#include +#include "BunReadableStreamDefaultReader.h" +#include "BunClientData.h" +#include "BunReadableStream.h" +#include "BunReadableStreamDefaultController.h" +#include "BunStreamInlines.h" +#include "BunTeeState.h" +#include "JSAbortSignal.h" +#include +#include +#include +#include +#include + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamDefaultReader::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReader) }; + +JSReadableStreamDefaultReader* JSReadableStreamDefaultReader::create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStream* stream) +{ + JSReadableStreamDefaultReader* reader = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultReader(vm, structure); + reader->finishCreation(vm, stream); + + return reader; +} + +template +void JSReadableStreamDefaultReader::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* reader = static_cast(cell); + ASSERT_GC_OBJECT_INHERITS(reader, JSReadableStreamDefaultReader::info()); + Base::visitChildren(reader, visitor); + + reader->visitAdditionalChildren(visitor); +} + +template +void JSReadableStreamDefaultReader::visitAdditionalChildren(Visitor& visitor) +{ + m_readyPromise.visit(visitor); + m_closedPromise.visit(visitor); + visitor.append(m_stream); + + { + WTF::Locker lock(cellLock()); + for (auto request : m_readRequests) { + if (request.isCell()) + visitor.appendUnbarriered(request); + } + } +} + +DEFINE_VISIT_CHILDREN(JSReadableStreamDefaultReader); + +template +void JSReadableStreamDefaultReader::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + Base::visitOutputConstraints(cell, visitor); + + thisObject->visitAdditionalChildren(visitor); +} + +DEFINE_VISIT_ADDITIONAL_CHILDREN(JSReadableStreamDefaultReader); +DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSReadableStreamDefaultReader); + +void JSReadableStreamDefaultReader::finishCreation(JSC::VM& vm, JSReadableStream* stream) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + m_stream.setMayBeNull(vm, this, stream); + + m_closedPromise.initLater( + [](const auto& init) { + auto& vm = init.vm; + auto* globalObject = init.owner->globalObject(); + init.set(JSC::JSPromise::create(vm, globalObject->promiseStructure())); + }); + m_readyPromise.initLater( + [](const auto& init) { + auto& vm = init.vm; + auto* globalObject = init.owner->globalObject(); + init.set(JSC::JSPromise::create(vm, globalObject->promiseStructure())); + }); +} + +JSPromise* JSReadableStreamDefaultReader::takeFirst(JSC::VM& vm, JSGlobalObject* globalObject) +{ + if (m_readRequests.isEmpty()) { + return nullptr; + } + JSValue first; + { + WTF::Locker lock(cellLock()); + first = m_readRequests.takeFirst(); + } + return jsCast(first); +} + +void JSReadableStreamDefaultReader::detach() +{ + ASSERT(isActive()); + m_stream.clear(); +} + +void JSReadableStreamDefaultReader::releaseLock() +{ + if (!isActive()) + return; + + // Release the stream's reader reference + stream()->setReader(vm(), nullptr); + detach(); +} + +JSPromise* JSReadableStreamDefaultReader::cancel(JSC::VM& vm, JSGlobalObject* globalObject, JSValue reason) +{ + auto* stream = this->stream(); + if (!stream) { + return JSPromise::rejectedPromise(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.cancel called on reader with no ReadableStream"_s)); + } + + return stream->cancel(vm, globalObject, reason); +} + +void JSReadableStreamDefaultReader::addReadRequest(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue promise) +{ + WTF::Locker lock(cellLock()); + m_readRequests.append(promise); +} + +JSPromise* JSReadableStreamDefaultReader::read(JSC::VM& vm, JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + if (!this->isActive()) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.read called on released reader"_s)); + return nullptr; + } + + JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure()); + EnsureStillAliveScope ensureStillAlive(promise); + + stream()->controller()->performPullSteps(vm, globalObject, promise); + + return promise; +} + +JSReadableStream* JSReadableStreamDefaultReader::stream() const +{ + return jsCast(m_stream.get()); +} + +GCClient::IsoSubspace* JSReadableStreamDefaultReader::subspaceForImpl(JSC::VM& vm) +{ + + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForJSReadableStreamDefaultReader.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSReadableStreamDefaultReader = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForJSReadableStreamDefaultReader.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForJSReadableStreamDefaultReader = std::forward(space); }); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReader.h b/src/bun.js/bindings/BunReadableStreamDefaultReader.h new file mode 100644 index 00000000000000..82d866b7499282 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReader.h @@ -0,0 +1,91 @@ +#pragma once + +#include "JavaScriptCore/JSGlobalObject.h" +#include "root.h" + +#include "JavaScriptCore/JSDestructibleObject.h" +#include +#include +#include +#include +#include + +namespace Bun { + +using namespace JSC; + +class JSReadableStream; + +class JSReadableStreamDefaultReader final : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + static constexpr bool needsDestruction = true; + static void destroy(JSC::JSCell* cell) + { + static_cast(cell)->~JSReadableStreamDefaultReader(); + } + ~JSReadableStreamDefaultReader() + { + } + + static JSReadableStreamDefaultReader* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStream* stream); + 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* prototype(JSC::VM& vm, JSGlobalObject* globalObject); + static JSObject* constructor(JSC::VM& vm, JSGlobalObject* globalObject, JSValue prototype); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + DECLARE_VISIT_OUTPUT_CONSTRAINTS; + template + void visitAdditionalChildren(Visitor& visitor); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + // Public API for C++ usage + JSC::JSPromise* readyPromise() { return m_readyPromise.get(this); } + JSC::JSPromise* closedPromise() { return m_closedPromise.get(this); } + JSReadableStream* stream() const; + + JSC::JSPromise* read(JSC::VM&, JSGlobalObject*); + JSC::JSPromise* cancel(JSC::VM&, JSGlobalObject*, JSValue reason); + bool isActive() const { return !!m_stream; } + void detach(); + + bool isEmpty() + { + return m_readRequests.isEmpty(); + } + + // Implements ReadableStreamDefaultReader + void releaseLock(); + JSC::JSPromise* takeFirst(JSC::VM&, JSC::JSGlobalObject*); + void addReadRequest(JSC::VM&, JSC::JSGlobalObject* globalObject, JSC::JSValue promise); + +private: + JSReadableStreamDefaultReader(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSReadableStream* stream); + + WTF::Deque m_readRequests; + + // Internal slots defined by the spec + mutable JSC::WriteBarrier m_stream; + JSC::LazyProperty m_readyPromise; + JSC::LazyProperty m_closedPromise; +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.cpp b/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.cpp new file mode 100644 index 00000000000000..376569d83f18d8 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.cpp @@ -0,0 +1,100 @@ +#include "root.h" + +#include "BunReadableStreamDefaultController.h" +#include "BunReadableStream.h" +#include "BunReadableStreamDefaultReader.h" + +#include "ErrorCode.h" +#include + +#include "BunReadableStreamDefaultReaderPrototype.h" +#include "BunReadableStreamDefaultReaderConstructor.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSReadableStreamDefaultReaderConstructor::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderConstructor) }; + +JSReadableStreamDefaultReaderConstructor* JSReadableStreamDefaultReaderConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStreamDefaultReaderPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, prototype); + JSReadableStreamDefaultReaderConstructor* constructor = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultReaderConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +void JSReadableStreamDefaultReaderConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStreamDefaultReaderPrototype* prototype) +{ + Base::finishCreation(vm, 1, "ReadableStreamDefaultReader"_s, PropertyAdditionMode::WithStructureTransition); + ASSERT(inherits(info())); + + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSReadableStreamDefaultReaderConstructor::call(JSC::JSGlobalObject* globalObject, JSC::CallFrame*) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, "ReadableStreamDefaultReader constructor cannot be called as a function"_s); + return {}; +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSReadableStreamDefaultReaderConstructor::construct(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (callFrame->argumentCount() < 1) { + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultReader constructor requires a ReadableStream argument"_s); + } + + JSValue streamValue = callFrame->uncheckedArgument(0); + JSReadableStream* stream = jsDynamicCast(streamValue); + if (!stream) { + return throwVMTypeError(globalObject, scope, "ReadableStreamDefaultReader constructor argument must be a ReadableStream"_s); + } + + // Check if stream is already locked + if (stream->isLocked()) { + return throwVMTypeError(globalObject, scope, "Cannot construct a ReadableStreamDefaultReader for a locked ReadableStream"_s); + } + + JSC::JSObject* newTarget = callFrame->newTarget().getObject(); + JSC::JSObject* constructor = callFrame->jsCallee(); + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + + auto* structure = streams.structure(domGlobalObject); + + // TODO: double-check this. + if (!(!newTarget || newTarget == constructor)) { + if (newTarget) { + structure = JSC::InternalFunction::createSubclassStructure(getFunctionRealm(globalObject, newTarget), newTarget, structure); + } else { + structure = JSC::InternalFunction::createSubclassStructure(globalObject, constructor, structure); + } + } + RETURN_IF_EXCEPTION(scope, {}); + + JSReadableStreamDefaultReader* reader = JSReadableStreamDefaultReader::create(vm, globalObject, structure, stream); + RETURN_IF_EXCEPTION(scope, {}); + + // Lock the stream to this reader + stream->setReader(vm, reader); + + // Set up initial ready state + if (stream->isDisturbed() || stream->state() == JSReadableStream::State::Errored) { + JSValue error = stream->storedError(); + if (!error) + error = jsUndefined(); + + reader->readyPromise()->reject(globalObject, error); + } else { + reader->readyPromise()->fulfillWithNonPromise(globalObject, jsUndefined()); + } + + RELEASE_AND_RETURN(scope, JSValue::encode(reader)); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.h b/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.h new file mode 100644 index 00000000000000..0edb3aa3f3b18b --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReaderConstructor.h @@ -0,0 +1,48 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +using namespace JSC; + +class JSReadableStreamDefaultReaderPrototype; + +class JSReadableStreamDefaultReaderConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSReadableStreamDefaultReaderConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStreamDefaultReaderPrototype* prototype); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + 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::InternalFunctionType, StructureFlags), info()); + } + + static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr bool needsDestruction = false; + +private: + JSReadableStreamDefaultReaderConstructor(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, call, construct) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSReadableStreamDefaultReaderPrototype*); + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.cpp b/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.cpp new file mode 100644 index 00000000000000..8902a0db957529 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.cpp @@ -0,0 +1,136 @@ +#include "BunReadableStreamDefaultReaderPrototype.h" +#include "BunReadableStreamDefaultReader.h" +#include "BunReadableStream.h" +#include +#include + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(readableStreamDefaultReaderClosedGetter); +static JSC_DECLARE_CUSTOM_GETTER(readableStreamDefaultReaderReadyGetter); +static JSC_DECLARE_HOST_FUNCTION(readableStreamDefaultReaderRead); +static JSC_DECLARE_HOST_FUNCTION(readableStreamDefaultReaderReleaseLock); +static JSC_DECLARE_HOST_FUNCTION(readableStreamDefaultReaderCancel); + +const ClassInfo JSReadableStreamDefaultReaderPrototype::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderPrototype) }; + +static const HashTableValue JSReadableStreamDefaultReaderPrototypeTableValues[] = { + { "closed"_s, + static_cast(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor), + NoIntrinsic, + { HashTableValue::GetterSetterType, readableStreamDefaultReaderClosedGetter, nullptr } }, + { "ready"_s, + static_cast(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor), + NoIntrinsic, + { HashTableValue::GetterSetterType, readableStreamDefaultReaderReadyGetter, nullptr } }, + { "read"_s, + static_cast(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, readableStreamDefaultReaderRead, 0 } }, + { "releaseLock"_s, + static_cast(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, readableStreamDefaultReaderReleaseLock, 0 } }, + { "cancel"_s, + static_cast(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, readableStreamDefaultReaderCancel, 1 } }, +}; + +JSReadableStreamDefaultReaderPrototype* JSReadableStreamDefaultReaderPrototype::create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSReadableStreamDefaultReaderPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultReaderPrototype(vm, globalObject, structure); + ptr->finishCreation(vm); + return ptr; +} + +void JSReadableStreamDefaultReaderPrototype::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSReadableStreamDefaultReader::info(), JSReadableStreamDefaultReaderPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +// JS Bindings Implementation +JSC_DEFINE_HOST_FUNCTION(readableStreamDefaultReaderRead, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultReader* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.read called on incompatible object"_s)); + return {}; + } + + JSC::JSPromise* promise = reader->read(vm, globalObject); + RETURN_IF_EXCEPTION(scope, {}); + return JSC::JSValue::encode(promise); +} + +JSC_DEFINE_HOST_FUNCTION(readableStreamDefaultReaderReleaseLock, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultReader* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.releaseLock called on incompatible object"_s)); + return {}; + } + + reader->releaseLock(); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_CUSTOM_GETTER(readableStreamDefaultReaderClosedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultReader* reader = jsDynamicCast(JSValue::decode(thisValue)); + if (!reader) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.closed called on incompatible object"_s)); + return {}; + } + + return JSValue::encode(reader->closedPromise()); +} + +JSC_DEFINE_CUSTOM_GETTER(readableStreamDefaultReaderReadyGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultReader* reader = jsDynamicCast(JSValue::decode(thisValue)); + if (!reader) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.ready called on incompatible object"_s)); + return {}; + } + + return JSValue::encode(reader->readyPromise()); +} + +JSC_DEFINE_HOST_FUNCTION(readableStreamDefaultReaderCancel, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStreamDefaultReader* reader = jsDynamicCast(callFrame->thisValue()); + if (!reader) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.cancel called on incompatible object"_s)); + return {}; + } + + JSValue reason = callFrame->argument(0); + if (!reader->isActive()) { + scope.throwException(globalObject, createTypeError(globalObject, "ReadableStreamDefaultReader.prototype.cancel called on released reader"_s)); + return {}; + } + + return JSValue::encode(reader->stream()->cancel(vm, globalObject, reason)); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.h b/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.h new file mode 100644 index 00000000000000..ce4840c3b0d3b6 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamDefaultReaderPrototype.h @@ -0,0 +1,40 @@ +#pragma once + +#include "root.h" +#include +#include + +namespace Bun { + +using namespace JSC; + +class JSReadableStreamDefaultReaderPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSReadableStreamDefaultReaderPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultReaderPrototype, Base); + 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: + JSReadableStreamDefaultReaderPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamPipeToOperation.h b/src/bun.js/bindings/BunReadableStreamPipeToOperation.h new file mode 100644 index 00000000000000..9319009f0b059c --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamPipeToOperation.h @@ -0,0 +1,56 @@ +#pragma once + +#include "root.h" + +#include "JavaScriptCore/InternalFieldTuple.h" + +namespace Bun { + +class JSReadableStreamDefaultReader; +class JSWritableStreamDefaultWriter; + +// class PipeToOperation : public JSC::JSInternalFieldObjectImpl<7> { +// public: +// static constexpr unsigned numberOfInternalFields = 7; +// using Base = JSC::JSInternalFieldObjectImpl; +// static PipeToOperation* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, +// JSC::JSObject* reader, JSC::JSObject* writer, +// bool preventClose, bool preventAbort, bool preventCancel, JSC::JSObject* signal, JSC::JSPromise* promise) +// { +// PipeToOperation* operation = new (NotNull, JSC::allocateCell(vm)) PipeToOperation(vm, globalObject); +// operation->finishCreation(vm, reader, writer, preventClose, preventAbort, preventCancel, signal, promise); +// return operation; +// } + +// void perform(JSC::VM& vm, JSC::JSGlobalObject* globalObject) {} + +// bool preventClose { false }; +// bool preventAbort { false }; +// bool preventCancel { false }; + +// mutable JSC::WriteBarrier reader; +// mutable JSC::WriteBarrier writer; +// mutable JSC::WriteBarrier signal; +// mutable JSC::WriteBarrier promise; + +// private: +// PipeToOperation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +// : Base(vm, globalObject) +// { +// } + +// void finishCreation(JSC::VM& vm, JSC::JSObject* reader, JSC::JSObject* writer, +// bool preventClose, bool preventAbort, bool preventCancel, JSC::JSObject* signal, JSC::JSPromise* promise) +// { +// Base::finishCreation(vm); +// internalField(0).set(vm, this, reader); +// internalField(1).set(vm, this, writer); +// internalField(2).set(vm, this, JSC::jsBoolean(preventClose)); +// internalField(3).set(vm, this, JSC::jsBoolean(preventAbort)); +// internalField(4).set(vm, this, JSC::jsBoolean(preventCancel)); +// internalField(5).set(vm, this, signal ? signal : JSC::jsUndefined()); +// internalField(6).set(vm, this, promise); +// } +// }; + +} diff --git a/src/bun.js/bindings/BunReadableStreamPrototype.cpp b/src/bun.js/bindings/BunReadableStreamPrototype.cpp new file mode 100644 index 00000000000000..2a33990a12b5b6 --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamPrototype.cpp @@ -0,0 +1,171 @@ +#include "BunReadableStreamPrototype.h" +#include "BunReadableStream.h" +#include +#include +#include +#include + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamGetLocked); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamGetReader); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamCancel); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamPipeTo); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamPipeThrough); +static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamTee); + +static const HashTableValue JSReadableStreamPrototypeTableValues[] = { + { "locked"_s, + static_cast(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), + NoIntrinsic, + { HashTableValue::GetterSetterType, jsReadableStreamGetLocked, nullptr } }, + { "getReader"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamGetReader, 1 } }, + { "cancel"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamCancel, 1 } }, + { "pipeTo"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamPipeTo, 2 } }, + { "pipeThrough"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamPipeThrough, 2 } }, + { "tee"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsReadableStreamTee, 0 } } +}; + +const ClassInfo JSReadableStreamPrototype::s_info = { "ReadableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamPrototype) }; + +JSReadableStreamPrototype* JSReadableStreamPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + auto* thisObject = new (NotNull, allocateCell(vm)) JSReadableStreamPrototype(vm, structure); + thisObject->finishCreation(vm, globalObject); + return thisObject; +} + +Structure* JSReadableStreamPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + auto* structure = Base::createStructure(vm, globalObject, prototype); + structure->setMayBePrototype(true); + return structure; +} + +template +JSC::GCClient::IsoSubspace* JSReadableStreamPrototype::subspaceFor(VM& vm) +{ + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamPrototype, Base); + return &vm.plainObjectSpace(); +} + +JSReadableStreamPrototype::JSReadableStreamPrototype(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSReadableStreamPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, info(), JSReadableStreamPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +// JavaScript bindings +// JavaScript bindings +JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamGetLocked, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(JSValue::decode(thisValue)); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + return JSValue::encode(jsBoolean(stream->locked())); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamGetReader, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + JSValue options = callFrame->argument(0); + return JSValue::encode(stream->getReader(vm, globalObject, options)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamCancel, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + JSValue reason = callFrame->argument(0); + return JSValue::encode(stream->cancel(vm, globalObject, reason)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamPipeTo, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + JSValue destination = callFrame->argument(0); + JSValue options = callFrame->argument(1); + + return JSValue::encode(stream->pipeTo(vm, globalObject, destination.toObject(globalObject), options)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamPipeThrough, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + JSValue transform = callFrame->argument(0); + JSValue options = callFrame->argument(1); + + return JSValue::encode(stream->pipeThrough(vm, globalObject, transform.toObject(globalObject), options)); +} + +JSC_DEFINE_HOST_FUNCTION(jsReadableStreamTee, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSReadableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "Not a ReadableStream"_s); + + JSC::JSValue firstStream; + JSC::JSValue secondStream; + stream->tee(vm, globalObject, firstStream, secondStream); + RETURN_IF_EXCEPTION(scope, {}); + + JSArray* array = constructEmptyArray(globalObject, static_cast(nullptr), 2); + array->putDirectIndex(globalObject, 0, firstStream); + array->putDirectIndex(globalObject, 1, secondStream); + return JSValue::encode(array); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunReadableStreamPrototype.h b/src/bun.js/bindings/BunReadableStreamPrototype.h new file mode 100644 index 00000000000000..9755cc6201d3bf --- /dev/null +++ b/src/bun.js/bindings/BunReadableStreamPrototype.h @@ -0,0 +1,29 @@ +#pragma once + +#include "root.h" +#include +#include +#include +#include + +namespace Bun { + +using namespace JSC; + +class JSReadableStreamPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSReadableStreamPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure); + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(VM& vm); + +private: + JSReadableStreamPrototype(VM& vm, Structure* structure); + void finishCreation(VM& vm, JSGlobalObject* globalObject); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunStreamInlines.h b/src/bun.js/bindings/BunStreamInlines.h new file mode 100644 index 00000000000000..7dfa4622d053a4 --- /dev/null +++ b/src/bun.js/bindings/BunStreamInlines.h @@ -0,0 +1,45 @@ +#include "root.h" + +#include +#include "ZigGlobalObject.h" + +namespace Bun { + +using namespace JSC; + +static inline JSValue then(JSGlobalObject* globalObject, JSPromise* promise, Zig::GlobalObject::PromiseHandler resolverFunction, Zig::GlobalObject::PromiseHandler rejecterFunction, JSValue ctx = jsUndefined()) +{ + JSFunction* performPromiseThenFunction = globalObject->performPromiseThenFunction(); + auto callData = JSC::getCallData(performPromiseThenFunction); + ASSERT(callData.type != CallData::Type::None); + + MarkedArgumentBuffer arguments; + arguments.append(promise); + auto* bunGlobalObject = jsDynamicCast(globalObject); + arguments.append(bunGlobalObject->thenable(resolverFunction)); + arguments.append(bunGlobalObject->thenable(rejecterFunction)); + arguments.append(jsUndefined()); + arguments.append(ctx); + ASSERT(!arguments.hasOverflowed()); + // async context tracking is handled by performPromiseThenFunction internally. + return JSC::profiledCall(globalObject, JSC::ProfilingReason::Microtask, performPromiseThenFunction, callData, jsUndefined(), arguments); +} + +static inline JSValue then(JSGlobalObject* globalObject, JSPromise* promise, JSValue resolverFunction, JSValue rejecterFunction, JSValue ctx = jsUndefined()) +{ + JSFunction* performPromiseThenFunction = globalObject->performPromiseThenFunction(); + auto callData = JSC::getCallData(performPromiseThenFunction); + ASSERT(callData.type != CallData::Type::None); + + MarkedArgumentBuffer arguments; + arguments.append(promise); + arguments.append(resolverFunction); + arguments.append(rejecterFunction); + arguments.append(jsUndefined()); + arguments.append(ctx); + ASSERT(!arguments.hasOverflowed()); + // async context tracking is handled by performPromiseThenFunction internally. + return JSC::profiledCall(globalObject, JSC::ProfilingReason::Microtask, performPromiseThenFunction, callData, jsUndefined(), arguments); +} + +} diff --git a/src/bun.js/bindings/BunStreamQueue.cpp b/src/bun.js/bindings/BunStreamQueue.cpp new file mode 100644 index 00000000000000..6e87530636c9b9 --- /dev/null +++ b/src/bun.js/bindings/BunStreamQueue.cpp @@ -0,0 +1,176 @@ +#include "root.h" + +#include "BunStreamQueue.h" +#include +#include "JSByteLengthQueuingStrategy.h" +#include "JSCountQueuingStrategy.h" +#include "ErrorCode.h" + +namespace Bun { + +using namespace JSC; + +static int64_t byteLength(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSValue value) +{ + if (auto* arrayBufferView = jsDynamicCast(value)) { + return arrayBufferView->byteLength(); + } + + if (auto* arrayBuffer = jsDynamicCast(value)) { + if (auto* impl = arrayBuffer->impl()) { + return impl->byteLength(); + } else { + return 0; + } + } + + if (auto* object = value.getObject()) { + JSValue byteLengthProperty = object->getIfPropertyExists(globalObject, vm.propertyNames->byteLength); + if (byteLengthProperty) { + return byteLengthProperty.toLength(globalObject); + } + } + + return 0; +} + +void StreamQueue::initialize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, double highWaterMark, JSObject* owner, JSObject* sizeAlgorithm) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + this->highWaterMark = highWaterMark; + this->queueTotalSize = 0; + + if (sizeAlgorithm) { + if (auto* byteLengthStrategy = jsDynamicCast(sizeAlgorithm)) { + this->type = StreamQueueType::ByteLengthQueuingStrategy; + m_userDefinedStrategy.clear(); + } else if (auto* countStrategy = jsDynamicCast(sizeAlgorithm)) { + this->type = StreamQueueType::CountQueuingStrategy; + m_userDefinedStrategy.clear(); + } else if (auto sizeFunction = sizeAlgorithm->getIfPropertyExists(globalObject, vm.propertyNames->size)) { + if (!sizeFunction.isUndefinedOrNull()) { + if (!sizeFunction.isCallable()) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Expected 'size' to be a function"_s); + return; + } + + m_userDefinedStrategy.set(vm, owner, sizeFunction.getObject()); + this->type = StreamQueueType::UserDefined; + } + } + } +} + +void StreamQueue::resetQueue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner) +{ + { + WTF::Locker lock(owner->cellLock()); + m_queue.clear(); + } + this->queueTotalSize = 0; + m_userDefinedQueueSizes.clear(); +} + +void StreamQueue::clearAlgorithms() +{ + m_userDefinedStrategy.clear(); +} + +void StreamQueue::enqueueValueWithSize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObject* owner, JSValue value, double size) +{ + { + WTF::Locker lock(owner->cellLock()); + m_queue.append(value); + } + + this->queueTotalSize += size; + + if (type == StreamQueueType::UserDefined) { + m_userDefinedQueueSizes.append(size); + } +} + +JSValue StreamQueue::peekQueueValue(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + if (m_queue.isEmpty()) { + return {}; + } + + return m_queue.first(); +} + +void StreamQueue::enqueueValueAndGetSize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner, JSC::JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + double size; + switch (type) { + case StreamQueueType::UserDefined: { + auto* userDefinedStrategy = m_userDefinedStrategy.get(); + JSC::CallData callData = JSC::getCallData(userDefinedStrategy); + ASSERT_WITH_MESSAGE(callData.type != JSC::CallData::Type::None, "User defined strategy is not callable"); + MarkedArgumentBuffer args; + args.append(value); + JSValue result = JSC::call(globalObject, userDefinedStrategy, callData, jsUndefined(), args); + RETURN_IF_EXCEPTION(scope, void()); + size = result.toNumber(globalObject); + RETURN_IF_EXCEPTION(scope, void()); + if (size < 0) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Expected 'size' to be a non-negative number"_s); + return; + } else if (size == PNaN) { + size = 0; + } else if (size == std::numeric_limits::infinity()) { + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Expected 'size' to be a finite number"_s); + return; + } + break; + } + case StreamQueueType::CountQueuingStrategy: + size = 1; + break; + case StreamQueueType::ByteLengthQueuingStrategy: + size = byteLength(vm, globalObject, value); + RETURN_IF_EXCEPTION(scope, void()); + break; + } + + this->enqueueValueWithSize(vm, globalObject, owner, value, size); +} + +JSValue StreamQueue::dequeueValue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner) +{ + + JSValue result; + { + WTF::Locker lock(owner->cellLock()); + result = m_queue.takeFirst(); + } + auto scope = DECLARE_THROW_SCOPE(vm); + + RETURN_IF_EXCEPTION(scope, {}); + + if (!result) { + return {}; + } + + if (type == StreamQueueType::UserDefined) { + auto size = m_userDefinedQueueSizes.takeFirst(); + this->queueTotalSize -= size; + } else if (type == StreamQueueType::CountQueuingStrategy) { + this->queueTotalSize -= 1; + } else if (type == StreamQueueType::ByteLengthQueuingStrategy) { + // This can technically throw because we call .byteLength on the value + // and that value could be a JSObject with a getter for "byteLength" + // that throws. + this->queueTotalSize -= byteLength(vm, globalObject, result); + RETURN_IF_EXCEPTION(scope, {}); + } + + if (UNLIKELY(this->queueTotalSize < 0)) { + this->queueTotalSize = 0; + } + + return result; +} + +} diff --git a/src/bun.js/bindings/BunStreamQueue.h b/src/bun.js/bindings/BunStreamQueue.h new file mode 100644 index 00000000000000..86c00589b81aee --- /dev/null +++ b/src/bun.js/bindings/BunStreamQueue.h @@ -0,0 +1,79 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +enum class StreamQueueType : uint8_t { + CountQueuingStrategy, + ByteLengthQueuingStrategy, + UserDefined, +}; + +class StreamQueue { +public: + StreamQueueType type { StreamQueueType::CountQueuingStrategy }; + double highWaterMark { 0 }; + + // Due to the limited precision of floating-point arithmetic, the framework + // specified here, of keeping a running total in the [[queueTotalSize]] + // slot, is not equivalent to adding up the size of all chunks in [[queue]]. + // (However, this only makes a difference when there is a huge (~10^15) + // variance in size between chunks, or when trillions of chunks are + // enqueued.) + double queueTotalSize { 0 }; + + template + void visit(JSCell* owner, Visitor& visitor) + { + if (m_userDefinedStrategy) + visitor.append(m_userDefinedStrategy); + { + WTF::Locker lock(owner->cellLock()); + for (auto value : m_queue) { + if (value.isCell()) + visitor.appendUnbarriered(value); + } + } + } + + void setUserDefinedStrategy(JSC::JSObject* strategy); + + void initialize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, double highWaterMark, JSC::JSObject* owner, JSC::JSObject* sizeAlgorithm); + + // 1. Assert: container has [[queue]] and [[queueTotalSize]] internal slots. + // 2. Set container.[[queue]] to a new empty list. + // 3. Set container.[[queueTotalSize]] to 0. + void resetQueue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner); + JSC::JSValue peekQueueValue(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + void enqueueValueWithSize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner, JSC::JSValue value, double size); + JSC::JSValue dequeueValue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner); + + void enqueueValueAndGetSize(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner, JSC::JSValue value); + + void clearAlgorithms(); + + mutable JSC::WriteBarrier m_userDefinedStrategy; + WTF::Deque m_userDefinedQueueSizes = {}; + + bool isEmpty() + { + const bool isEmpty = queueTotalSize == 0; +#if ASSERT_ENABLED + ASSERT(type == StreamQueueType::UserDefined ? m_userDefinedQueueSizes.isEmpty() == isEmpty : true); +#endif + return isEmpty; + } + + double desiredSize() const + { + return highWaterMark - queueTotalSize; + } + +private: + WTF::Deque& queue() { return m_queue; } + const WTF::Deque& queue() const { return m_queue; } + + WTF::Deque m_queue = {}; +}; +} diff --git a/src/bun.js/bindings/BunStreamStructures.cpp b/src/bun.js/bindings/BunStreamStructures.cpp new file mode 100644 index 00000000000000..1dfd5404eb0694 --- /dev/null +++ b/src/bun.js/bindings/BunStreamStructures.cpp @@ -0,0 +1,88 @@ +#include "root.h" + +#include +#include + +#include "ZigGlobalObject.h" +#include "BunStreamStructures.h" + +#include "BunReadableStream.h" +#include "BunReadableStreamPrototype.h" +#include "BunReadableStreamConstructor.h" + +#include "BunReadableStreamDefaultReader.h" +#include "BunReadableStreamDefaultReaderPrototype.h" +#include "BunReadableStreamDefaultReaderConstructor.h" + +#include "BunReadableStreamDefaultController.h" +#include "BunReadableStreamDefaultControllerPrototype.h" +#include "BunReadableStreamDefaultControllerConstructor.h" + +#include "BunReadableStreamBYOBReader.h" +#include "BunReadableStreamBYOBReaderPrototype.h" +#include "BunReadableStreamBYOBReaderConstructor.h" + +#include "BunWritableStream.h" +#include "BunWritableStreamPrototype.h" +#include "BunWritableStreamConstructor.h" + +#include "BunWritableStreamDefaultWriter.h" +#include "BunWritableStreamDefaultWriterPrototype.h" +#include "BunWritableStreamDefaultWriterConstructor.h" + +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStreamDefaultControllerPrototype.h" +#include "BunWritableStreamDefaultControllerConstructor.h" + +#include "BunTransformStream.h" +#include "BunTransformStreamPrototype.h" +#include "BunTransformStreamConstructor.h" + +#include "BunTransformStreamDefaultController.h" +#include "BunTransformStreamDefaultControllerPrototype.h" +#include "BunTransformStreamDefaultControllerConstructor.h" + +#include + +namespace Bun { + +void StreamStructures::initialize(VM& vm, JSC::JSGlobalObject* _globalObject) +{ + +#define INIT_WHATWG_STREAM_CONSTRUCTOR(ConstructorName) \ + m_##ConstructorName.initLater( \ + [](LazyClassStructure::Initializer& init) { \ + auto* globalObject = reinterpret_cast(init.global); \ + auto* prototype = ConstructorName##Prototype::create(init.vm, globalObject, ConstructorName##Prototype::createStructure(init.vm, globalObject, globalObject->objectPrototype())); \ + auto* structure = ConstructorName::createStructure(init.vm, globalObject, prototype); \ + auto* constructor = ConstructorName##Constructor::create(init.vm, globalObject, prototype); \ + init.setPrototype(prototype); \ + init.setStructure(structure); \ + init.setConstructor(constructor); \ + }); + + FOR_EACH_WHATWG_STREAM_CLASS_TYPE(INIT_WHATWG_STREAM_CONSTRUCTOR) + +#undef INIT_WHATWG_STREAM_CONSTRUCTOR +} + +#define DEFINE_STREAM_MEMBERS(ClassName) \ + template<> \ + JSObject* StreamStructures::constructor(const JSGlobalObject* globalObject) \ + { \ + return m_##ClassName.constructor(globalObject); \ + } \ + template<> \ + Structure* StreamStructures::structure(const JSGlobalObject* globalObject) \ + { \ + return m_##ClassName.get(globalObject); \ + } \ + template<> \ + JSObject* StreamStructures::prototype(const JSGlobalObject* globalObject) \ + { \ + return m_##ClassName.prototype(globalObject); \ + } +FOR_EACH_WHATWG_STREAM_CLASS_TYPE(DEFINE_STREAM_MEMBERS) +#undef DEFINE_STREAM_MEMBERS + +} diff --git a/src/bun.js/bindings/BunStreamStructures.h b/src/bun.js/bindings/BunStreamStructures.h new file mode 100644 index 00000000000000..e00b00ee7000a1 --- /dev/null +++ b/src/bun.js/bindings/BunStreamStructures.h @@ -0,0 +1,66 @@ +#pragma once + +#include "root.h" + +#include "JavaScriptCore/LazyClassStructure.h" +#include + +namespace Bun { + +using namespace JSC; + +// Forward declarations +class JSReadableStream; +class JSReadableStreamDefaultReader; +class JSReadableStreamDefaultController; +class JSReadableStreamByteController; +class JSReadableStreamBYOBReader; +class JSWritableStream; +class JSWritableStreamDefaultWriter; +class JSWritableStreamDefaultController; +class JSTransformStream; +class JSTransformStreamDefaultController; + +// clang-format off +#define FOR_EACH_WHATWG_STREAM_CLASS_TYPE(macro) \ + macro(JSReadableStream) \ + macro(JSReadableStreamDefaultReader) \ + macro(JSReadableStreamDefaultController) \ + macro(JSReadableStreamBYOBReader) \ + macro(JSWritableStream) \ + macro(JSWritableStreamDefaultWriter) \ + macro(JSWritableStreamDefaultController) \ + macro(JSTransformStream) \ + macro(JSTransformStreamDefaultController) +// clang-format on + +// Stream-related structures for the global object +struct StreamStructures { +public: +#define DECLARE_STREAM_MEMBER(ClassName) LazyClassStructure m_##ClassName; + FOR_EACH_WHATWG_STREAM_CLASS_TYPE(DECLARE_STREAM_MEMBER) +#undef DECLARE_STREAM_MEMBER + + template + JSObject* constructor(const JSGlobalObject* globalObject); + + template + Structure* structure(const JSGlobalObject* globalObject); + + template + JSObject* prototype(const JSGlobalObject* globalObject); + + void initialize(VM& vm, JSC::JSGlobalObject* globalObject); +}; + +#define DECLARE_STREAM_TEMPLATE_METHODS(ClassName) \ + template<> \ + JSObject* StreamStructures::constructor(const JSGlobalObject* globalObject); \ + template<> \ + Structure* StreamStructures::structure(const JSGlobalObject* globalObject); \ + template<> \ + JSObject* StreamStructures::prototype(const JSGlobalObject* globalObject); + +FOR_EACH_WHATWG_STREAM_CLASS_TYPE(DECLARE_STREAM_TEMPLATE_METHODS) + +} diff --git a/src/bun.js/bindings/BunTeeState.cpp b/src/bun.js/bindings/BunTeeState.cpp new file mode 100644 index 00000000000000..2ca37559f36f4e --- /dev/null +++ b/src/bun.js/bindings/BunTeeState.cpp @@ -0,0 +1,205 @@ +#include "root.h" + +#include "BunReadableStream.h" +#include "BunWritableStream.h" +#include "BunTransformStream.h" +#include "BunReadableStreamDefaultReader.h" +#include "BunTeeState.h" +#include "JSTextEncoderStream.h" +#include "BunStreamInlines.h" + +#include "BunReadableStreamDefaultReader.h" +#include "BunReadableStreamDefaultController.h" +#include "ZigGlobalObject.h" +#include "StructuredClone.h" + +#include "JavaScriptCore/IteratorOperations.h" +#include "BunPromiseInlines.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo TeeState::s_info = { "TeeState"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(TeeState) }; + +TeeState::TeeState(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +JSC::GCClient::IsoSubspace* TeeState::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForTeeState.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTeeState = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForTeeState.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForTeeState = std::forward(space); }); +} + +void TeeState::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +JSC::JSPromise* TeeState::cancel(VM& vm, JSGlobalObject* globalObject, Bun::JSReadableStream* canceledBranch, JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (m_closedOrErrored) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + if (canceledBranch == m_branch1.get()) { + m_canceled1 = true; + m_reason1.set(vm, this, reason); + } else { + m_canceled2 = true; + m_reason2.set(vm, this, reason); + } + + // Create the cancelPromise if it doesn't exist + if (!m_cancelPromise) { + m_cancelPromise.set(vm, this, JSPromise::create(vm, globalObject->promiseStructure())); + } + + if (!m_canceled1 || !m_canceled2) + return m_cancelPromise.get(); + + // Both branches are now canceled - composite the reasons + auto* reasons = JSC::constructEmptyArray(globalObject, static_cast(nullptr), 2); + reasons->putDirectIndex(globalObject, 0, m_reason1.get()); + reasons->putDirectIndex(globalObject, 1, m_reason2.get()); + + JSC::JSPromise* result = this->m_reader->cancel(vm, globalObject, reasons); + RETURN_IF_EXCEPTION(scope, nullptr); + + JSValue resolve = m_cancelPromiseResolve.get(); + JSValue reject = m_cancelPromiseReject.get(); + m_cancelPromiseResolve.clear(); + m_cancelPromiseReject.clear(); + + Bun::then(globalObject, result, resolve, reject); + + return m_cancelPromise.get(); +} + +void TeeState::perform(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + // Start pulling from the original stream + pullAlgorithm(vm, globalObject); +} + +Structure* TeeState::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + return Structure::create(vm, globalObject, jsNull(), TypeInfo(CellType, StructureFlags), info()); +} + +TeeState* TeeState::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, Bun::JSReadableStreamDefaultReader* reader, Bun::JSReadableStream* branch1, Bun::JSReadableStream* branch2) +{ + auto* structure = defaultGlobalObject(globalObject)->teeStateStructure(); + auto* teeState = new (NotNull, allocateCell(vm)) TeeState(vm, structure); + teeState->finishCreation(vm, reader, branch1, branch2); + return teeState; +} + +void TeeState::finishCreation(JSC::VM& vm, Bun::JSReadableStreamDefaultReader* reader, Bun::JSReadableStream* branch1, Bun::JSReadableStream* branch2) +{ + Base::finishCreation(vm); + m_reader.set(vm, this, reader); + m_branch1.set(vm, this, branch1); + m_branch2.set(vm, this, branch2); +} + +void TeeState::pullAlgorithmReject(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue error) +{ + m_closedOrErrored = true; + if (!m_canceled1) + m_branch1->controller()->error(vm, globalObject, error); + if (!m_canceled2) + m_branch2->controller()->error(vm, globalObject, error); +} + +void TeeState::pullAlgorithmFulfill(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue result) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + JSObject* resultObj = result.toObject(globalObject); + RETURN_IF_EXCEPTION(scope, void()); + + bool done = resultObj->get(globalObject, vm.propertyNames->done).toBoolean(globalObject); + JSValue value = resultObj->get(globalObject, vm.propertyNames->value); + + if (done) { + if (!m_canceled1) + m_branch1->controller()->close(vm, globalObject); + if (!m_canceled2) + m_branch2->controller()->close(vm, globalObject); + m_closedOrErrored = true; + } else { + // Enqueue the chunk to both branches + JSValue chunk1 = value; + JSValue chunk2 = value; + + if (!m_canceled1) + m_branch1->controller()->enqueue(vm, globalObject, chunk1); + if (!m_canceled2) + m_branch2->controller()->enqueue(vm, globalObject, chunk2); + + m_pullInProgress = false; + pullAlgorithm(vm, globalObject); + } +} + +JSC_DEFINE_HOST_FUNCTION(jsTeeStatePullAlgorithmFulfill, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + TeeState* teeState = jsDynamicCast(callFrame->argument(1)); + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + if (UNLIKELY(!teeState)) + return throwVMTypeError(globalObject, scope, "TeeState.pullAlgorithmFulfill called on incompatible object"_s); + + teeState->pullAlgorithmFulfill(globalObject->vm(), globalObject, callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsTeeStatePullAlgorithmReject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + TeeState* teeState = jsDynamicCast(callFrame->argument(1)); + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + if (UNLIKELY(!teeState)) + return throwVMTypeError(globalObject, scope, "TeeState.pullAlgorithmReject called on incompatible object"_s); + + teeState->pullAlgorithmReject(globalObject->vm(), globalObject, callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +void TeeState::pullAlgorithm(VM& vm, JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (m_pullInProgress || m_closedOrErrored) + return; + + m_pullInProgress = true; + + JSValue readResult = m_reader->read(vm, globalObject); + RETURN_IF_EXCEPTION(scope, void()); + + if (JSPromise* promise = jsDynamicCast(readResult)) { + Bun::then(globalObject, promise, jsTeeStatePullAlgorithmFulfill, jsTeeStatePullAlgorithmReject, this); + } +} + +template +void TeeState::visitChildrenImpl(JSC::JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_reader); + visitor.append(thisObject->m_branch1); + visitor.append(thisObject->m_branch2); +} + +DEFINE_VISIT_CHILDREN(TeeState); + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTeeState.h b/src/bun.js/bindings/BunTeeState.h new file mode 100644 index 00000000000000..7ca624eb745d5d --- /dev/null +++ b/src/bun.js/bindings/BunTeeState.h @@ -0,0 +1,64 @@ +#include "root.h" + +#include +#include +#include +#include + +namespace Bun { + +// Prefer forward declarations over including headers, to save compile time +class JSReadableStream; +class JSReadableStreamDefaultReader; + +using namespace JSC; + +class TeeState final : public JSC::JSCell { +public: + using Base = JSC::JSCell; + + static TeeState* create(VM&, JSGlobalObject*, JSReadableStreamDefaultReader*, JSReadableStream* branch1, JSReadableStream* branch2); + static Structure* createStructure(VM&, JSGlobalObject*); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + void perform(VM&, JSGlobalObject*); // Start the tee operation + + void pullAlgorithmFulfill(VM&, JSGlobalObject*, JSValue result); + void pullAlgorithmReject(VM&, JSGlobalObject*, JSValue error); + void finishCreation(VM&, JSReadableStreamDefaultReader*, JSReadableStream* branch1, JSReadableStream* branch2); + +private: + TeeState(VM&, Structure*); + + void finishCreation(VM&); + + // Called when either branch is canceled + JSC::JSPromise* cancel(VM&, JSGlobalObject*, JSReadableStream* canceledBranch, JSValue reason); + void pullAlgorithm(VM&, JSGlobalObject*); + + mutable JSC::WriteBarrier m_reader; + mutable JSC::WriteBarrier m_branch1; + mutable JSC::WriteBarrier m_branch2; + mutable JSC::WriteBarrier m_reason1; + mutable JSC::WriteBarrier m_reason2; + mutable JSC::WriteBarrier m_cancelPromise; + mutable JSC::WriteBarrier m_cancelPromiseResolve; + mutable JSC::WriteBarrier m_cancelPromiseReject; + bool m_canceled1 { false }; + bool m_canceled2 { false }; + bool m_closedOrErrored { false }; + bool m_pullInProgress { false }; +}; + +} diff --git a/src/bun.js/bindings/BunTransformStream.cpp b/src/bun.js/bindings/BunTransformStream.cpp new file mode 100644 index 00000000000000..314f1b0f95ef9f --- /dev/null +++ b/src/bun.js/bindings/BunTransformStream.cpp @@ -0,0 +1,168 @@ +#include "root.h" + +#include "BunWritableStream.h" +#include "BunReadableStream.h" +#include "BunTransformStream.h" +#include "BunTransformStreamDefaultController.h" + +#include "ZigGlobalObject.h" +#include + +#include "BunWritableStreamDefaultController.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSTransformStream::s_info = { + "TransformStream"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSTransformStream) +}; + +template +void JSTransformStream::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_readable); + visitor.append(thisObject->m_writable); + visitor.append(thisObject->m_controller); + visitor.append(thisObject->m_backpressureChangePromise); +} + +DEFINE_VISIT_CHILDREN(JSTransformStream); + +JSTransformStream::JSTransformStream(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSTransformStream::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + // Initialize readable/writable sides and controller + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* zigGlobalObject = jsDynamicCast(globalObject); + if (UNLIKELY(!zigGlobalObject)) { + throwTypeError(globalObject, scope, "Invalid global object"_s); + return; + } + + // Initialize with empty promises that will be fulfilled when ready + m_backpressureChangePromise.set(vm, this, JSPromise::create(vm, zigGlobalObject->promiseStructure())); + + // Set up the controller + m_controller.set(vm, this, JSTransformStreamDefaultController::create(vm, globalObject, zigGlobalObject->streams().structure(zigGlobalObject), this)); + + RETURN_IF_EXCEPTION(scope, void()); +} + +JSTransformStream* JSTransformStream::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + JSTransformStream* ptr = new (NotNull, JSC::allocateCell(vm)) JSTransformStream(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +void JSTransformStream::enqueue(VM& vm, JSGlobalObject* globalObject, JSValue chunk) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (m_controller) + m_controller->enqueue(globalObject, chunk); + + RETURN_IF_EXCEPTION(scope, void()); +} + +void JSTransformStream::error(VM& vm, JSGlobalObject* globalObject, JSValue error) +{ + if (m_controller) + m_controller->error(vm, globalObject, error); +} + +void JSTransformStream::terminate(VM& vm, JSGlobalObject* globalObject) +{ + if (m_controller) + m_controller->terminate(vm, globalObject); +} + +void JSTransformStream::errorWritableAndUnblockWrite(VM& vm, JSGlobalObject* globalObject, JSValue error) +{ + if (m_controller) { + auto* controller = this->controller(); + // Clear algorithms on controller + controller->clearAlgorithms(); + + // Error the writable stream's controller if needed + if (auto* writable = writableStream()) { + if (auto* controller = writable->controller()) { + controller->error(vm, globalObject, error); + } + } + + this->unblockWrite(vm, globalObject); + } +} + +void JSTransformStream::unblockWrite(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + // If stream.[[backpressure]] is true, perform ! TransformStreamSetBackpressure(stream, false). + if (m_backpressure) { + if (m_backpressureChangePromise) { + m_backpressureChangePromise->fulfillWithNonPromise(globalObject, jsUndefined()); + m_backpressureChangePromise.clear(); + } + } + + m_backpressure = false; +} + +JSWritableStream* JSTransformStream::writableStream() const +{ + return jsCast(m_writable.get()); +} + +JSReadableStream* JSTransformStream::readableStream() const +{ + return jsCast(m_readable.get()); +} + +void JSTransformStream::setBackpressure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + if (m_backpressure) { + return; + } + + // TransformStreamSetBackpressure(stream, backpressure) performs the following steps: + // Assert: stream.[[backpressure]] is not backpressure. + if (m_backpressureChangePromise) { + m_backpressureChangePromise->fulfillWithNonPromise(globalObject, jsUndefined()); + m_backpressureChangePromise.clear(); + } + + m_backpressure = true; +} + +JSTransformStreamDefaultController* JSTransformStream::controller() +{ + return jsCast(m_controller.get()); +} + +JSC::GCClient::IsoSubspace* JSTransformStream::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForTransformStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTransformStream = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForTransformStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForTransformStream = std::forward(space); }); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStream.h b/src/bun.js/bindings/BunTransformStream.h new file mode 100644 index 00000000000000..b4a5ed3c0a2c76 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStream.h @@ -0,0 +1,80 @@ +#include "root.h" + +#include +#include +#include + +namespace Bun { + +class JSTransformStreamDefaultController; +class JSReadableStream; +class JSWritableStream; +class JSTransformStream final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + // For garbage collection + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + static JSTransformStream* create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::Structure* structure); + + static JSC::Structure* createStructure( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::JSValue prototype) + { + return JSC::Structure::create( + vm, + globalObject, + prototype, + JSC::TypeInfo(JSC::JSType::ObjectType, StructureFlags), + info()); + } + + // Readable side operations + JSC::JSValue readable() const { return m_readable.get(); } + Bun::JSReadableStream* readableStream() const; + JSC::JSValue writable() const { return m_writable.get(); } + Bun::JSWritableStream* writableStream() const; + JSTransformStreamDefaultController* controller(); + + // Direct C++ API + void enqueue(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue chunk); + void error(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue error); + void terminate(JSC::VM&, JSC::JSGlobalObject*); + void errorWritableAndUnblockWrite(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue error); + void errorWritableAndUnblockWrite(JSC::JSGlobalObject* globalObject, JSC::JSValue error) { this->errorWritableAndUnblockWrite(this->vm(), globalObject, error); } + + // Backpressure operations + bool hasBackpressure() const { return m_backpressure; } + void setBackpressure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + void unblockWrite(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + +private: + JSTransformStream(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); + + // The readable and writable sides of the transform stream + JSC::WriteBarrier m_readable; + JSC::WriteBarrier m_writable; + JSC::WriteBarrier m_controller; + + // State flags + bool m_backpressure { false }; + JSC::WriteBarrier m_backpressureChangePromise; +}; + +} diff --git a/src/bun.js/bindings/BunTransformStreamConstructor.cpp b/src/bun.js/bindings/BunTransformStreamConstructor.cpp new file mode 100644 index 00000000000000..a6c0bde65364f6 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamConstructor.cpp @@ -0,0 +1,160 @@ +#include "root.h" + +#include "BunReadableStream.h" +#include "BunWritableStream.h" +#include "BunTransformStream.h" +#include "BunReadableStreamDefaultReader.h" +#include "BunTransformStreamDefaultController.h" + +#include "ZigGlobalObject.h" +#include "BunTransformStreamConstructor.h" +#include "BunTransformStreamPrototype.h" +#include "BunBuiltinNames.h" +#include +#include "ErrorCode.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSTransformStreamConstructor::s_info = { + "Function"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSTransformStreamConstructor) +}; + +JSTransformStreamConstructor* JSTransformStreamConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSTransformStreamConstructor* constructor = new (NotNull, JSC::allocateCell(vm)) JSTransformStreamConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +JSTransformStreamConstructor::JSTransformStreamConstructor(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +void JSTransformStreamConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamPrototype* prototype) +{ + Base::finishCreation(vm, 3, "TransformStream"_s, PropertyAdditionMode::WithStructureTransition); + putDirect(vm, vm.propertyNames->prototype, prototype, + PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSC_DEFINE_HOST_FUNCTION(JSTransformStreamConstructor::construct, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* zigGlobalObject = jsDynamicCast(globalObject); + if (UNLIKELY(!zigGlobalObject)) + return throwVMTypeError(globalObject, scope, "Invalid global object"_s); + + JSObject* newTarget = asObject(callFrame->newTarget()); + Structure* structure = zigGlobalObject->streams().structure(zigGlobalObject); + auto* constructor = zigGlobalObject->streams().constructor(zigGlobalObject); + + if (!(!newTarget || newTarget != constructor)) { + if (newTarget) { + structure = JSC::InternalFunction::createSubclassStructure(getFunctionRealm(globalObject, newTarget), newTarget, structure); + } else { + structure = JSC::InternalFunction::createSubclassStructure(globalObject, constructor, structure); + } + } + + RETURN_IF_EXCEPTION(scope, {}); + + // Extract constructor arguments per spec: + // new TransformStream(transformer = undefined, writableStrategy = {}, readableStrategy = {}) + JSValue transformerArg = callFrame->argument(0); + JSValue writableStrategyArg = callFrame->argument(1); + JSValue readableStrategyArg = callFrame->argument(2); + + // Create the underlying transform stream + JSTransformStream* transformStream = JSTransformStream::create(vm, globalObject, structure); + RETURN_IF_EXCEPTION(scope, {}); + + auto& builtinNames = Bun::builtinNames(vm); + + // Set up readable and writable sides with provided strategies + if (!writableStrategyArg.isUndefined()) { + // Apply writable strategy + JSValue highWaterMark = writableStrategyArg.get(globalObject, builtinNames.highWaterMarkPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + JSValue size = writableStrategyArg.get(globalObject, vm.propertyNames->size); + RETURN_IF_EXCEPTION(scope, {}); + // ... apply strategy to writable side + UNUSED_PARAM(highWaterMark); + UNUSED_PARAM(size); + } + + if (!readableStrategyArg.isUndefined()) { + // Apply readable strategy + JSValue highWaterMark = readableStrategyArg.get(globalObject, builtinNames.highWaterMarkPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + JSValue size = readableStrategyArg.get(globalObject, vm.propertyNames->size); + RETURN_IF_EXCEPTION(scope, {}); + // ... apply strategy to readable side + UNUSED_PARAM(highWaterMark); + UNUSED_PARAM(size); + } + + // Handle transformer setup if provided + if (!transformerArg.isUndefined()) { + JSValue transformFn = transformerArg.get(globalObject, builtinNames.transformPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + JSValue flushFn = transformerArg.get(globalObject, builtinNames.flushPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + JSValue startFn = transformerArg.get(globalObject, builtinNames.startPublicName()); + RETURN_IF_EXCEPTION(scope, {}); + + // Set up transform algorithm + if (!transformFn.isUndefined()) { + // Install transform function + } + + // Set up flush algorithm + if (!flushFn.isUndefined()) { + // Install flush function + } + + // Call start if present + if (!startFn.isUndefined()) { + auto* controller = transformStream->controller(); + MarkedArgumentBuffer args; + args.append(controller); + + auto callData = JSC::getCallData(startFn); + if (callData.type == JSC::CallData::Type::None) { + throwTypeError(globalObject, scope, "Start function is not callable"_s); + return {}; + } + IGNORE_WARNINGS_BEGIN("unused-variable") + JSC::JSValue startResult = JSC::call(globalObject, startFn, callData, transformerArg, args); + IGNORE_WARNINGS_END + RETURN_IF_EXCEPTION(scope, {}); + } + } + + RELEASE_AND_RETURN(scope, JSValue::encode(transformStream)); +} + +JSC_DEFINE_HOST_FUNCTION(JSTransformStreamConstructor::call, (JSGlobalObject * globalObject, CallFrame*)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Cannot call TransformStream"_s); + return {}; +} + +Structure* JSTransformStreamConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamConstructor.h b/src/bun.js/bindings/BunTransformStreamConstructor.h new file mode 100644 index 00000000000000..51542d648756bc --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamConstructor.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace Bun { + +class JSTransformStreamPrototype; + +class JSTransformStreamConstructor final : public JSC::InternalFunction { + using Base = JSC::InternalFunction; + +public: + static JSTransformStreamConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamPrototype* prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype); + +private: + JSTransformStreamConstructor(JSC::VM& vm, JSC::Structure* structure); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSTransformStreamPrototype*); + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); +}; +} diff --git a/src/bun.js/bindings/BunTransformStreamDefaultController.cpp b/src/bun.js/bindings/BunTransformStreamDefaultController.cpp new file mode 100644 index 00000000000000..7fb99bf546fa62 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultController.cpp @@ -0,0 +1,149 @@ +#include "BunClientData.h" +#include "root.h" + +#include "BunTransformStreamDefaultController.h" +#include "BunTransformStream.h" +#include "BunReadableStream.h" +#include "BunWritableStream.h" +#include "BunReadableStreamDefaultController.h" + +namespace Bun { + +using namespace JSC; + +JSTransformStreamDefaultController* JSTransformStreamDefaultController::create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::Structure* structure, + JSTransformStream* transformStream) +{ + JSTransformStreamDefaultController* controller = new (NotNull, JSC::allocateCell(vm)) + JSTransformStreamDefaultController(vm, structure); + controller->finishCreation(vm, globalObject, transformStream); + return controller; +} + +JSC::GCClient::IsoSubspace* JSTransformStreamDefaultController::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForTransformStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTransformStreamDefaultController = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForTransformStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForTransformStreamDefaultController = std::forward(space); }); +} + +void JSTransformStreamDefaultController::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStream* transformStream) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + m_stream.set(vm, this, transformStream); +} + +JSTransformStream* JSTransformStreamDefaultController::stream() const +{ + return JSC::jsCast(m_stream.get()); +} + +template +void JSTransformStreamDefaultController::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + visitor.append(thisObject->m_stream); + visitor.append(thisObject->m_flushPromise); + visitor.append(thisObject->m_transformAlgorithm); + visitor.append(thisObject->m_flushAlgorithm); +} + +DEFINE_VISIT_CHILDREN(JSTransformStreamDefaultController); + +bool JSTransformStreamDefaultController::enqueue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // Get the transform stream + auto* stream = jsDynamicCast(m_stream.get()); + ASSERT(stream); + + // Get the readable controller from the stream's readable side + auto* readable = jsDynamicCast(stream->readable()); + ASSERT(readable); + auto* readableController = jsDynamicCast(readable->controller()); + ASSERT(readableController); + + // Check if we can enqueue to the readable controller + if (!readableController->canCloseOrEnqueue()) { + throwTypeError(globalObject, scope, "Cannot enqueue to readable side - controller cannot close or enqueue"_s); + return false; + } + + // Try to enqueue the chunk to the readable controller + readableController->enqueue(vm, globalObject, chunk); + + // If enqueuing resulted in an error + if (scope.exception()) { + // Get the error from the scope + JSValue error = scope.exception(); + scope.clearException(); + + // Error the writable side and unblock write + stream->error(vm, globalObject, error); + + // Throw the readable's stored error + throwException(globalObject, scope, error); + return false; + } + + // Check if the readable controller now has backpressure + double desiredSize = readableController->desiredSize(); + bool hasBackpressure = desiredSize <= 0; + + // If backpressure state changed and is now true + if (hasBackpressure) { + stream->setBackpressure(vm, globalObject); + } else { + stream->unblockWrite(vm, globalObject); + } + + return true; +} + +void JSTransformStreamDefaultController::error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue error) +{ + auto* stream = this->stream(); + ASSERT(stream); + stream->error(vm, globalObject, error); +} + +void JSTransformStreamDefaultController::terminate(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* stream = this->stream(); + ASSERT(stream); + + // Get the readable controller + auto* readable = stream->readableStream(); + ASSERT(readable); + auto* readableController = readable->controller(); + ASSERT(readableController); + + // Close the readable controller + readableController->close(vm, globalObject); + RETURN_IF_EXCEPTION(scope, void()); + + // Create TypeError for termination + JSC::JSValue error = JSC::createTypeError(globalObject, "The stream has been terminated"_s); + + // Error the writable side and unblock write + // Call TransformStreamErrorWritableAndUnblockWrite operation + stream->errorWritableAndUnblockWrite(vm, globalObject, error); +} + +const ClassInfo JSTransformStreamDefaultController::s_info = { "TransformStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultController) }; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamDefaultController.h b/src/bun.js/bindings/BunTransformStreamDefaultController.h new file mode 100644 index 00000000000000..48faefc48ddceb --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultController.h @@ -0,0 +1,62 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +class JSTransformStream; + +class JSTransformStreamDefaultController final : public JSC::JSNonFinalObject { + using Base = JSC::JSNonFinalObject; + +public: + static JSTransformStreamDefaultController* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSTransformStream* transformStream); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if (mode == JSC::SubspaceAccess::Concurrently) { + return nullptr; + } + + return subspaceForImpl(vm); + } + + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + 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()); + } + + bool enqueue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue chunk); + bool enqueue(JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) { return enqueue(this->vm(), globalObject, chunk); } + void error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue error); + void error(JSC::JSGlobalObject* globalObject, JSC::JSValue error) { this->error(this->vm(), globalObject, error); } + void terminate(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + void terminate(JSC::JSGlobalObject* globalObject) { terminate(this->vm(), globalObject); } + + void clearAlgorithms() + { + m_transformAlgorithm.clear(); + m_flushAlgorithm.clear(); + } + + JSTransformStream* stream() const; + +private: + JSTransformStreamDefaultController(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSTransformStream* transformStream); + + JSC::WriteBarrier m_stream; + JSC::WriteBarrier m_flushPromise; + JSC::WriteBarrier m_transformAlgorithm; + JSC::WriteBarrier m_flushAlgorithm; +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.cpp b/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.cpp new file mode 100644 index 00000000000000..7e7da90f543533 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.cpp @@ -0,0 +1,48 @@ +#include "root.h" + +#include "ErrorCode.h" +#include "BunTransformStreamDefaultControllerConstructor.h" +#include "BunTransformStreamDefaultControllerPrototype.h" +#include + +namespace Bun { + +const JSC::ClassInfo JSTransformStreamDefaultControllerConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultControllerConstructor) }; + +JSTransformStreamDefaultControllerConstructor::JSTransformStreamDefaultControllerConstructor(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +JSTransformStreamDefaultControllerConstructor* JSTransformStreamDefaultControllerConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamDefaultControllerPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSTransformStreamDefaultControllerConstructor* constructor = new (NotNull, JSC::allocateCell(vm)) + JSTransformStreamDefaultControllerConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +void JSTransformStreamDefaultControllerConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamDefaultControllerPrototype* prototype) +{ + Base::finishCreation(vm, 2, "TransformStreamDefaultController"_s, PropertyAdditionMode::WithStructureTransition); + ASSERT(inherits(info())); + + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | 0); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSTransformStreamDefaultControllerConstructor::call(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, "TransformStreamDefaultController constructor cannot be called directly"_s); +} + +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSTransformStreamDefaultControllerConstructor::construct(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, "TransformStreamDefaultController constructor cannot be constructed directly"_s); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.h b/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.h new file mode 100644 index 00000000000000..14f77ff7538f21 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultControllerConstructor.h @@ -0,0 +1,35 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +class JSTransformStreamDefaultControllerPrototype; + +class JSTransformStreamDefaultControllerConstructor final : public JSC::InternalFunction { + using Base = JSC::InternalFunction; + +public: + static JSTransformStreamDefaultControllerConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTransformStreamDefaultControllerPrototype* prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + 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()); + } + +private: + JSTransformStreamDefaultControllerConstructor(JSC::VM& vm, JSC::Structure* structure); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSTransformStreamDefaultControllerPrototype*); + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.cpp b/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.cpp new file mode 100644 index 00000000000000..77e935d34f3063 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.cpp @@ -0,0 +1,108 @@ +#include "root.h" + +#include +#include "BunTransformStreamDefaultControllerPrototype.h" +#include "BunTransformStreamDefaultController.h" + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamDefaultControllerDesiredSize); +static JSC_DECLARE_HOST_FUNCTION(jsTransformStreamDefaultControllerEnqueue); +static JSC_DECLARE_HOST_FUNCTION(jsTransformStreamDefaultControllerError); +static JSC_DECLARE_HOST_FUNCTION(jsTransformStreamDefaultControllerTerminate); + +static const JSC::HashTableValue JSTransformStreamDefaultControllerPrototypeTableValues[] = { + { "enqueue"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsTransformStreamDefaultControllerEnqueue, 1 } }, + { "error"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsTransformStreamDefaultControllerError, 1 } }, + { "terminate"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsTransformStreamDefaultControllerTerminate, 0 } }, + { "desiredSize"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, + { HashTableValue::GetterSetterType, jsTransformStreamDefaultControllerDesiredSize, 0 } }, +}; + +const JSC::ClassInfo JSTransformStreamDefaultControllerPrototype::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultControllerPrototype) }; + +JSTransformStreamDefaultControllerPrototype::JSTransformStreamDefaultControllerPrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) +{ +} + +JSTransformStreamDefaultControllerPrototype* JSTransformStreamDefaultControllerPrototype::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + structure->setMayBePrototype(true); + JSTransformStreamDefaultControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) + JSTransformStreamDefaultControllerPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +void JSTransformStreamDefaultControllerPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + reifyStaticProperties(vm, info(), JSTransformStreamDefaultControllerPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +JSC_DEFINE_CUSTOM_GETTER(jsTransformStreamDefaultControllerDesiredSize, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* thisObject = jsDynamicCast(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return throwVMTypeError(globalObject, scope, "Receiver must be a TransformStreamDefaultController"_s); + + // Return the desired size per spec + return JSValue::encode(jsNumber(0)); // Placeholder +} + +JSC_DEFINE_HOST_FUNCTION(jsTransformStreamDefaultControllerEnqueue, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* controller = jsDynamicCast(callFrame->thisValue()); + if (UNLIKELY(!controller)) + return throwVMTypeError(globalObject, scope, "Receiver must be a TransformStreamDefaultController"_s); + + JSValue chunk = callFrame->argument(0); + + if (!controller->enqueue(globalObject, chunk)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsTransformStreamDefaultControllerError, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* controller = jsDynamicCast(callFrame->thisValue()); + if (UNLIKELY(!controller)) + return throwVMTypeError(globalObject, scope, "Receiver must be a TransformStreamDefaultController"_s); + + controller->error(vm, globalObject, callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsTransformStreamDefaultControllerTerminate, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* controller = jsDynamicCast(callFrame->thisValue()); + if (UNLIKELY(!controller)) + return throwVMTypeError(globalObject, scope, "Receiver must be a TransformStreamDefaultController"_s); + + controller->terminate(globalObject); + return JSValue::encode(jsUndefined()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.h b/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.h new file mode 100644 index 00000000000000..96d3fb8b929bbc --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamDefaultControllerPrototype.h @@ -0,0 +1,31 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +class JSTransformStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { + using Base = JSC::JSNonFinalObject; + +public: + static JSTransformStreamDefaultControllerPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamDefaultControllerPrototype, Base); + 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: + JSTransformStreamDefaultControllerPrototype(JSC::VM& vm, JSC::Structure* structure); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamPrototype.cpp b/src/bun.js/bindings/BunTransformStreamPrototype.cpp new file mode 100644 index 00000000000000..32849f67cd92d3 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamPrototype.cpp @@ -0,0 +1,93 @@ +#include "root.h" + +#include "BunTransformStreamPrototype.h" +#include "BunTransformStream.h" +#include "BunBuiltinNames.h" +#include "ZigGlobalObject.h" + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamReadableGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamWritableGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamConstructor); + +// All static properties for the prototype +static const HashTableValue JSTransformStreamPrototypeTableValues[] = { + { "readable"_s, + static_cast(PropertyAttribute::ReadOnly), + NoIntrinsic, + { HashTableValue::GetterSetterType, jsTransformStreamReadableGetter, nullptr } }, + { "writable"_s, + static_cast(PropertyAttribute::ReadOnly), + NoIntrinsic, + { HashTableValue::GetterSetterType, jsTransformStreamWritableGetter, nullptr } }, +}; + +JSC_DEFINE_CUSTOM_GETTER(jsTransformStreamReadableGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = JSC::getVM(globalObject); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* thisObject = jsDynamicCast(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + return throwVMTypeError(globalObject, scope, "Cannot get readable property of non-TransformStream"_s); + } + + ASSERT(thisObject->readable()); + return JSValue::encode(thisObject->readable()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsTransformStreamWritableGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = JSC::getVM(globalObject); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* thisObject = jsDynamicCast(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + return throwVMTypeError(globalObject, scope, "Cannot get writable property of non-TransformStream"_s); + } + + ASSERT(thisObject->writable()); + return JSValue::encode(thisObject->writable()); +} + +JSTransformStreamPrototype* JSTransformStreamPrototype::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSTransformStreamPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSTransformStreamPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +template +JSC::GCClient::IsoSubspace* JSTransformStreamPrototype::subspaceFor(JSC::VM& vm) +{ + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamPrototype, Base); + return &vm.plainObjectSpace(); +} + +JSTransformStreamPrototype::JSTransformStreamPrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) +{ +} + +void JSTransformStreamPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties( + vm, + JSTransformStream::info(), + JSTransformStreamPrototypeTableValues, + *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +const ClassInfo JSTransformStreamPrototype::s_info = { "TransformStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamPrototype) }; + +Structure* JSTransformStreamPrototype::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType::ObjectType, StructureFlags), info()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunTransformStreamPrototype.h b/src/bun.js/bindings/BunTransformStreamPrototype.h new file mode 100644 index 00000000000000..6b7960f8a632c1 --- /dev/null +++ b/src/bun.js/bindings/BunTransformStreamPrototype.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace Bun { + +class JSTransformStreamPrototype final : public JSC::JSNonFinalObject { + using Base = JSC::JSNonFinalObject; + +public: + static JSTransformStreamPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype); + +private: + JSTransformStreamPrototype(JSC::VM& vm, JSC::Structure* structure); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; +} diff --git a/src/bun.js/bindings/BunWritableStream.cpp b/src/bun.js/bindings/BunWritableStream.cpp new file mode 100644 index 00000000000000..b188a69a10c44c --- /dev/null +++ b/src/bun.js/bindings/BunWritableStream.cpp @@ -0,0 +1,438 @@ +#include "root.h" + +#include "BunStreamStructures.h" +#include "BunWritableStream.h" +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStreamDefaultWriter.h" +#include "BunStreamStructures.h" +#include "BunStreamInlines.h" +#include "ZigGlobalObject.h" + +#include "BunPromiseInlines.h" + +namespace Bun { + +using namespace JSC; + +// Forward declarations +namespace Operations { +void WritableStreamStartErroring(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStream* stream, JSC::JSValue reason); +void WritableStreamFinishErroring(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStream* stream); +void WritableStreamDefaultWriterEnsureReadyPromiseRejected(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStreamDefaultWriter* writer, JSC::JSValue reason); +} // namespace Operations + +// WritableStream implementation +const ClassInfo JSWritableStream::s_info = { "WritableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStream) }; + +JSWritableStream::JSWritableStream(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSWritableStream::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +JSWritableStream* JSWritableStream::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + Structure* streamStructure = streams.structure(domGlobalObject); + JSWritableStream* stream = new (NotNull, allocateCell(vm)) + JSWritableStream(vm, streamStructure ? streamStructure : structure); + stream->finishCreation(vm); + return stream; +} + +template +void JSWritableStream::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + visitor.append(thisObject->m_controller); + visitor.append(thisObject->m_writer); + visitor.append(thisObject->m_closeRequest); + visitor.append(thisObject->m_inFlightWriteRequest); + visitor.append(thisObject->m_inFlightCloseRequest); + visitor.append(thisObject->m_storedError); +} + +DEFINE_VISIT_CHILDREN(JSWritableStream); + +Structure* JSWritableStream::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, + TypeInfo(ObjectType, StructureFlags), info()); +} + +bool JSWritableStream::isLocked() const +{ + return !!m_writer; +} + +JSValue JSWritableStream::error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue error) +{ + if (m_state == State::Writable) { + Operations::WritableStreamStartErroring(vm, globalObject, this, error); + } else if (m_state == State::Erroring) { + Operations::WritableStreamFinishErroring(vm, globalObject, this); + } + return jsUndefined(); +} + +void JSWritableStream::setStoredError(JSC::VM& vm, JSC::JSValue error) +{ + m_storedError.set(vm, this, error); +} + +namespace Operations { + +void WritableStreamStartErroring(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStream* stream, JSC::JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Assert: stream.[[storedError]] is undefined. + ASSERT(!stream->storedError() || stream->storedError().isUndefined()); + + // 2. Assert: stream.[[state]] is "writable". + ASSERT(stream->state() == JSWritableStream::State::Writable); + + // 3. Let controller be stream.[[writableStreamController]]. + auto* controller = stream->controller(); + ASSERT(controller); + + // 4. Set stream.[[state]] to "erroring". + stream->setState(JSWritableStream::State::Erroring); + + // 5. Set stream.[[storedError]] to reason. + stream->setStoredError(vm, reason); + + // 6. Let writer be stream.[[writer]]. + auto* writer = stream->writer(); + + // 7. If writer is not undefined, perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason). + if (writer) + WritableStreamDefaultWriterEnsureReadyPromiseRejected(vm, globalObject, writer, reason); + + // 8. If ! WritableStreamHasOperationMarkedInFlight(stream) is false and controller.[[started]] is true, + // perform ! WritableStreamFinishErroring(stream). + if (!stream->hasOperationMarkedInFlight() && controller->started()) + WritableStreamFinishErroring(vm, globalObject, stream); + + RETURN_IF_EXCEPTION(scope, void()); +} + +void WritableStreamFinishErroring(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStream* stream) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Assert: stream.[[state]] is "erroring". + ASSERT(stream->state() == JSWritableStream::State::Erroring); + + // 2. Assert: ! WritableStreamHasOperationMarkedInFlight(stream) is false. + ASSERT(!stream->hasOperationMarkedInFlight()); + + // 3. Set stream.[[state]] to "errored". + stream->setState(JSWritableStream::State::Errored); + + // 4. Perform ! WritableStreamDefaultControllerErrorSteps(stream.[[writableStreamController]]). + stream->controller()->errorSteps(); + + JSValue storedError = stream->storedError(); + + // 5. Let writer be stream.[[writer]]. + auto* writer = stream->writer(); + + // 6. If writer is not undefined, + if (writer) { + // a. Let writeRequests be writer.[[writeRequests]]. + // b. Set writer.[[writeRequests]] to an empty List. + // c. For each writeRequest of writeRequests, + // 1. Reject writeRequest with stream.[[storedError]]. + writer->rejectWriteRequests(vm, globalObject, storedError); + } + + JSPromise* abortPromise = stream->pendingAbortRequestPromise(); + + // 7. Let pendingAbortRequest be stream.[[pendingAbortRequest]]. + // 8. If pendingAbortRequest is undefined, return. + if (!abortPromise) + return; + + JSValue abortReason = stream->pendingAbortRequestReason(); + bool wasAlreadyErroring = stream->wasAlreadyErroring(); + stream->clearPendingAbortRequest(); + + // 10. If pendingAbortRequest.[[wasAlreadyErroring]] is true, + if (wasAlreadyErroring) { + // a. Reject pendingAbortRequest.[[promise]] with pendingAbortRequest.[[reason]]. + abortPromise->reject(globalObject, abortReason); + // b. Return. + return; + } + + // 11. Let abortAlgorithm be stream.[[writableStreamController]].[[abortAlgorithm]]. + // 12. Let result be the result of performing abortAlgorithm with argument pendingAbortRequest.[[reason]]. + JSValue result = stream->controller()->performAbortAlgorithm(abortReason); + + // 13. Upon fulfillment of result, + // a. Resolve pendingAbortRequest.[[promise]] with undefined. + // 14. Upon rejection of result with reason r, + // a. Reject pendingAbortRequest.[[promise]] with r. + if (JSPromise* resultPromise = jsDynamicCast(result)) { + Bun::then(globalObject, resultPromise, + jsFunctionResolveAbortPromiseWithUndefined, + jsFunctionRejectAbortPromiseWithReason, + abortPromise); + } else { + // If not a promise, treat as fulfilled + abortPromise->fulfillWithNonPromise(globalObject, jsUndefined()); + } +} + +void WritableStreamUpdateBackpressure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStream* stream, bool backpressure) +{ + ASSERT(stream->state() == JSWritableStream::State::Writable); + ASSERT(!stream->isCloseQueuedOrInFlight()); + + JSWritableStreamDefaultWriter* writer = stream->writer(); + + if (writer && backpressure != stream->backpressure()) { + if (backpressure) { + writer->resetReadyPromise(); + } else { + ASSERT(!backpressure); + writer->resolveReadyPromise(); + } + } + + stream->setBackpressure(backpressure); +} + +void WritableStreamDefaultWriterEnsureReadyPromiseRejected(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStreamDefaultWriter* writer, JSC::JSValue reason) +{ + // 1. If writer.[[readyPromise]] is pending, reject it with reason. + JSPromise* readyPromise = writer->ready(); + if (readyPromise && readyPromise->status(vm) == JSPromise::Status::Pending) + readyPromise->rejectAsHandled(globalObject, reason); + + // 2. Set writer.[[readyPromise]] to a promise rejected with reason. + JSPromise* newPromise = JSPromise::rejectedPromise(globalObject, reason); + writer->setReady(vm, newPromise); +} + +} // namespace Operations + +JSValue JSWritableStream::abort(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. + if (isLocked()) + return JSPromise::rejectedPromise(globalObject, createTypeError(globalObject, "Cannot abort a locked WritableStream"_s)); + + // 2. Let state be this.[[state]]. + const auto state = m_state; + + // 3. If state is "closed" or state is "errored", return a promise resolved with undefined. + if (state == State::Closed || state == State::Errored) + return Bun::createFulfilledPromise(globalObject, jsUndefined()); + + // 4. If this.[[pendingAbortRequest]] is not undefined, return this.[[pendingAbortRequest]].[[promise]]. + if (auto promise = m_pendingAbortRequestPromise.get()) + return promise; + + // 5. Assert: state is "writable" or state is "erroring". + ASSERT(state == State::Writable || state == State::Erroring); + + // 6. Let wasAlreadyErroring be false. + bool wasAlreadyErroring = false; + + // 7. If state is "erroring", + if (state == State::Erroring) { + // a. Set wasAlreadyErroring to true. + wasAlreadyErroring = true; + // b. Set reason to undefined. + reason = jsUndefined(); + } + + // 8. Let promise be a new promise. + JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure()); + + // 9. Set this.[[pendingAbortRequest]] to record {[[promise]]: promise, [[reason]]: reason, [[wasAlreadyErroring]]: wasAlreadyErroring}. + m_pendingAbortRequestPromise.set(vm, this, promise); + m_pendingAbortRequestReason.set(vm, this, reason); + m_wasAlreadyErroring = wasAlreadyErroring; + + // 10. If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(this, reason). + if (!wasAlreadyErroring) + Operations::WritableStreamStartErroring(vm, globalObject, this, reason); + + // 11. If this.[[state]] is "errored", perform ! WritableStreamFinishErroring(this). + if (m_state == State::Errored) + Operations::WritableStreamFinishErroring(vm, globalObject, this); + + // 12. Return promise. + return promise; +} + +JSValue JSWritableStream::close(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. + if (isLocked()) + return JSPromise::rejectedPromise(globalObject, createTypeError(globalObject, "Cannot close a locked WritableStream"_s)); + + // 2. If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception. + if (m_closeRequest || m_inFlightCloseRequest) + return JSPromise::rejectedPromise(globalObject, createTypeError(globalObject, "Cannot close an already closing stream"_s)); + + // 3. Let state be this.[[state]]. + const auto state = m_state; + + // 4. If state is "closed", return a promise rejected with a TypeError exception. + if (state == State::Closed) + return JSPromise::rejectedPromise(globalObject, createTypeError(globalObject, "Cannot close an already closed stream"_s)); + + // 5. If state is "errored", return a promise rejected with this.[[storedError]]. + if (state == State::Errored) + return JSPromise::rejectedPromise(globalObject, m_storedError.get()); + + // 6. If state is "erroring", return a promise rejected with this.[[storedError]]. + if (state == State::Erroring) + return JSPromise::rejectedPromise(globalObject, m_storedError.get()); + + // 7. Assert: state is "writable". + ASSERT(state == State::Writable); + + // 8. Let closeRequest be ! WritableStreamCreateCloseRequest(this). + JSPromise* closeRequest = JSPromise::create(vm, globalObject->promiseStructure()); + m_closeRequest.set(vm, this, closeRequest); + + // 9. Perform ! WritableStreamDefaultControllerClose(this.[[controller]]). + controller()->close(globalObject); + + // 10. Return closeRequest.[[promise]]. + return closeRequest; +} + +void JSWritableStream::finishInFlightClose() +{ + JSGlobalObject* globalObject = m_controller->globalObject(); + + // 1. Assert: this.[[inFlightCloseRequest]] is not undefined. + ASSERT(m_inFlightCloseRequest); + + // 2. Resolve this.[[inFlightCloseRequest]] with undefined. + m_inFlightCloseRequest->resolve(globalObject, jsUndefined()); + + // 3. Set this.[[inFlightCloseRequest]] to undefined. + m_inFlightCloseRequest.clear(); + + // 4. Set this.[[state]] to "closed". + m_state = State::Closed; + + // 5. Let writer be this.[[writer]]. + auto* writer = this->writer(); + + // 6. If writer is not undefined, + if (writer) { + // a. Resolve writer.[[closedPromise]] with undefined. + writer->resolveClosedPromise(globalObject, jsUndefined()); + } +} + +void JSWritableStream::updateBackpressure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool backpressure) +{ +} + +void JSWritableStream::finishInFlightCloseWithError(JSValue error) +{ + VM& vm = m_controller->vm(); + JSGlobalObject* globalObject = m_controller->globalObject(); + + // 1. Assert: this.[[inFlightCloseRequest]] is not undefined. + ASSERT(m_inFlightCloseRequest); + + // 2. Reject this.[[inFlightCloseRequest]] with error. + m_inFlightCloseRequest->reject(globalObject, error); + + // 3. Set this.[[inFlightCloseRequest]] to undefined. + m_inFlightCloseRequest.clear(); + + // 4. Set this.[[state]] to "errored". + m_state = State::Errored; + + // 5. Set this.[[storedError]] to error. + m_storedError.set(vm, this, error); + + // 6. Let writer be this.[[writer]]. + auto* writer = this->writer(); + + // 7. If writer is not undefined, + if (writer) { + // a. Reject writer.[[closedPromise]] with error. + writer->rejectClosedPromise(globalObject, error); + } +} + +JSWritableStreamDefaultController* JSWritableStream::controller() const +{ + return jsCast(m_controller.get()); +} + +void JSWritableStream::setController(JSC::VM& vm, JSWritableStreamDefaultController* controller) +{ + m_controller.set(vm, this, controller); +} + +JSWritableStreamDefaultWriter* JSWritableStream::writer() const +{ + return jsCast(m_writer.get()); +} + +void JSWritableStream::setWriter(VM& vm, JSWritableStreamDefaultWriter* writer) +{ + m_writer.set(vm, this, writer); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionResolveAbortPromiseWithUndefined, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSPromise* promise = jsDynamicCast(callFrame->argument(1)); + if (!promise) + return JSValue::encode(jsUndefined()); + promise->fulfillWithNonPromise(globalObject, jsUndefined()); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionRejectAbortPromiseWithReason, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSPromise* promise = jsDynamicCast(callFrame->argument(1)); + if (!promise) + return JSValue::encode(jsUndefined()); + promise->reject(globalObject, callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +JSC::GCClient::IsoSubspace* JSWritableStream::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForWritableStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStream = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForWritableStream.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStream = std::forward(space); }); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStream.h b/src/bun.js/bindings/BunWritableStream.h new file mode 100644 index 00000000000000..c4515bee486c58 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStream.h @@ -0,0 +1,99 @@ +#pragma once + +#include "root.h" +#include "JavaScriptCore/JSObject.h" + +namespace Bun { + +using namespace JSC; + +class JSWritableStreamDefaultController; +class JSWritableStreamDefaultWriter; + +class JSWritableStream final : public JSNonFinalObject { +public: + using Base = JSNonFinalObject; + + enum class State { + Writable, + Erroring, + Errored, + Closed + }; + + static JSWritableStream* create(VM&, JSGlobalObject*, Structure*); + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + bool isLocked() const; + JSValue error(JSC::VM& vm, JSC::JSGlobalObject*, JSC::JSValue error); + JSValue error(JSC::JSGlobalObject* globalObject, JSC::JSValue error) { return this->error(this->vm(), globalObject, error); } + JSValue abort(JSC::VM& vm, JSC::JSGlobalObject*, JSC::JSValue reason); + JSValue abort(JSC::JSGlobalObject* globalObject, JSC::JSValue reason) { return abort(this->vm(), globalObject, reason); } + JSValue close(JSC::VM& vm, JSC::JSGlobalObject*); + JSValue close(JSC::JSGlobalObject* globalObject) { return close(this->vm(), globalObject); } + void write(JSC::VM& vm, JSC::JSGlobalObject*, JSC::JSValue chunk); + void write(JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) { return write(this->vm(), globalObject, chunk); } + void finishInFlightClose(); + void finishInFlightCloseWithError(JSValue error); + + bool isCloseQueuedOrInFlight() const { return m_closeRequest || m_inFlightCloseRequest; } + bool isCloseQueued() const { return !!m_closeRequest; } + bool isInFlightClose() const { return !!m_inFlightCloseRequest; } + State state() const { return m_state; } + void setState(State state) { m_state = state; } + JSWritableStreamDefaultController* controller() const; + void setController(JSC::VM& vm, JSWritableStreamDefaultController* controller); + void setController(JSWritableStreamDefaultController* controller) { setController(this->vm(), controller); } + JSWritableStreamDefaultWriter* writer() const; + void setWriter(JSC::VM& vm, JSWritableStreamDefaultWriter* writer); + void setWriter(JSWritableStreamDefaultWriter* writer) { setWriter(this->vm(), writer); } + JSValue storedError() const { return m_storedError.get(); } + void setStoredError(JSC::VM& vm, JSC::JSValue error); + void setStoredError(JSC::JSValue error) { setStoredError(this->vm(), error); } + JSPromise* pendingAbortRequestPromise() const { return m_pendingAbortRequestPromise.get(); } + JSValue pendingAbortRequestReason() const { return m_pendingAbortRequestReason.get(); } + bool wasAlreadyErroring() const { return m_wasAlreadyErroring; } + void clearPendingAbortRequest() + { + m_pendingAbortRequestPromise.clear(); + m_pendingAbortRequestReason.clear(); + m_wasAlreadyErroring = false; + } + void updateBackpressure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool backpressure); + bool backpressure() const { return m_backpressure; } + bool hasOperationMarkedInFlight() const { return m_inFlightWriteRequest || m_inFlightCloseRequest; } + void setBackpressure(bool backpressure) { m_backpressure = backpressure; } + +private: + JSWritableStream(VM&, Structure*); + void finishCreation(VM&); + + State m_state { State::Writable }; + mutable WriteBarrier m_controller; + mutable WriteBarrier m_writer; + mutable WriteBarrier m_closeRequest; + mutable WriteBarrier m_inFlightWriteRequest; + mutable WriteBarrier m_inFlightCloseRequest; + mutable WriteBarrier m_storedError; + mutable WriteBarrier m_pendingAbortRequestPromise; + mutable WriteBarrier m_pendingAbortRequestReason; + bool m_wasAlreadyErroring { false }; + bool m_backpressure { false }; +}; + +JSC_DECLARE_HOST_FUNCTION(jsFunctionResolveAbortPromiseWithUndefined); +JSC_DECLARE_HOST_FUNCTION(jsFunctionRejectAbortPromiseWithReason); + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamConstructor.cpp b/src/bun.js/bindings/BunWritableStreamConstructor.cpp new file mode 100644 index 00000000000000..dae70d26fcf491 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamConstructor.cpp @@ -0,0 +1,249 @@ +#include "BunWritableStreamConstructor.h" +#include "BunWritableStreamPrototype.h" +#include "BunWritableStream.h" +#include "BunWritableStreamDefaultController.h" +#include "ZigGlobalObject.h" +#include + +namespace Bun { + +using namespace JSC; + +// Constructor Implementation +const ClassInfo JSWritableStreamConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamConstructor) }; + +JSWritableStreamConstructor::JSWritableStreamConstructor(VM& vm, Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +JSWritableStreamConstructor* JSWritableStreamConstructor::create(VM& vm, JSGlobalObject* globalObject, JSWritableStreamPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSWritableStreamConstructor* constructor = new (NotNull, allocateCell(vm)) JSWritableStreamConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +Structure* JSWritableStreamConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info()); +} + +static void underlyingSinkFromJS( + JSC::VM& vm, JSGlobalObject* globalObject, JSValue underlyingSinkValue, + JSC::JSValue strategyValue, + JSC::JSValue& highWaterMarkValue, + JSC::JSValue& sizeAlgorithmValue, + JSC::JSValue& closeAlgorithmValue, + JSC::JSValue& abortAlgorithmValue, + JSC::JSValue& writeAlgorithmValue, + JSC::JSValue& startAlgorithmValue) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // Default values + startAlgorithmValue = jsUndefined(); + writeAlgorithmValue = jsUndefined(); + closeAlgorithmValue = jsUndefined(); + abortAlgorithmValue = jsUndefined(); + + auto& propertyNames = Bun::builtinNames(vm); + + // Extract strategy parameters + if (!strategyValue.isUndefined()) { + JSObject* strategyObj = strategyValue.getObject(); + if (!strategyObj) { + throwVMTypeError(globalObject, scope, "WritableStream strategy must be an object"_s); + return; + } + + // Get highWaterMark + highWaterMarkValue = strategyObj->getIfPropertyExists(globalObject, propertyNames.highWaterMarkPublicName()); + RETURN_IF_EXCEPTION(scope, void()); + if (!highWaterMarkValue || highWaterMarkValue.isUndefined()) { + highWaterMarkValue = jsNumber(1); + } + + // Get size algorithm + sizeAlgorithmValue = strategyObj->getIfPropertyExists(globalObject, vm.propertyNames->size); + RETURN_IF_EXCEPTION(scope, void()); + + if (!sizeAlgorithmValue) { + sizeAlgorithmValue = jsUndefined(); + } + + if (!sizeAlgorithmValue.isUndefined() && !sizeAlgorithmValue.isCallable()) { + throwVMTypeError(globalObject, scope, "WritableStream strategy size must be callable"_s); + return; + } + strategyValue = sizeAlgorithmValue; + } else { + highWaterMarkValue = jsNumber(1); + sizeAlgorithmValue = jsUndefined(); + } + + // If no underlying sink, use defaults and return + if (underlyingSinkValue.isUndefinedOrNull()) { + return; + } + + JSObject* underlyingSink = underlyingSinkValue.getObject(); + if (!underlyingSink) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink must be an object"_s); + return; + } + + // Get start method + startAlgorithmValue = underlyingSink->getIfPropertyExists(globalObject, propertyNames.startPublicName()); + RETURN_IF_EXCEPTION(scope, void()); + if (!startAlgorithmValue) { + startAlgorithmValue = jsUndefined(); + } + + if (!startAlgorithmValue.isUndefined() && !startAlgorithmValue.isCallable()) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink start must be callable"_s); + return; + } + + // Get write method + writeAlgorithmValue = underlyingSink->getIfPropertyExists(globalObject, propertyNames.writePublicName()); + RETURN_IF_EXCEPTION(scope, void()); + if (!writeAlgorithmValue) { + writeAlgorithmValue = jsUndefined(); + } + + if (!writeAlgorithmValue.isUndefined() && !writeAlgorithmValue.isCallable()) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink write must be callable"_s); + return; + } + + // Get close method + closeAlgorithmValue = underlyingSink->getIfPropertyExists(globalObject, propertyNames.closePublicName()); + RETURN_IF_EXCEPTION(scope, void()); + if (!closeAlgorithmValue) { + closeAlgorithmValue = jsUndefined(); + } + + if (!closeAlgorithmValue.isUndefined() && !closeAlgorithmValue.isCallable()) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink close must be callable"_s); + return; + } + + // Get abort method + abortAlgorithmValue = underlyingSink->getIfPropertyExists(globalObject, Identifier::fromString(vm, "abort"_s)); + RETURN_IF_EXCEPTION(scope, void()); + if (!abortAlgorithmValue) { + abortAlgorithmValue = jsUndefined(); + } + + if (!abortAlgorithmValue.isUndefined() && !abortAlgorithmValue.isCallable()) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink abort must be callable"_s); + return; + } + + // Check for type property which is currently reserved + JSValue typeValue = underlyingSink->getIfPropertyExists(globalObject, Identifier::fromString(vm, "type"_s)); + RETURN_IF_EXCEPTION(scope, void()); + if (!typeValue) { + typeValue = jsUndefined(); + } + + if (!typeValue.isUndefined()) { + throwVMTypeError(globalObject, scope, "WritableStream underlying sink type property is reserved for future use"_s); + return; + } +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrivateConstructor, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + // Similar to above but for internal usage + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + Structure* structure = streams.structure(domGlobalObject); + JSWritableStream* stream = JSWritableStream::create(vm, globalObject, structure); + RETURN_IF_EXCEPTION(scope, {}); + + return JSValue::encode(stream); +} + +void JSWritableStreamConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSWritableStreamPrototype* prototype) +{ + Base::finishCreation(vm, 1, "WritableStream"_s, PropertyAdditionMode::WithStructureTransition); + + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSC_DEFINE_HOST_FUNCTION(JSWritableStreamConstructor::call, (JSGlobalObject * globalObject, CallFrame*)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + return throwVMTypeError(globalObject, scope, "Cannot call WritableStream"_s); +} + +JSC_DEFINE_HOST_FUNCTION(JSWritableStreamConstructor::construct, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* zigGlobalObject = jsDynamicCast(globalObject); + if (UNLIKELY(!zigGlobalObject)) + return throwVMTypeError(globalObject, scope, "Invalid global object"_s); + + JSObject* newTarget = asObject(callFrame->newTarget()); + Structure* structure = zigGlobalObject->streams().structure(zigGlobalObject); + auto* constructor = zigGlobalObject->streams().constructor(zigGlobalObject); + + if (!(!newTarget || newTarget != constructor)) { + if (newTarget) { + structure = JSC::InternalFunction::createSubclassStructure(getFunctionRealm(globalObject, newTarget), newTarget, structure); + } else { + structure = JSC::InternalFunction::createSubclassStructure(globalObject, constructor, structure); + } + } + + RETURN_IF_EXCEPTION(scope, {}); + + // Extract constructor arguments per spec: + // new WritableStream(underlyingSink = {}, strategy = {}) + JSValue underlyingSinkArg = callFrame->argument(0); + JSValue strategyArg = callFrame->argument(1); + + // Create the underlying writable stream + JSWritableStream* writableStream = JSWritableStream::create(vm, globalObject, structure); + RETURN_IF_EXCEPTION(scope, {}); + + double highWaterMark = 1; + + JSC::JSValue highWaterMarkValue; + JSC::JSValue sizeAlgorithmValue; + JSC::JSValue closeAlgorithmValue; + JSC::JSValue abortAlgorithmValue; + JSC::JSValue writeAlgorithmValue; + JSC::JSValue startAlgorithmValue; + underlyingSinkFromJS(vm, globalObject, underlyingSinkArg, strategyArg, highWaterMarkValue, sizeAlgorithmValue, closeAlgorithmValue, abortAlgorithmValue, writeAlgorithmValue, startAlgorithmValue); + RETURN_IF_EXCEPTION(scope, {}); + + // Set up the controller + Structure* controllerStructure = zigGlobalObject->streams().structure(zigGlobalObject); + auto* controller = JSWritableStreamDefaultController::create( + vm, + globalObject, + controllerStructure, + writableStream, + highWaterMark, + abortAlgorithmValue.getObject(), + closeAlgorithmValue.getObject(), + writeAlgorithmValue.getObject(), + sizeAlgorithmValue.getObject()); + RETURN_IF_EXCEPTION(scope, {}); + writableStream->setController(controller); + + RELEASE_AND_RETURN(scope, JSValue::encode(writableStream)); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamConstructor.h b/src/bun.js/bindings/BunWritableStreamConstructor.h new file mode 100644 index 00000000000000..6dcae9eb3ad09e --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamConstructor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +class JSWritableStreamPrototype; + +using namespace JSC; + +class JSWritableStreamConstructor final : public InternalFunction { +public: + using Base = InternalFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + static JSWritableStreamConstructor* create(VM&, JSGlobalObject*, JSWritableStreamPrototype*); + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(VM& vm) + { + if constexpr (mode == SubspaceAccess::Concurrently) + return nullptr; + return &vm.internalFunctionSpace(); + } + + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); + static EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSGlobalObject*, CallFrame*); + static EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSGlobalObject*, CallFrame*); + +private: + JSWritableStreamConstructor(VM& vm, Structure* structure); + void finishCreation(VM& vm, JSGlobalObject* globalObject, JSWritableStreamPrototype* prototype); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultController.cpp b/src/bun.js/bindings/BunWritableStreamDefaultController.cpp new file mode 100644 index 00000000000000..51ab3cd3be2050 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultController.cpp @@ -0,0 +1,338 @@ +#include "root.h" + +#include "AbortController.h" +#include "JSDOMConvertInterface.h" +#include +#include "JSAbortController.h" +#include + +#include "ZigGlobalObject.h" +#include +#include + +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStream.h" +#include "JSAbortSignal.h" +#include "IDLTypes.h" +#include "JSDOMBinding.h" +#include "BunStreamStructures.h" +#include +#include "BunStreamInlines.h" +#include "JSAbortSignal.h" +#include "DOMJITIDLType.h" +#include + +namespace Bun { + +JSWritableStream* JSWritableStreamDefaultController::stream() const +{ + return jsDynamicCast(m_stream.get()); +} + +void JSWritableStreamDefaultController::setStream(JSC::VM& vm, JSWritableStream* stream) { m_stream.set(vm, this, stream); } +void JSWritableStreamDefaultController::setAbortAlgorithm(JSC::VM& vm, JSC::JSObject* abortAlgorithm) { m_abortAlgorithm.set(vm, this, abortAlgorithm); } +void JSWritableStreamDefaultController::setCloseAlgorithm(JSC::VM& vm, JSC::JSObject* closeAlgorithm) { m_closeAlgorithm.set(vm, this, closeAlgorithm); } +void JSWritableStreamDefaultController::setWriteAlgorithm(JSC::VM& vm, JSC::JSObject* writeAlgorithm) { m_writeAlgorithm.set(vm, this, writeAlgorithm); } + +JSC::GCClient::IsoSubspace* JSWritableStreamDefaultController::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForWritableStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStreamDefaultController = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForWritableStreamDefaultController.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStreamDefaultController = std::forward(space); }); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultControllerCloseFulfill, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(callFrame->argument(1)); + if (UNLIKELY(!stream)) + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultController.close called with invalid stream"_s); + + stream->finishInFlightClose(); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultControllerCloseReject, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(callFrame->argument(1)); + if (UNLIKELY(!stream)) + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultController.close called with invalid stream"_s); + + stream->finishInFlightCloseWithError(callFrame->argument(0)); + return JSValue::encode(jsUndefined()); +} + +JSWritableStreamDefaultController* JSWritableStreamDefaultController::create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::Structure* structure, + JSWritableStream* stream, + double highWaterMark, + JSC::JSObject* abortAlgorithm, + JSC::JSObject* closeAlgorithm, + JSC::JSObject* writeAlgorithm, + JSC::JSObject* sizeAlgorithm) +{ + JSWritableStreamDefaultController* controller = new ( + NotNull, JSC::allocateCell(vm)) + JSWritableStreamDefaultController(vm, structure); + + controller->finishCreation(vm); + if (abortAlgorithm) + controller->m_abortAlgorithm.setMayBeNull(vm, controller, abortAlgorithm); + else + controller->m_abortAlgorithm.clear(); + if (closeAlgorithm) + controller->m_closeAlgorithm.setMayBeNull(vm, controller, closeAlgorithm); + else + controller->m_closeAlgorithm.clear(); + if (writeAlgorithm) + controller->m_writeAlgorithm.setMayBeNull(vm, controller, writeAlgorithm); + else + controller->m_writeAlgorithm.clear(); + + if (stream) + controller->m_stream.set(vm, controller, stream); + else + controller->m_stream.clear(); + + controller->queue().initialize(vm, globalObject, highWaterMark, controller, sizeAlgorithm); + + return controller; +} + +void JSWritableStreamDefaultController::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); + m_abortController.initLater([](const JSC::LazyProperty::Initializer& init) { + auto* lexicalGlobalObject = init.owner->globalObject(); + Zig::GlobalObject* globalObject = defaultGlobalObject(lexicalGlobalObject); + auto& scriptExecutionContext = *globalObject->scriptExecutionContext(); + Ref abortController = WebCore::AbortController::create(scriptExecutionContext); + JSAbortController* abortControllerValue = jsCast(WebCore::toJSNewlyCreated>(*lexicalGlobalObject, *globalObject, WTFMove(abortController))); + init.set(abortControllerValue); + }); +} + +WebCore::AbortSignal& JSWritableStreamDefaultController::signal() const +{ + auto* abortController = m_abortController.getInitializedOnMainThread(this); + auto& impl = abortController->wrapped(); + return impl.signal(); +} + +Ref JSWritableStreamDefaultController::abortSignal() const +{ + auto* abortController = m_abortController.getInitializedOnMainThread(this); + auto& impl = abortController->wrapped(); + return impl.protectedSignal(); +} + +JSC::JSValue JSWritableStreamDefaultController::error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Let stream be this.[[stream]]. + JSWritableStream* stream = this->stream(); + + // 2. Assert: stream is not undefined. + ASSERT(stream); + + // 3. Let state be stream.[[state]]. + auto state = stream->state(); + + // 4. Assert: state is "writable". + if (state != JSWritableStream::State::Writable) + return throwTypeError(globalObject, scope, "WritableStreamDefaultController.error called on non-writable stream"_s); + + // 5. Perform ! WritableStreamDefaultControllerError(this, error). + m_writeAlgorithm.clear(); + m_closeAlgorithm.clear(); + m_abortAlgorithm.clear(); + m_queue.clearAlgorithms(); + + stream->error(vm, globalObject, reason); + + return jsUndefined(); +} + +void JSWritableStreamDefaultController::write(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Let stream be this.[[stream]]. + JSWritableStream* stream = this->stream(); + ASSERT(stream); + + // 2. If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError. + if (stream->isCloseQueuedOrInFlight()) { + throwTypeError(globalObject, scope, "Cannot write to a stream that is closed or closing"_s); + return; + } + + // 3. If stream.[[state]] is not "writable", return a promise rejected with a TypeError. + if (stream->state() != JSWritableStream::State::Writable) { + throwTypeError(globalObject, scope, "Cannot write to a stream that is not writable"_s); + return; + } + + // 4. Let sizeAlgorithm be this.[[strategySizeAlgorithm]]. + // 5. Let chunkSize be ? Call(sizeAlgorithm, undefined, « chunk »). + // 6. Let enqueueResult be EnqueueValueWithSize(this, chunk, chunkSize). + m_queue.enqueueValueAndGetSize(vm, globalObject, this, chunk); + RETURN_IF_EXCEPTION(scope, void()); + + // 7. If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[state]] is "writable", + if (!stream->isCloseQueuedOrInFlight() && stream->state() == JSWritableStream::State::Writable) { + // Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(this). + bool backpressure = getDesiredSize() <= 0; + + // Perform ! WritableStreamUpdateBackpressure(stream, backpressure). + stream->updateBackpressure(vm, globalObject, backpressure); + } + + // 8. Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(this). + if (shouldCallWrite()) { + m_writing = true; + m_inFlightWriteRequest = true; + MarkedArgumentBuffer args; + args.append(chunk); + JSObject* writeAlgorithm = m_writeAlgorithm.get(); + auto callData = JSC::getCallData(writeAlgorithm); + JSC::profiledCall(globalObject, JSC::ProfilingReason::API, writeAlgorithm, callData, jsUndefined(), args); + if (UNLIKELY(scope.exception())) { + m_writing = false; + m_inFlightWriteRequest = false; + return; + } + } +} + +bool JSWritableStreamDefaultController::shouldCallWrite() const +{ + if (!m_started) + return false; + + if (m_writing) + return false; + + if (m_inFlightWriteRequest) + return false; + + if (!stream() || stream()->state() != JSWritableStream::State::Writable) + return false; + + return true; +} + +template +void JSWritableStreamDefaultController::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSWritableStreamDefaultController* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + visitor.append(thisObject->m_stream); + visitor.append(thisObject->m_abortAlgorithm); + visitor.append(thisObject->m_closeAlgorithm); + visitor.append(thisObject->m_writeAlgorithm); + thisObject->m_abortController.visit(visitor); + + thisObject->m_queue.visit(thisObject, visitor); +} + +DEFINE_VISIT_CHILDREN(JSWritableStreamDefaultController); + +const JSC::ClassInfo JSWritableStreamDefaultController::s_info = { + "WritableStreamDefaultController"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultController) +}; + +JSValue JSWritableStreamDefaultController::close(JSGlobalObject* globalObject) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Let stream be this.[[stream]]. + JSWritableStream* stream = this->stream(); + + // 2. Assert: stream is not undefined. + ASSERT(stream); + + // 3. Let state be stream.[[state]]. + auto state = stream->state(); + + // 4. Assert: state is "writable". + ASSERT(state == JSWritableStream::State::Writable); + + // 5. Let closeRequest be stream.[[closeRequest]]. + // 6. Assert: closeRequest is not undefined. + // TODO: do we need to check this? + + JSObject* closeFunction = m_closeAlgorithm.get(); + + // 7. Perform ! WritableStreamDefaultControllerClearAlgorithms(this). + m_writeAlgorithm.clear(); + m_closeAlgorithm.clear(); + m_abortAlgorithm.clear(); + m_queue.clearAlgorithms(); + + // 8. Let sinkClosePromise be the result of performing this.[[closeAlgorithm]]. + JSValue sinkClosePromise; + if (m_closeAlgorithm) { + if (closeFunction) { + MarkedArgumentBuffer args; + ASSERT(!args.hasOverflowed()); + sinkClosePromise = JSC::profiledCall(globalObject, JSC::ProfilingReason::Microtask, closeFunction, JSC::getCallData(closeFunction), jsUndefined(), args); + RETURN_IF_EXCEPTION(scope, {}); + } else { + sinkClosePromise = jsUndefined(); + } + } else { + sinkClosePromise = jsUndefined(); + } + + // 9. Upon fulfillment of sinkClosePromise: + // a. Perform ! WritableStreamFinishInFlightClose(stream). + // 10. Upon rejection of sinkClosePromise with reason r: + // a. Perform ! WritableStreamFinishInFlightCloseWithError(stream, r). + if (JSPromise* promise = jsDynamicCast(sinkClosePromise)) { + Bun::then(globalObject, promise, jsWritableStreamDefaultControllerCloseFulfill, jsWritableStreamDefaultControllerCloseReject, stream); + } else { + // If not a promise, treat as fulfilled + stream->finishInFlightClose(); + } + + return jsUndefined(); +} + +void JSWritableStreamDefaultController::errorSteps() +{ + // Implementation of error steps for the controller + if (stream()) + stream()->error(globalObject(), jsUndefined()); +} + +JSValue JSWritableStreamDefaultController::performAbortAlgorithm(JSValue reason) +{ + if (!m_abortAlgorithm) + return jsUndefined(); + + MarkedArgumentBuffer args; + args.append(reason); + + auto callData = JSC::getCallData(m_abortAlgorithm.get()); + return call(globalObject(), m_abortAlgorithm.get(), callData, jsUndefined(), args); +} +} diff --git a/src/bun.js/bindings/BunWritableStreamDefaultController.h b/src/bun.js/bindings/BunWritableStreamDefaultController.h new file mode 100644 index 00000000000000..2f408680409375 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultController.h @@ -0,0 +1,115 @@ +#pragma once + +#include "root.h" + +#include +#include +#include +#include "BunStreamQueue.h" + +namespace WebCore { +class JSAbortController; +class JSAbortSignal; +class AbortSignal; +} + +namespace Bun { + +class JSWritableStream; + +class JSWritableStreamDefaultController final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static constexpr bool needsDestruction = false; + + static JSWritableStreamDefaultController* create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::Structure* structure, + JSWritableStream* stream, + double highWaterMark, + JSC::JSObject* abortAlgorithm, + JSC::JSObject* closeAlgorithm, + JSC::JSObject* writeAlgorithm, + JSC::JSObject* sizeAlgorithm); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if (mode == JSC::SubspaceAccess::Concurrently) { + return nullptr; + } + + return subspaceForImpl(vm); + } + + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + 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()); + } + + // JavaScript-facing methods + JSC::JSValue error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason); + JSC::JSValue error(JSC::JSGlobalObject* globalObject, JSC::JSValue reason) { return error(this->vm(), globalObject, reason); } + + JSC::JSValue close(JSC::JSGlobalObject* globalObject); + void write(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue chunk); + void write(JSC::JSGlobalObject* globalObject, JSC::JSValue chunk) { this->write(this->vm(), globalObject, chunk); } + + // C++-facing methods + bool shouldCallWrite() const; + double getDesiredSize() const { return m_queue.desiredSize(); } + bool started() const { return m_started; } + void errorSteps(); + JSC::JSValue performAbortAlgorithm(JSC::JSValue reason); + + // For garbage collection + DECLARE_VISIT_CHILDREN; + + Ref abortSignal() const; + WebCore::AbortSignal& signal() const; + + JSWritableStream* stream() const; + JSC::JSObject* abortAlgorithm() const { return m_abortAlgorithm.get(); } + JSC::JSObject* closeAlgorithm() const { return m_closeAlgorithm.get(); } + JSC::JSObject* writeAlgorithm() const { return m_writeAlgorithm.get(); } + + void setStream(JSC::VM& vm, JSWritableStream* stream); + void setAbortAlgorithm(JSC::VM& vm, JSC::JSObject* abortAlgorithm); + void setCloseAlgorithm(JSC::VM& vm, JSC::JSObject* closeAlgorithm); + void setWriteAlgorithm(JSC::VM& vm, JSC::JSObject* writeAlgorithm); + + void resetQueue(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* owner) { m_queue.resetQueue(vm, globalObject, owner); } + Bun::StreamQueue& queue() { return m_queue; } + const Bun::StreamQueue& queue() const { return m_queue; } + +private: + JSWritableStreamDefaultController(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&); + + // Internal slots per spec + JSC::WriteBarrier m_stream; + Bun::StreamQueue m_queue; + + // Functions for us to call. + JSC::WriteBarrier m_abortAlgorithm; + JSC::WriteBarrier m_closeAlgorithm; + JSC::WriteBarrier m_writeAlgorithm; + + bool m_started { false }; + bool m_writing { false }; + bool m_inFlightWriteRequest { false }; + bool m_closeRequested { false }; + JSC::LazyProperty m_abortController; +}; + +} diff --git a/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.cpp b/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.cpp new file mode 100644 index 00000000000000..799d24f0ec6779 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.cpp @@ -0,0 +1,52 @@ +#include "root.h" + +#include "JavaScriptCore/InternalFunction.h" +#include "ZigGlobalObject.h" +#include "BunWritableStreamDefaultControllerConstructor.h" +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStreamDefaultControllerPrototype.h" +#include +#include + +namespace Bun { + +JSWritableStreamDefaultControllerConstructor* JSWritableStreamDefaultControllerConstructor::create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSWritableStreamDefaultControllerPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSWritableStreamDefaultControllerConstructor* constructor = new ( + NotNull, JSC::allocateCell(vm)) + JSWritableStreamDefaultControllerConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +void JSWritableStreamDefaultControllerConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStreamDefaultControllerPrototype* prototype) +{ + Base::finishCreation(vm, 1, "WritableStreamDefaultController"_s, JSC::InternalFunction::PropertyAdditionMode::WithStructureTransition); + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); +} + +JSC_DEFINE_HOST_FUNCTION(constructJSWritableStreamDefaultController, (JSGlobalObject * globalObject, CallFrame*)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultController constructor cannot be called directly"_s); +} + +JSC_DEFINE_HOST_FUNCTION(callJSWritableStreamDefaultController, (JSGlobalObject * globalObject, CallFrame*)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultController constructor cannot be called as a function"_s); +} + +const JSC::ClassInfo JSWritableStreamDefaultControllerConstructor::s_info = { + "WritableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultControllerConstructor) +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.h b/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.h new file mode 100644 index 00000000000000..5bce66ead4caf6 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultControllerConstructor.h @@ -0,0 +1,50 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +using namespace JSC; + +class JSWritableStreamDefaultControllerPrototype; + +JSC_DECLARE_HOST_FUNCTION(callJSWritableStreamDefaultController); +JSC_DECLARE_HOST_FUNCTION(constructJSWritableStreamDefaultController); + +class JSWritableStreamDefaultControllerConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr bool needsDestruction = false; + + static JSWritableStreamDefaultControllerConstructor* create( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSWritableStreamDefaultControllerPrototype* prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return &vm.internalFunctionSpace(); + } + + 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()); + } + +private: + JSWritableStreamDefaultControllerConstructor(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, callJSWritableStreamDefaultController, constructJSWritableStreamDefaultController) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSWritableStreamDefaultControllerPrototype*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.cpp b/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.cpp new file mode 100644 index 00000000000000..8853c4301c2a5e --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.cpp @@ -0,0 +1,101 @@ +#include "root.h" + +#include +#include +#include +#include "JSAbortController.h" + +#include "BunWritableStreamDefaultControllerPrototype.h" +#include "BunWritableStreamDefaultController.h" +#include "JSAbortSignal.h" +#include "IDLTypes.h" +#include "DOMJITIDLType.h" +#include "JSDOMBinding.h" +#include "BunStreamInlines.h" +#include "ZigGlobalObject.h" +#include "BunWritableStream.h" +#include "AbortSignal.h" +namespace Bun { + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultControllerErrorFunction, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultController* controller = jsDynamicCast(callFrame->thisValue()); + if (UNLIKELY(!controller)) { + scope.throwException(globalObject, createTypeError(globalObject, "WritableStreamDefaultController.prototype.error called on non-WritableStreamDefaultController"_s)); + return {}; + } + + return JSValue::encode(controller->error(globalObject, callFrame->argument(0))); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultControllerGetSignal, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* thisObject = jsDynamicCast(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + scope.throwException(lexicalGlobalObject, createTypeError(lexicalGlobalObject, "WritableStreamDefaultController.prototype.signal called on non-WritableStreamDefaultController"_s)); + return {}; + } + + auto* globalObject = defaultGlobalObject(lexicalGlobalObject); + + auto& abortSignal = thisObject->signal(); + + return JSValue::encode(WebCore::toJS(lexicalGlobalObject, globalObject, abortSignal)); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultControllerGetDesiredSize, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* thisObject = jsDynamicCast(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + scope.throwException(lexicalGlobalObject, createTypeError(lexicalGlobalObject, "WritableStreamDefaultController.prototype.desiredSize called on non-WritableStreamDefaultController"_s)); + return {}; + } + + switch (thisObject->stream()->state()) { + case JSWritableStream::State::Errored: + return JSValue::encode(jsNull()); + case JSWritableStream::State::Closed: + return JSValue::encode(jsNumber(0)); + default: + return JSValue::encode(jsNumber(thisObject->getDesiredSize())); + } +} + +static const HashTableValue JSWritableStreamDefaultControllerPrototypeTableValues[] = { + { "error"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultControllerErrorFunction, 1 } }, + { "signal"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultControllerGetSignal, 0 } }, + { "desiredSize"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultControllerGetDesiredSize, 0 } }, +}; + +JSWritableStreamDefaultControllerPrototype* JSWritableStreamDefaultControllerPrototype::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSWritableStreamDefaultControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultControllerPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +void JSWritableStreamDefaultControllerPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSWritableStreamDefaultController::info(), JSWritableStreamDefaultControllerPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +const JSC::ClassInfo JSWritableStreamDefaultControllerPrototype::s_info = { + "WritableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultControllerPrototype) +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.h b/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.h new file mode 100644 index 00000000000000..e8b967341b64d8 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultControllerPrototype.h @@ -0,0 +1,35 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +class JSWritableStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSWritableStreamDefaultControllerPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultControllerPrototype, Base); + 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: + JSWritableStreamDefaultControllerPrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp new file mode 100644 index 00000000000000..81fb9c655a5b20 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp @@ -0,0 +1,231 @@ + +#include "root.h" + +#include "JavaScriptCore/JSCJSValue.h" +#include +#include "BunWritableStreamDefaultWriter.h" +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStream.h" +#include "JSDOMWrapper.h" +#include "ErrorCode.h" +#include +#include "BunPromiseInlines.h" +#include +#include + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSWritableStreamDefaultWriter::s_info = { + "WritableStreamDefaultWriter"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultWriter) +}; + +JSWritableStreamDefaultWriter::JSWritableStreamDefaultWriter(VM& vm, Structure* structure, JSWritableStream* stream) + : Base(vm, structure) +{ +} + +JSC::GCClient::IsoSubspace* JSWritableStreamDefaultWriter::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForWritableStreamDefaultWriter.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStreamDefaultWriter = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForWritableStreamDefaultWriter.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStreamDefaultWriter = std::forward(space); }); +} + +JSC::Structure* JSWritableStreamDefaultWriter::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, globalObject, prototype, + JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +JSWritableStreamDefaultWriter* JSWritableStreamDefaultWriter::create(VM& vm, Structure* structure, JSWritableStream* stream) +{ + JSWritableStreamDefaultWriter* writer = new ( + NotNull, + allocateCell(vm)) JSWritableStreamDefaultWriter(vm, structure, stream); + + writer->finishCreation(vm); + return writer; +} + +static constexpr auto initPendingPromise = [](const JSC::LazyProperty::Initializer& init) { + auto* globalObject = init.owner->globalObject(); + init.set(JSPromise::create(init.vm, globalObject->promiseStructure())); +}; + +static constexpr auto initResolvedPromise + = [](const JSC::LazyProperty::Initializer& init) { + auto* globalObject = init.owner->globalObject(); + init.set(Bun::createFulfilledPromise(globalObject, jsUndefined())); + }; + +static constexpr auto initEmptyArray = [](const JSC::LazyProperty::Initializer& init) { + auto* globalObject = init.owner->globalObject(); + init.set(JSC::constructEmptyArray(globalObject, static_cast(nullptr), 0)); +}; + +void JSWritableStreamDefaultWriter::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + m_closedPromise.initLater(initPendingPromise); + m_readyPromise.initLater(initPendingPromise); + m_writeRequests.initLater(initEmptyArray); +} + +void JSWritableStreamDefaultWriter::error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason) +{ + if (auto* stream = this->stream()) { + stream->error(vm, globalObject, reason); + } +} + +void JSWritableStreamDefaultWriter::setReady(JSC::VM& vm, JSC::JSPromise* promise) +{ + m_readyPromise.set(vm, this, promise); +} + +void JSWritableStreamDefaultWriter::resetReadyPromise() +{ + if (m_readyPromise.isInitialized()) { + m_readyPromise.setMayBeNull(vm(), this, nullptr); + } + + m_readyPromise.initLater(initPendingPromise); +} + +void JSWritableStreamDefaultWriter::resolveReadyPromise() +{ + if (m_readyPromise.isInitialized()) { + m_readyPromise.get(this)->fulfillWithNonPromise(globalObject(), jsUndefined()); + } else { + m_readyPromise.initLater(initResolvedPromise); + } +} + +void JSWritableStreamDefaultWriter::resetClosedPromise() +{ + if (m_closedPromise.isInitialized()) { + m_closedPromise.setMayBeNull(vm(), this, nullptr); + } + + m_closedPromise.initLater(initPendingPromise); +} + +void JSWritableStreamDefaultWriter::setClosed(JSC::VM& vm, JSC::JSPromise* promise) +{ + m_closedPromise.set(vm, this, promise); +} + +template +void JSWritableStreamDefaultWriter::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + auto* writer = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(writer, info()); + + Base::visitChildren(writer, visitor); + visitor.append(writer->m_stream); + writer->m_closedPromise.visit(visitor); + writer->m_readyPromise.visit(visitor); + writer->m_writeRequests.visit(visitor); +} + +DEFINE_VISIT_CHILDREN(JSWritableStreamDefaultWriter); + +double JSWritableStreamDefaultWriter::desiredSize() +{ + auto* stream = this->stream(); + if (!stream) { + return 0; + } + auto* controller = stream->controller(); + if (!controller) { + return 0; + } + return controller->getDesiredSize(); +} + +// Non-JS Methods for C++ Use + +#define CHECK_STREAM() \ + if (!m_stream) { \ + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_STATE, "WritableStreamDefaultWriter has no associated stream"_s); \ + return; \ + } + +void JSWritableStreamDefaultWriter::write(JSGlobalObject* globalObject, JSValue chunk) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + CHECK_STREAM(); + + m_stream->controller()->write(globalObject, chunk); +} + +void JSWritableStreamDefaultWriter::rejectWriteRequests(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSValue error) +{ + // a. Let writeRequests be writer.[[writeRequests]]. + // b. Set writer.[[writeRequests]] to an empty List. + // c. For each writeRequest of writeRequests, + // 1. Reject writeRequest with stream.[[storedError]]. + if (m_writeRequests.isInitialized()) { + auto* writeRequests = m_writeRequests.get(this); + JSC::EnsureStillAliveScope ensureStillAlive(writeRequests); + m_writeRequests.setMayBeNull(vm, this, nullptr); + m_writeRequests.initLater(initEmptyArray); + + JSC::forEachInIterable(globalObject, writeRequests, [error](JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue writeRequest) { + jsCast(writeRequest)->reject(globalObject, error); + }); + } +} + +void JSWritableStreamDefaultWriter::close(JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + CHECK_STREAM(); + + m_stream->close(globalObject); +} + +void JSWritableStreamDefaultWriter::abort(JSGlobalObject* globalObject, JSValue reason) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + CHECK_STREAM(); + + m_stream->abort(globalObject, reason); +} + +void JSWritableStreamDefaultWriter::release() +{ + m_stream.clear(); + if (m_closedPromise.isInitialized()) + m_closedPromise.get(this)->rejectAsHandled(globalObject(), jsUndefined()); + if (m_readyPromise.isInitialized()) + m_readyPromise.get(this)->rejectAsHandled(globalObject(), jsUndefined()); +} + +void JSWritableStreamDefaultWriter::resolveClosedPromise(JSGlobalObject* globalObject, JSValue value) +{ + if (m_closedPromise.isInitialized()) + m_closedPromise.get(this)->resolve(globalObject, value); +} + +void JSWritableStreamDefaultWriter::rejectClosedPromise(JSGlobalObject* globalObject, JSValue error) +{ + if (m_closedPromise.isInitialized()) + m_closedPromise.get(this)->rejectAsHandled(globalObject, error); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriter.h b/src/bun.js/bindings/BunWritableStreamDefaultWriter.h new file mode 100644 index 00000000000000..94e02c10a5678b --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriter.h @@ -0,0 +1,68 @@ +#pragma once + +#include "root.h" + +#include +#include +#include +#include + +namespace Bun { + +class JSWritableStream; + +class JSWritableStreamDefaultWriter final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSWritableStreamDefaultWriter* create(JSC::VM&, JSC::Structure*, JSWritableStream*); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return subspaceForImpl(vm); + } + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype); + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + // JavaScript-visible properties + JSC::JSPromise* closed() { return m_closedPromise.get(this); } + JSC::JSPromise* ready() { return m_readyPromise.get(this); } + double desiredSize(); + + void resolveClosedPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value); + void rejectClosedPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue error); + void rejectWriteRequests(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason); + void setReady(JSC::VM& vm, JSC::JSPromise* promise); + void setClosed(JSC::VM& vm, JSC::JSPromise* promise); + void error(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue reason); + void error(JSC::JSGlobalObject* globalObject, JSC::JSValue reason) { this->error(this->vm(), globalObject, reason); } + + // Internal APIs for C++ use + JSWritableStream* stream() const { return m_stream.get(); } + void release(); // For releaseLock() + void write(JSC::JSGlobalObject*, JSC::JSValue chunk); + void abort(JSC::JSGlobalObject*, JSC::JSValue reason = JSC::jsUndefined()); + void close(JSC::JSGlobalObject*); + void resetReadyPromise(); + void resetClosedPromise(); + void resolveReadyPromise(); + +protected: + JSWritableStreamDefaultWriter(JSC::VM&, JSC::Structure*, JSWritableStream*); + void finishCreation(JSC::VM&); + +private: + mutable JSC::WriteBarrier m_stream; + JSC::LazyProperty m_closedPromise; + JSC::LazyProperty m_readyPromise; + JSC::LazyProperty m_writeRequests; +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp new file mode 100644 index 00000000000000..17cc5ab0fadd2d --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp @@ -0,0 +1,89 @@ +#include "BunWritableStreamDefaultWriterConstructor.h" +#include "BunWritableStreamDefaultWriterPrototype.h" +#include "BunWritableStreamDefaultWriter.h" +#include "BunWritableStream.h" +#include "JavaScriptCore/InternalFunction.h" +#include "ZigGlobalObject.h" +#include + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSWritableStreamDefaultWriterConstructor::s_info = { + "Function"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterConstructor) +}; + +JSWritableStreamDefaultWriterConstructor::JSWritableStreamDefaultWriterConstructor(VM& vm, Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +void JSWritableStreamDefaultWriterConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSWritableStreamDefaultWriterPrototype* prototype) +{ + Base::finishCreation(vm, 1, "WritableStreamDefaultWriter"_s, PropertyAdditionMode::WithStructureTransition); + putDirect(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + ASSERT(inherits(info())); +} + +JSWritableStreamDefaultWriterConstructor* JSWritableStreamDefaultWriterConstructor::create(VM& vm, JSGlobalObject* globalObject, JSWritableStreamDefaultWriterPrototype* prototype) +{ + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSWritableStreamDefaultWriterConstructor* constructor = new (NotNull, allocateCell(vm)) JSWritableStreamDefaultWriterConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +// This is called when constructing a new writer with new WritableStreamDefaultWriter(stream) +EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) +{ + VM& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!callFrame->argumentCount()) { + throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor requires a WritableStream argument"_s); + return encodedJSValue(); + } + + JSValue streamValue = callFrame->argument(0); + JSWritableStream* stream = jsDynamicCast(streamValue); + if (!stream) { + throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor argument must be a WritableStream"_s); + return encodedJSValue(); + } + + // Check if stream is locked + if (stream->isLocked()) { + throwTypeError(lexicalGlobalObject, scope, "Cannot construct a WritableStreamDefaultWriter for a locked WritableStream"_s); + return encodedJSValue(); + } + + auto* domGlobalObject = defaultGlobalObject(lexicalGlobalObject); + auto& streams = domGlobalObject->streams(); + Structure* structure = streams.structure(domGlobalObject); + JSValue newTarget = callFrame->newTarget(); + + if (UNLIKELY(streams.constructor(lexicalGlobalObject) != newTarget)) { + RETURN_IF_EXCEPTION(scope, {}); + structure = InternalFunction::createSubclassStructure( + lexicalGlobalObject, newTarget.getObject(), structure); + RETURN_IF_EXCEPTION(scope, {}); + } + + JSWritableStreamDefaultWriter* writer = JSWritableStreamDefaultWriter::create(vm, structure, stream); + return JSValue::encode(writer); +} + +// This handles direct calls to WritableStreamDefaultWriter as a function, which should throw an error +EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::call(JSGlobalObject* globalObject, CallFrame*) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultWriter constructor cannot be called as a function"_s); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h new file mode 100644 index 00000000000000..7a6f19d56c511c --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +class JSWritableStreamDefaultWriterPrototype; + +class JSWritableStreamDefaultWriterConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSWritableStreamDefaultWriterConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSWritableStreamDefaultWriterPrototype* prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + 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()); + } + +private: + JSWritableStreamDefaultWriterConstructor(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSWritableStreamDefaultWriterPrototype*); + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp new file mode 100644 index 00000000000000..d03e5596fad0ec --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp @@ -0,0 +1,176 @@ +#include "BunWritableStreamDefaultWriterPrototype.h" +#include "BunWritableStreamDefaultWriter.h" +#include "JSDOMWrapper.h" + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock); + +// Property attributes for standard WritableStreamDefaultWriter prototype properties +static const unsigned ProtoAccessorDontDelete = PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor; +static const unsigned ProtoFunctionDontEnum = PropertyAttribute::DontEnum | PropertyAttribute::Function; + +// Table of prototype properties and methods +static const HashTableValue JSWritableStreamDefaultWriterPrototypeTableValues[] = { + { "closed"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterClosedGetter, nullptr } }, + { "ready"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterReadyGetter, nullptr } }, + { "desiredSize"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterDesiredSizeGetter, nullptr } }, + { "write"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterWrite, 1 } }, + { "abort"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterAbort, 1 } }, + { "close"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterClose, 0 } }, + { "releaseLock"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterReleaseLock, 0 } }, +}; + +const ClassInfo JSWritableStreamDefaultWriterPrototype::s_info = { + "WritableStreamDefaultWriter"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterPrototype) +}; + +JSWritableStreamDefaultWriterPrototype* JSWritableStreamDefaultWriterPrototype::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSWritableStreamDefaultWriterPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultWriterPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +void JSWritableStreamDefaultWriterPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, info(), JSWritableStreamDefaultWriterPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +// Getter implementations +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(writer->closed()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(writer->ready()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(jsNumber(writer->desiredSize())); +} + +// Method implementations +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + JSValue chunk = callFrame->argument(0); + + writer->write(globalObject, chunk); + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + writer->close(globalObject); + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + JSValue reason = callFrame->argument(0); + + writer->abort(globalObject, reason); + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + writer->release(); + return JSValue::encode(jsUndefined()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h new file mode 100644 index 00000000000000..2e6c074b0c5edd --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h @@ -0,0 +1,37 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +class JSWritableStreamDefaultWriterPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSWritableStreamDefaultWriterPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriterPrototype, Base); + 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: + JSWritableStreamDefaultWriterPrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamPrototype.cpp b/src/bun.js/bindings/BunWritableStreamPrototype.cpp new file mode 100644 index 00000000000000..3f4a62349a44c8 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamPrototype.cpp @@ -0,0 +1,119 @@ +#include "BunWritableStreamPrototype.h" +#include "BunWritableStream.h" +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStreamDefaultWriter.h" +#include "ZigGlobalObject.h" + +namespace Bun { + +using namespace JSC; + +// JSWritableStreamPrototype bindings +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_abort, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "WritableStream.prototype.abort called on non-WritableStream object"_s); + + JSValue reason = callFrame->argument(0); + return JSValue::encode(stream->abort(globalObject, reason)); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_close, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "WritableStream.prototype.close called on non-WritableStream object"_s); + + return JSValue::encode(stream->close(globalObject)); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_getWriter, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(callFrame->thisValue()); + if (!stream) + return throwVMTypeError(globalObject, scope, "WritableStream.prototype.getWriter called on non-WritableStream object"_s); + + if (stream->isLocked()) + return throwVMTypeError(globalObject, scope, "Cannot get writer for locked WritableStream"_s); + + auto* domGlobalObject = defaultGlobalObject(globalObject); + auto& streams = domGlobalObject->streams(); + + Structure* writerStructure = streams.structure(domGlobalObject); + auto* writer = JSWritableStreamDefaultWriter::create(vm, writerStructure, stream); + RETURN_IF_EXCEPTION(scope, {}); + + stream->setWriter(vm, writer); + return JSValue::encode(writer); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamPrototypeLockedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStream* stream = jsDynamicCast(JSValue::decode(thisValue)); + if (!stream) + return throwVMTypeError(globalObject, scope, "WritableStream.prototype.locked called on non-WritableStream object"_s); + + return JSValue::encode(jsBoolean(stream->isLocked())); +} + +// Static hash table of properties +static const HashTableValue JSWritableStreamPrototypeTableValues[] = { + { "abort"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_abort, 1 } }, + { "close"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_close, 0 } }, + { "getWriter"_s, + static_cast(PropertyAttribute::Function), + NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_getWriter, 0 } }, + { "locked"_s, + static_cast(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), + NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamPrototypeLockedGetter, nullptr } } +}; + +// Prototype Implementation +const ClassInfo JSWritableStreamPrototype::s_info = { "WritableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamPrototype) }; + +JSWritableStreamPrototype* JSWritableStreamPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + auto* prototype = new (NotNull, allocateCell(vm)) JSWritableStreamPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; +} + +JSWritableStreamPrototype::JSWritableStreamPrototype(VM& vm, Structure* structure) + : Base(vm, structure) +{ +} + +void JSWritableStreamPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, JSWritableStream::info(), JSWritableStreamPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +Structure* JSWritableStreamPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamPrototype.h b/src/bun.js/bindings/BunWritableStreamPrototype.h new file mode 100644 index 00000000000000..8ef53cdf8f6a6d --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamPrototype.h @@ -0,0 +1,30 @@ +#pragma once + +#include "root.h" +#include "BunStreamStructures.h" + +namespace Bun { + +using namespace JSC; + +class JSWritableStreamPrototype final : public JSNonFinalObject { +public: + using Base = JSNonFinalObject; + + static JSWritableStreamPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure); + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype); + + DECLARE_INFO; + template + static GCClient::IsoSubspace* subspaceFor(VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamPrototype, Base); + return &vm.plainObjectSpace(); + } + +private: + JSWritableStreamPrototype(VM& vm, Structure* structure); + void finishCreation(VM& vm, JSGlobalObject* globalObject); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/JSMockFunction.cpp b/src/bun.js/bindings/JSMockFunction.cpp index 5140505d04c9fd..e5362667c22150 100644 --- a/src/bun.js/bindings/JSMockFunction.cpp +++ b/src/bun.js/bindings/JSMockFunction.cpp @@ -27,6 +27,7 @@ #include "BunPlugin.h" #include "AsyncContextFrame.h" #include "ErrorCode.h" +#include "BunPromiseInlines.h" BUN_DECLARE_HOST_FUNCTION(JSMock__jsUseFakeTimers); BUN_DECLARE_HOST_FUNCTION(JSMock__jsUseRealTimers); @@ -1180,7 +1181,7 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockResolvedValue, (JSC::JSGlobalObject * auto scope = DECLARE_THROW_SCOPE(vm); CHECK_IS_MOCK_FUNCTION(thisValue); - pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0))); + pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, Bun::createFulfilledPromise(globalObject, callframe->argument(0))); RELEASE_AND_RETURN(scope, JSValue::encode(thisObject)); } @@ -1193,7 +1194,7 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockResolvedValueOnce, (JSC::JSGlobalObje auto scope = DECLARE_THROW_SCOPE(vm); CHECK_IS_MOCK_FUNCTION(thisValue); - pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0))); + pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, Bun::createFulfilledPromise(globalObject, callframe->argument(0))); RELEASE_AND_RETURN(scope, JSValue::encode(thisObject)); } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index a8a8ea91cebb12..fb9b4982a55a77 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1,7 +1,9 @@ #include "root.h" + #include "ZigGlobalObject.h" #include "helpers.h" #include "JavaScriptCore/ArgList.h" +#include "JSDOMGuardedObject.h" #include "JavaScriptCore/JSImmutableButterfly.h" #include "wtf/text/Base64.h" #include "JavaScriptCore/BuiltinNames.h" @@ -14,6 +16,7 @@ #include "JavaScriptCore/Error.h" #include "JavaScriptCore/ErrorInstance.h" #include "JavaScriptCore/Exception.h" +#include "JSDOMConvert.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/FunctionConstructor.h" #include "JavaScriptCore/FunctionPrototype.h" @@ -78,6 +81,7 @@ #include "JSByteLengthQueuingStrategy.h" #include "JSCloseEvent.h" #include "JSCountQueuingStrategy.h" + #include "JSCustomEvent.h" #include "JSDOMConvertBase.h" #include "JSDOMConvertUnion.h" @@ -103,12 +107,12 @@ #include "JSPerformanceMeasure.h" #include "JSPerformanceObserver.h" #include "JSPerformanceObserverEntryList.h" -#include "JSReadableByteStreamController.h" -#include "JSReadableStream.h" -#include "JSReadableStreamBYOBReader.h" -#include "JSReadableStreamBYOBRequest.h" -#include "JSReadableStreamDefaultController.h" -#include "JSReadableStreamDefaultReader.h" +// #include "JSReadableByteStreamController.h" +#include "BunReadableStream.h" +#include "BunReadableStreamBYOBReader.h" +// #include "BunReadableStreamBYOBRequest.h" +#include "BunReadableStreamDefaultController.h" +#include "BunReadableStreamDefaultReader.h" #include "JSSink.h" #include "JSSocketAddress.h" #include "JSSQLStatement.h" @@ -116,14 +120,14 @@ #include "JSTextEncoder.h" #include "JSTextEncoderStream.h" #include "JSTextDecoderStream.h" -#include "JSTransformStream.h" -#include "JSTransformStreamDefaultController.h" +#include "BunTransformStream.h" +#include "BunTransformStreamDefaultController.h" #include "JSURLSearchParams.h" #include "JSWebSocket.h" #include "JSWorker.h" -#include "JSWritableStream.h" -#include "JSWritableStreamDefaultController.h" -#include "JSWritableStreamDefaultWriter.h" +#include "BunWritableStream.h" +#include "BunWritableStreamDefaultController.h" +#include "BunWritableStreamDefaultWriter.h" #include "libusockets.h" #include "ModuleLoader.h" #include "napi_external.h" @@ -136,7 +140,6 @@ #include "ProcessBindingConstants.h" #include "ProcessBindingTTYWrap.h" #include "ProcessIdentifier.h" -#include "ReadableStream.h" #include "SerializedScriptValue.h" #include "StructuredClone.h" #include "WebCoreJSBuiltins.h" @@ -155,6 +158,7 @@ #include "JSPerformanceServerTiming.h" #include "JSPerformanceResourceTiming.h" #include "JSPerformanceTiming.h" +#include "IDLTypes.h" #if ENABLE(REMOTE_INSPECTOR) #include "JavaScriptCore/RemoteInspectorServer.h" @@ -1385,24 +1389,30 @@ WEBCORE_GENERATED_CONSTRUCTOR_GETTER(PerformanceObserverEntryList) WEBCORE_GENERATED_CONSTRUCTOR_GETTER(PerformanceResourceTiming) WEBCORE_GENERATED_CONSTRUCTOR_GETTER(PerformanceServerTiming) WEBCORE_GENERATED_CONSTRUCTOR_GETTER(PerformanceTiming) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableByteStreamController) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStream) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamBYOBReader) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamBYOBRequest) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamDefaultController) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamDefaultReader) +// WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableByteStreamController) + WEBCORE_GENERATED_CONSTRUCTOR_GETTER(SubtleCrypto); WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextEncoder); WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextEncoderStream); WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextDecoderStream); -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStream) -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStreamDefaultController) WEBCORE_GENERATED_CONSTRUCTOR_GETTER(URLSearchParams); WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WebSocket); WEBCORE_GENERATED_CONSTRUCTOR_GETTER(Worker); -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStream); -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStreamDefaultController); -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStreamDefaultWriter); + +#define WHATWG_STREAM_CONSTRUCTOR_GETTER(ConstructorName) \ + JSValue ConstructorName##ConstructorCallback(VM& vm, JSObject* lexicalGlobalObject) \ + { \ + auto* thisObject = jsCast(lexicalGlobalObject); \ + return thisObject->streams().constructor(jsCast(lexicalGlobalObject)); \ + } \ + JSC_DEFINE_CUSTOM_GETTER(ConstructorName##_getter, \ + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ + JSC::PropertyName)) \ + { \ + return JSC::JSValue::encode(jsCast(lexicalGlobalObject)->streams().constructor(lexicalGlobalObject)); \ + } +FOR_EACH_WHATWG_STREAM_CLASS_TYPE(WHATWG_STREAM_CONSTRUCTOR_GETTER) +#undef WHATWG_STREAM_CONSTRUCTOR_GETTER JSC_DEFINE_HOST_FUNCTION(functionGetSelf, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) @@ -2065,10 +2075,10 @@ JSC_DEFINE_HOST_FUNCTION(getInternalWritableStream, (JSGlobalObject*, CallFrame* ASSERT(callFrame); ASSERT(callFrame->argumentCount() == 1); - auto* writableStream = jsDynamicCast(callFrame->uncheckedArgument(0)); - if (UNLIKELY(!writableStream)) - return JSValue::encode(jsUndefined()); - return JSValue::encode(writableStream->wrapped().internalWritableStream()); + // auto* writableStream = jsDynamicCast(callFrame->uncheckedArgument(0)); + // if (UNLIKELY(!writableStream)) + return JSValue::encode(jsUndefined()); + // return JSValue::encode(writableStream->wrapped().internalWritableStream()); } JSC_DEFINE_HOST_FUNCTION(createWritableStreamFromInternal, (JSGlobalObject * globalObject, CallFrame* callFrame)) @@ -2077,9 +2087,10 @@ JSC_DEFINE_HOST_FUNCTION(createWritableStreamFromInternal, (JSGlobalObject * glo ASSERT(callFrame->argumentCount() == 1); ASSERT(callFrame->uncheckedArgument(0).isObject()); - auto* jsDOMGlobalObject = JSC::jsCast(globalObject); - auto internalWritableStream = InternalWritableStream::fromObject(*jsDOMGlobalObject, *callFrame->uncheckedArgument(0).toObject(globalObject)); - return JSValue::encode(toJSNewlyCreated(globalObject, jsDOMGlobalObject, WritableStream::create(WTFMove(internalWritableStream)))); + return JSValue::encode(jsUndefined()); + // auto* jsDOMGlobalObject = JSC::jsCast(globalObject); + // auto internalWritableStream = InternalWritableStream::fromObject(*jsDOMGlobalObject, *callFrame->uncheckedArgument(0).toObject(globalObject)); + // return JSValue::encode(toJSNewlyCreated(globalObject, jsDOMGlobalObject, WritableStream::create(WTFMove(internalWritableStream)))); } JSC_DEFINE_HOST_FUNCTION(addAbortAlgorithmToSignal, (JSGlobalObject * globalObject, CallFrame* callFrame)) @@ -2139,174 +2150,177 @@ static inline std::optional invokeReadableStreamFunction(JSC::JSGl } extern "C" bool ReadableStream__tee(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject, JSC__JSValue* possibleReadableStream1, JSC__JSValue* possibleReadableStream2) { - auto* readableStream = jsDynamicCast(JSC::JSValue::decode(possibleReadableStream)); - if (UNLIKELY(!readableStream)) - return false; + // auto* readableStream = jsDynamicCast(JSC::JSValue::decode(possibleReadableStream)); + // if (UNLIKELY(!readableStream)) + // return false; - auto& lexicalGlobalObject = *globalObject; - auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamTeePrivateName(); + // auto& lexicalGlobalObject = *globalObject; + // auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); + // auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamTeePrivateName(); - MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(JSC::jsBoolean(true)); - ASSERT(!arguments.hasOverflowed()); - auto returnedValue = invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments); - if (!returnedValue) - return false; + // MarkedArgumentBuffer arguments; + // arguments.append(readableStream); + // arguments.append(JSC::jsBoolean(true)); + // ASSERT(!arguments.hasOverflowed()); + // auto returnedValue = invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments); + // if (!returnedValue) + return false; - auto results = Detail::SequenceConverter::convert(lexicalGlobalObject, *returnedValue); + // auto results = Detail::SequenceConverter::convert(lexicalGlobalObject, *returnedValue); - ASSERT(results.size() == 2); - *possibleReadableStream1 = JSValue::encode(results[0]); - *possibleReadableStream2 = JSValue::encode(results[1]); - return true; + // ASSERT(results.size() == 2); + // *possibleReadableStream1 = JSValue::encode(results[0]); + // *possibleReadableStream2 = JSValue::encode(results[1]); + // return true; } extern "C" void ReadableStream__cancel(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject) { - auto* readableStream = jsDynamicCast(JSC::JSValue::decode(possibleReadableStream)); - if (UNLIKELY(!readableStream)) - return; + // auto* readableStream = jsDynamicCast(JSC::JSValue::decode(possibleReadableStream)); + // if (UNLIKELY(!readableStream)) + // return; - if (!ReadableStream::isLocked(globalObject, readableStream)) { - return; - } + // if (!ReadableStream::isLocked(globalObject, readableStream)) { + // return; + // } - WebCore::Exception exception { AbortError }; - ReadableStream::cancel(*globalObject, readableStream, exception); + // WebCore::Exception exception { AbortError }; + // ReadableStream::cancel(*globalObject, readableStream, exception); } extern "C" void ReadableStream__detach(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject) { - auto value = JSC::JSValue::decode(possibleReadableStream); - if (value.isEmpty() || !value.isCell()) - return; + // auto value = JSC::JSValue::decode(possibleReadableStream); + // if (value.isEmpty() || !value.isCell()) + // return; - auto* readableStream = static_cast(value.asCell()); - if (UNLIKELY(!readableStream)) - return; - readableStream->setNativePtr(globalObject->vm(), jsNumber(-1)); - readableStream->setNativeType(0); - readableStream->setDisturbed(true); + // auto* readableStream = static_cast(value.asCell()); + // if (UNLIKELY(!readableStream)) + // return; + // readableStream->setNativePtr(globalObject->vm(), jsNumber(-1)); + // readableStream->setNativeType(0); + // readableStream->setDisturbed(true); } extern "C" bool ReadableStream__isDisturbed(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject); extern "C" bool ReadableStream__isDisturbed(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject) { ASSERT(globalObject); - return ReadableStream::isDisturbed(globalObject, jsDynamicCast(JSC::JSValue::decode(possibleReadableStream))); + // return ReadableStream::isDisturbed(globalObject, jsDynamicCast(JSC::JSValue::decode(possibleReadableStream))); + return false; } extern "C" bool ReadableStream__isLocked(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject); extern "C" bool ReadableStream__isLocked(JSC__JSValue possibleReadableStream, Zig::GlobalObject* globalObject) { ASSERT(globalObject); - WebCore::JSReadableStream* stream = jsDynamicCast(JSValue::decode(possibleReadableStream)); - return stream != nullptr && ReadableStream::isLocked(globalObject, stream); + // WebCore::JSReadableStream* stream = jsDynamicCast(JSValue::decode(possibleReadableStream)); + // return stream != nullptr && ReadableStream::isLocked(globalObject, stream); + return false; } extern "C" int32_t ReadableStreamTag__tagged(Zig::GlobalObject* globalObject, JSC__JSValue* possibleReadableStream, void** ptr) { ASSERT(globalObject); - JSC::JSObject* object = JSValue::decode(*possibleReadableStream).getObject(); - if (!object) { - *ptr = nullptr; - return -1; - } - - auto& vm = globalObject->vm(); - - if (!object->inherits()) { - auto throwScope = DECLARE_THROW_SCOPE(vm); - JSValue target = object; - JSValue fn = JSValue(); - auto* function = jsDynamicCast(object); - if (function && function->jsExecutable() && function->jsExecutable()->isAsyncGenerator()) { - fn = object; - target = jsUndefined(); - } else if (auto iterable = object->getIfPropertyExists(globalObject, vm.propertyNames->asyncIteratorSymbol)) { - if (iterable.isCallable()) { - fn = iterable; - } - } - - if (UNLIKELY(throwScope.exception())) { - *ptr = nullptr; - return -1; - } - - if (fn.isEmpty()) { - *ptr = nullptr; - return -1; - } - - auto* createIterator = globalObject->builtinInternalFunctions().readableStreamInternals().m_readableStreamFromAsyncIteratorFunction.get(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(target); - arguments.append(fn); - - JSC::JSValue result = profiledCall(globalObject, JSC::ProfilingReason::API, createIterator, JSC::getCallData(createIterator), JSC::jsUndefined(), arguments); - - if (UNLIKELY(throwScope.exception())) { - return -1; - } - - if (!result.isObject()) { - *ptr = nullptr; - return -1; - } - - object = result.getObject(); + // JSC::JSObject* object = JSValue::decode(*possibleReadableStream).getObject(); + // if (!object) { + *ptr = nullptr; + return -1; + // } - ASSERT(object->inherits()); - *possibleReadableStream = JSValue::encode(object); - *ptr = nullptr; - ensureStillAliveHere(object); - return 0; - } + // auto& vm = globalObject->vm(); + + // if (!object->inherits()) { + // auto throwScope = DECLARE_THROW_SCOPE(vm); + // JSValue target = object; + // JSValue fn = JSValue(); + // auto* function = jsDynamicCast(object); + // if (function && function->jsExecutable() && function->jsExecutable()->isAsyncGenerator()) { + // fn = object; + // target = jsUndefined(); + // } else if (auto iterable = object->getIfPropertyExists(globalObject, vm.propertyNames->asyncIteratorSymbol)) { + // if (iterable.isCallable()) { + // fn = iterable; + // } + // } + + // if (UNLIKELY(throwScope.exception())) { + // *ptr = nullptr; + // return -1; + // } + + // if (fn.isEmpty()) { + // *ptr = nullptr; + // return -1; + // } + + // auto* createIterator = globalObject->builtinInternalFunctions().readableStreamInternals().m_readableStreamFromAsyncIteratorFunction.get(); + + // JSC::MarkedArgumentBuffer arguments; + // arguments.append(target); + // arguments.append(fn); + + // JSC::JSValue result = profiledCall(globalObject, JSC::ProfilingReason::API, createIterator, JSC::getCallData(createIterator), JSC::jsUndefined(), arguments); + + // if (UNLIKELY(throwScope.exception())) { + // return -1; + // } + + // if (!result.isObject()) { + // *ptr = nullptr; + // return -1; + // } + + // object = result.getObject(); + + // ASSERT(object->inherits()); + // *possibleReadableStream = JSValue::encode(object); + // *ptr = nullptr; + // ensureStillAliveHere(object); + // return 0; + // } - auto* readableStream = jsCast(object); + // auto* readableStream = jsCast(object); - JSValue nativePtrHandle = readableStream->nativePtr(); - if (nativePtrHandle.isEmpty() || !nativePtrHandle.isCell()) { - *ptr = nullptr; - return 0; - } + // JSValue nativePtrHandle = readableStream->nativePtr(); + // if (nativePtrHandle.isEmpty() || !nativePtrHandle.isCell()) { + // *ptr = nullptr; + // return 0; + // } - JSCell* cell = nativePtrHandle.asCell(); + // JSCell* cell = nativePtrHandle.asCell(); - if (auto* casted = jsDynamicCast(cell)) { - *ptr = casted->wrapped(); - return 1; - } + // if (auto* casted = jsDynamicCast(cell)) { + // *ptr = casted->wrapped(); + // return 1; + // } - if (auto* casted = jsDynamicCast(cell)) { - *ptr = casted->wrapped(); - return 2; - } + // if (auto* casted = jsDynamicCast(cell)) { + // *ptr = casted->wrapped(); + // return 2; + // } - if (auto* casted = jsDynamicCast(cell)) { - *ptr = casted->wrapped(); - return 4; - } + // if (auto* casted = jsDynamicCast(cell)) { + // *ptr = casted->wrapped(); + // return 4; + // } - return 0; + // return 0; } extern "C" JSC__JSValue ZigGlobalObject__createNativeReadableStream(Zig::GlobalObject* globalObject, JSC__JSValue nativePtr) { - auto& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); + // auto& vm = globalObject->vm(); + // auto scope = DECLARE_THROW_SCOPE(vm); - auto& builtinNames = WebCore::builtinNames(vm); + // auto& builtinNames = WebCore::builtinNames(vm); - auto function = globalObject->getDirect(vm, builtinNames.createNativeReadableStreamPrivateName()).getObject(); - JSC::MarkedArgumentBuffer arguments = JSC::MarkedArgumentBuffer(); - arguments.append(JSValue::decode(nativePtr)); + // auto function = globalObject->getDirect(vm, builtinNames.createNativeReadableStreamPrivateName()).getObject(); + // JSC::MarkedArgumentBuffer arguments = JSC::MarkedArgumentBuffer(); + // arguments.append(JSValue::decode(nativePtr)); - auto callData = JSC::getCallData(function); - return JSC::JSValue::encode(call(globalObject, function, callData, JSC::jsUndefined(), arguments)); + // auto callData = JSC::getCallData(function); + // return JSC::JSValue::encode(call(globalObject, function, callData, JSC::jsUndefined(), arguments)); + return JSValue::encode(jsUndefined()); } extern "C" JSC__JSValue Bun__Jest__createTestModuleObject(JSC::JSGlobalObject*); @@ -2819,6 +2833,7 @@ void GlobalObject::finishCreation(VM& vm) m_http2_commongStrings.initialize(); Bun::addNodeModuleConstructorProperties(vm, this); + m_streamStructures.initialize(vm, this); m_lazyStackCustomGetterSetter.initLater( [](const Initializer& init) { @@ -3523,26 +3538,26 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionToClass, (JSC::JSGlobalObject * globalObject, EncodedJSValue GlobalObject::assignToStream(JSValue stream, JSValue controller) { - JSC::VM& vm = this->vm(); - JSC::JSFunction* function = this->m_assignToStream.get(); - if (!function) { - function = JSFunction::create(vm, this, static_cast(readableStreamInternalsAssignToStreamCodeGenerator(vm)), this); - this->m_assignToStream.set(vm, this, function); - } + // JSC::VM& vm = this->vm(); + // JSC::JSFunction* function = this->m_assignToStream.get(); + // if (!function) { + // function = JSFunction::create(vm, this, static_cast(readableStreamInternalsAssignToStreamCodeGenerator(vm)), this); + // this->m_assignToStream.set(vm, this, function); + // } - auto callData = JSC::getCallData(function); - JSC::MarkedArgumentBuffer arguments; - arguments.append(stream); - arguments.append(controller); + // auto callData = JSC::getCallData(function); + // JSC::MarkedArgumentBuffer arguments; + // arguments.append(stream); + // arguments.append(controller); - WTF::NakedPtr returnedException = nullptr; + // WTF::NakedPtr returnedException = nullptr; - auto result = JSC::profiledCall(this, ProfilingReason::API, function, callData, JSC::jsUndefined(), arguments, returnedException); - if (auto* exception = returnedException.get()) { - return JSC::JSValue::encode(exception); - } + // auto result = JSC::profiledCall(this, ProfilingReason::API, function, callData, JSC::jsUndefined(), arguments, returnedException); + // if (auto* exception = returnedException.get()) { + // return JSC::JSValue::encode(exception); + // } - return JSC::JSValue::encode(result); + return JSC::JSValue::encode(jsUndefined()); } JSC::JSObject* GlobalObject::navigatorObject() @@ -3609,11 +3624,11 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) GlobalPropertyInfo(builtinNames.makeDOMExceptionPrivateName(), JSFunction::create(vm, this, 2, String(), makeDOMExceptionForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(builtinNames.addAbortAlgorithmToSignalPrivateName(), JSFunction::create(vm, this, 2, String(), addAbortAlgorithmToSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(builtinNames.removeAbortAlgorithmFromSignalPrivateName(), JSFunction::create(vm, this, 2, String(), removeAbortAlgorithmFromSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), - GlobalPropertyInfo(builtinNames.cloneArrayBufferPrivateName(), JSFunction::create(vm, this, 3, String(), cloneArrayBuffer, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), - GlobalPropertyInfo(builtinNames.structuredCloneForStreamPrivateName(), JSFunction::create(vm, this, 1, String(), structuredCloneForStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.cloneArrayBufferPrivateName(), JSFunction::create(vm, this, 3, String(), jsFunctionCloneArrayBuffer, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.structuredCloneForStreamPrivateName(), JSFunction::create(vm, this, 1, String(), jsFunctionStructuredCloneForStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(builtinNames.isAbortSignalPrivateName(), JSFunction::create(vm, this, 1, String(), isAbortSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), - GlobalPropertyInfo(builtinNames.getInternalWritableStreamPrivateName(), JSFunction::create(vm, this, 1, String(), getInternalWritableStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), - GlobalPropertyInfo(builtinNames.createWritableStreamFromInternalPrivateName(), JSFunction::create(vm, this, 1, String(), createWritableStreamFromInternal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + // GlobalPropertyInfo(builtinNames.getInternalWritableStreamPrivateName(), JSFunction::create(vm, this, 1, String(), getInternalWritableStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + // GlobalPropertyInfo(builtinNames.createWritableStreamFromInternalPrivateName(), JSFunction::create(vm, this, 1, String(), createWritableStreamFromInternal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(builtinNames.fulfillModuleSyncPrivateName(), JSFunction::create(vm, this, 1, String(), functionFulfillModuleSync, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(vm.propertyNames->builtinNames().ArrayBufferPrivateName(), arrayBufferConstructor(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), GlobalPropertyInfo(builtinNames.LoaderPrivateName(), this->moduleLoader(), PropertyAttribute::DontDelete | 0), @@ -3630,9 +3645,9 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) // i've noticed doing it as is will work somewhat but getDirect() wont be able to find them putDirectBuiltinFunction(vm, this, builtinNames.createFIFOPrivateName(), streamInternalsCreateFIFOCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirectBuiltinFunction(vm, this, builtinNames.createEmptyReadableStreamPrivateName(), readableStreamCreateEmptyReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirectBuiltinFunction(vm, this, builtinNames.createUsedReadableStreamPrivateName(), readableStreamCreateUsedReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + // putDirectBuiltinFunction(vm, this, builtinNames.createEmptyReadableStreamPrivateName(), readableStreamCreateEmptyReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + // putDirectBuiltinFunction(vm, this, builtinNames.createUsedReadableStreamPrivateName(), readableStreamCreateUsedReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + // putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.requireESMPrivateName(), importMetaObjectRequireESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.loadCJS2ESMPrivateName(), importMetaObjectLoadCJS2ESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.internalRequirePrivateName(), importMetaObjectInternalRequireCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); @@ -3660,18 +3675,18 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0); putDirectCustomAccessor(vm, static_cast(vm.clientData)->builtinNames().BufferPrivateName(), JSC::CustomGetterSetter::create(vm, JSBuffer_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.lazyStreamPrototypeMapPrivateName(), JSC::CustomGetterSetter::create(vm, functionLazyLoadStreamPrototypeMap_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.TransformStreamPrivateName(), CustomGetterSetter::create(vm, TransformStream_getter, nullptr), attributesForStructure(static_cast(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.TransformStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, TransformStreamDefaultController_getter, nullptr), attributesForStructure(static_cast(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableByteStreamControllerPrivateName(), CustomGetterSetter::create(vm, ReadableByteStreamController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamPrivateName(), CustomGetterSetter::create(vm, ReadableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBRequestPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBRequest_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.WritableStreamPrivateName(), CustomGetterSetter::create(vm, WritableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultWriterPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultWriter_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.lazyStreamPrototypeMapPrivateName(), JSC::CustomGetterSetter::create(vm, functionLazyLoadStreamPrototypeMap_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.TransformStreamPrivateName(), CustomGetterSetter::create(vm, TransformStream_getter, nullptr), attributesForStructure(static_cast(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.TransformStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, TransformStreamDefaultController_getter, nullptr), attributesForStructure(static_cast(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableByteStreamControllerPrivateName(), CustomGetterSetter::create(vm, ReadableByteStreamController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableStreamPrivateName(), CustomGetterSetter::create(vm, ReadableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBRequestPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBRequest_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.WritableStreamPrivateName(), CustomGetterSetter::create(vm, WritableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); + // putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultWriterPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultWriter_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomValue); putDirectCustomAccessor(vm, builtinNames.AbortSignalPrivateName(), CustomGetterSetter::create(vm, AbortSignal_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomValue); // ----- Public Properties ----- @@ -3866,6 +3881,11 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->visitGeneratedLazyClasses(thisObject, visitor); thisObject->visitAdditionalChildren(visitor); + +#define VISIT_STREAM_CLASS(ClassName) \ + thisObject->streams().m_##ClassName.visit(visitor); + FOR_EACH_WHATWG_STREAM_CLASS_TYPE(VISIT_STREAM_CLASS) +#undef VISIT_STREAM_CLASS } extern "C" bool JSGlobalObject__setTimeZone(JSC::JSGlobalObject* globalObject, const ZigString* timeZone) diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index c2dca678fc2b42..a13b5f08dfc045 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -53,6 +53,7 @@ class GlobalInternals; #include "BunCommonStrings.h" #include "BunHttp2CommonStrings.h" #include "BunGlobalScope.h" +#include "BunStreamStructures.h" namespace WebCore { class WorkerGlobalScope; @@ -227,6 +228,8 @@ class GlobalObject : public Bun::GlobalScope { JSC::JSObject* NodeVMScript() const { return m_NodeVMScriptClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue NodeVMScriptPrototype() const { return m_NodeVMScriptClassStructure.prototypeInitializedOnMainThread(this); } + JSC::Structure* teeStateStructure() const { return m_teeStateStructure.getInitializedOnMainThread(this); } + JSC::JSMap* readableStreamNativeMap() const { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); } JSC::JSMap* requireMap() const { return m_requireMap.getInitializedOnMainThread(this); } JSC::JSMap* esmRegistryMap() const { return m_esmRegistryMap.getInitializedOnMainThread(this); } @@ -339,9 +342,10 @@ class GlobalObject : public Bun::GlobalScope { }; static constexpr size_t promiseFunctionsSize = 26; - static PromiseFunctions promiseHandlerID(SYSV_ABI EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1)); + using PromiseHandler = SYSV_ABI EncodedJSValue (*)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1); + static PromiseFunctions promiseHandlerID(PromiseHandler handler); - JSFunction* thenable(SYSV_ABI EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1)) + JSFunction* thenable(PromiseHandler handler) { auto& barrier = this->m_thenables[static_cast(GlobalObject::promiseHandlerID(handler))]; if (JSFunction* func = barrier.get()) { @@ -478,6 +482,9 @@ class GlobalObject : public Bun::GlobalScope { JSObject* JSDOMFileConstructor() const { return m_JSDOMFileConstructor.getInitializedOnMainThread(this); } Bun::CommonStrings& commonStrings() { return m_commonStrings; } Bun::Http2CommonStrings& http2CommonStrings() { return m_http2_commongStrings; } + + Bun::StreamStructures& streams() { return m_streamStructures; } + #include "ZigGeneratedClasses+lazyStructureHeader.h" void finishCreation(JSC::VM&); @@ -522,6 +529,7 @@ class GlobalObject : public Bun::GlobalScope { LazyClassStructure m_callSiteStructure; LazyClassStructure m_JSBufferClassStructure; LazyClassStructure m_NodeVMScriptClassStructure; + LazyClassStructure m_teeStateStructure; /** * WARNING: You must update visitChildrenImpl() if you add a new field. @@ -593,6 +601,8 @@ class GlobalObject : public Bun::GlobalScope { WTF::Vector> m_aboutToBeNotifiedRejectedPromises; WTF::Vector> m_ffiFunctions; + + Bun::StreamStructures m_streamStructures; }; class EvalGlobalObject : public GlobalObject { diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.txt b/src/bun.js/bindings/ZigGlobalObject.lut.txt index fa44a60673b210..f263d6fe4578d7 100644 --- a/src/bun.js/bindings/ZigGlobalObject.lut.txt +++ b/src/bun.js/bindings/ZigGlobalObject.lut.txt @@ -69,24 +69,21 @@ PerformanceResourceTiming PerformanceResourceTimingConstructorCallback PropertyCallback PerformanceServerTiming PerformanceServerTimingConstructorCallback PropertyCallback PerformanceTiming PerformanceTimingConstructorCallback PropertyCallback - ReadableByteStreamController ReadableByteStreamControllerConstructorCallback PropertyCallback - ReadableStream ReadableStreamConstructorCallback PropertyCallback - ReadableStreamBYOBReader ReadableStreamBYOBReaderConstructorCallback PropertyCallback - ReadableStreamBYOBRequest ReadableStreamBYOBRequestConstructorCallback PropertyCallback - ReadableStreamDefaultController ReadableStreamDefaultControllerConstructorCallback PropertyCallback - ReadableStreamDefaultReader ReadableStreamDefaultReaderConstructorCallback PropertyCallback + ReadableStream JSReadableStreamConstructorCallback PropertyCallback + ReadableStreamDefaultController JSReadableStreamDefaultControllerConstructorCallback PropertyCallback + ReadableStreamDefaultReader JSReadableStreamDefaultReaderConstructorCallback PropertyCallback SubtleCrypto SubtleCryptoConstructorCallback PropertyCallback TextDecoderStream TextDecoderStreamConstructorCallback PropertyCallback TextEncoder TextEncoderConstructorCallback PropertyCallback TextEncoderStream TextEncoderStreamConstructorCallback PropertyCallback - TransformStream TransformStreamConstructorCallback PropertyCallback - TransformStreamDefaultController TransformStreamDefaultControllerConstructorCallback PropertyCallback + TransformStream JSTransformStreamConstructorCallback PropertyCallback + TransformStreamDefaultController JSTransformStreamDefaultControllerConstructorCallback PropertyCallback URL DOMURLConstructorCallback PropertyCallback URLSearchParams URLSearchParamsConstructorCallback PropertyCallback WebSocket WebSocketConstructorCallback PropertyCallback Worker WorkerConstructorCallback PropertyCallback - WritableStream WritableStreamConstructorCallback PropertyCallback - WritableStreamDefaultController WritableStreamDefaultControllerConstructorCallback PropertyCallback - WritableStreamDefaultWriter WritableStreamDefaultWriterConstructorCallback PropertyCallback + WritableStream JSWritableStreamConstructorCallback PropertyCallback + WritableStreamDefaultController JSWritableStreamDefaultControllerConstructorCallback PropertyCallback + WritableStreamDefaultWriter JSWritableStreamDefaultWriterConstructorCallback PropertyCallback @end */ diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 45fb786707bbeb..0180a8e1b0a53a 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -130,6 +130,7 @@ #include "ObjectBindings.h" #include +#include "BunPromiseInlines.h" #if OS(DARWIN) #if BUN_DEBUG @@ -2732,18 +2733,20 @@ static JSC::Identifier jsValueToModuleKey(JSC::JSGlobalObject* lexicalGlobalObje JSC__JSValue ReadableStream__empty(Zig::GlobalObject* globalObject) { - auto& vm = globalObject->vm(); - auto clientData = WebCore::clientData(vm); - auto* function = globalObject->getDirect(vm, clientData->builtinNames().createEmptyReadableStreamPrivateName()).getObject(); - return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); + return JSValue::encode(jsUndefined()); + // auto& vm = globalObject->vm(); + // auto clientData = WebCore::clientData(vm); + // auto* function = globalObject->getDirect(vm, clientData->builtinNames().createEmptyReadableStreamPrivateName()).getObject(); + // return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); } JSC__JSValue ReadableStream__used(Zig::GlobalObject* globalObject) { - auto& vm = globalObject->vm(); - auto clientData = WebCore::clientData(vm); - auto* function = globalObject->getDirect(vm, clientData->builtinNames().createUsedReadableStreamPrivateName()).getObject(); - return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); + return JSValue::encode(jsUndefined()); + // auto& vm = globalObject->vm(); + // auto clientData = WebCore::clientData(vm); + // auto* function = globalObject->getDirect(vm, clientData->builtinNames().createUsedReadableStreamPrivateName()).getObject(); + // return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); } JSC__JSValue JSC__JSValue__createRangeError(const ZigString* message, const ZigString* arg1, @@ -3266,7 +3269,7 @@ JSC__JSValue JSC__JSPromise__wrap(JSC__JSGlobalObject* globalObject, void* ctx, return JSValue::encode(JSC::JSPromise::rejectedPromise(globalObject, err)); } - return JSValue::encode(JSC::JSPromise::resolvedPromise(globalObject, result)); + return JSValue::encode(Bun::createFulfilledPromise(globalObject, result)); } void JSC__JSPromise__reject(JSC__JSPromise* arg0, JSC__JSGlobalObject* globalObject, diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index dc805895d2ec81..1c21dde245f28e 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -58,6 +58,11 @@ class DOMClientIsoSubspaces { std::unique_ptr m_clientSubspaceForFunctionTemplate; std::unique_ptr m_clientSubspaceForV8Function; std::unique_ptr m_clientSubspaceForNodeVMGlobalObject; + std::unique_ptr m_clientSubspaceForJSReadableStreamDefaultController; + std::unique_ptr m_clientSubspaceForJSReadableStreamDefaultReader; + std::unique_ptr m_clientSubspaceForJSReadableStreamBYOBReader; + std::unique_ptr m_clientSubspaceForJSReadableStream; + std::unique_ptr m_clientSubspaceForTeeState; #include "ZigGeneratedClasses+DOMClientIsoSubspaces.h" /* --- bun --- */ diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index 2d4eb091c5129f..1cae36540de466 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -58,7 +58,10 @@ class DOMIsoSubspaces { std::unique_ptr m_subspaceForFunctionTemplate; std::unique_ptr m_subspaceForV8Function; std::unique_ptr m_subspaceForNodeVMGlobalObject; - + std::unique_ptr m_subspaceForJSReadableStreamDefaultController; + std::unique_ptr m_subspaceForJSReadableStreamDefaultReader; + std::unique_ptr m_subspaceForJSReadableStreamBYOBReader; + std::unique_ptr m_subspaceForTeeState; #include "ZigGeneratedClasses+DOMIsoSubspaces.h" /*-- BUN --*/ diff --git a/src/bun.js/bindings/webcore/InternalWritableStream.cpp b/src/bun.js/bindings/webcore/InternalWritableStream.cpp deleted file mode 100644 index d63acc71f57c20..00000000000000 --- a/src/bun.js/bindings/webcore/InternalWritableStream.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2020-2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CANON INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "InternalWritableStream.h" - -#include "Exception.h" -#include "WebCoreJSClientData.h" - -namespace WebCore { - -static ExceptionOr invokeWritableStreamFunction(JSC::JSGlobalObject& globalObject, const JSC::Identifier& identifier, const JSC::MarkedArgumentBuffer& arguments) -{ - JSC::VM& vm = globalObject.vm(); - JSC::JSLockHolder lock(vm); - - auto scope = DECLARE_CATCH_SCOPE(vm); - - auto function = globalObject.get(&globalObject, identifier); - ASSERT(function.isCallable()); - scope.assertNoExceptionExceptTermination(); - - auto callData = JSC::getCallData(function); - - auto result = call(&globalObject, function, callData, JSC::jsUndefined(), arguments); - RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError }); - - return result; -} - -ExceptionOr> InternalWritableStream::createFromUnderlyingSink(JSDOMGlobalObject& globalObject, JSC::JSValue underlyingSink, JSC::JSValue strategy) -{ - auto* clientData = static_cast(globalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().createInternalWritableStreamFromUnderlyingSinkPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(underlyingSink); - arguments.append(strategy); - ASSERT(!arguments.hasOverflowed()); - - auto result = invokeWritableStreamFunction(globalObject, privateName, arguments); - if (UNLIKELY(result.hasException())) - return result.releaseException(); - - ASSERT(result.returnValue().isObject()); - return adoptRef(*new InternalWritableStream(globalObject, *result.returnValue().toObject(&globalObject))); -} - -Ref InternalWritableStream::fromObject(JSDOMGlobalObject& globalObject, JSC::JSObject& object) -{ - return adoptRef(*new InternalWritableStream(globalObject, object)); -} - -bool InternalWritableStream::locked() const -{ - auto* globalObject = this->globalObject(); - if (!globalObject) - return false; - - auto scope = DECLARE_CATCH_SCOPE(globalObject->vm()); - - auto* clientData = static_cast(globalObject->vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().isWritableStreamLockedPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(guardedObject()); - ASSERT(!arguments.hasOverflowed()); - - auto result = invokeWritableStreamFunction(*globalObject, privateName, arguments); - if (scope.exception()) - scope.clearException(); - - return result.hasException() ? false : result.returnValue().isTrue(); -} - -void InternalWritableStream::lock() -{ - auto* globalObject = this->globalObject(); - if (!globalObject) - return; - - auto scope = DECLARE_CATCH_SCOPE(globalObject->vm()); - - auto* clientData = static_cast(globalObject->vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().acquireWritableStreamDefaultWriterPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(guardedObject()); - ASSERT(!arguments.hasOverflowed()); - - invokeWritableStreamFunction(*globalObject, privateName, arguments); - if (UNLIKELY(scope.exception())) - scope.clearException(); -} - -JSC::JSValue InternalWritableStream::abort(JSC::JSGlobalObject& globalObject, JSC::JSValue reason) -{ - auto* clientData = static_cast(globalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().writableStreamAbortForBindingsPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(guardedObject()); - arguments.append(reason); - ASSERT(!arguments.hasOverflowed()); - - auto result = invokeWritableStreamFunction(globalObject, privateName, arguments); - if (result.hasException()) - return {}; - - return result.returnValue(); -} - -JSC::JSValue InternalWritableStream::close(JSC::JSGlobalObject& globalObject) -{ - auto* clientData = static_cast(globalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().writableStreamCloseForBindingsPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(guardedObject()); - ASSERT(!arguments.hasOverflowed()); - - auto result = invokeWritableStreamFunction(globalObject, privateName, arguments); - if (result.hasException()) - return {}; - - return result.returnValue(); -} - -JSC::JSValue InternalWritableStream::getWriter(JSC::JSGlobalObject& globalObject) -{ - auto* clientData = static_cast(globalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().writableStreamInternalsBuiltins().acquireWritableStreamDefaultWriterPrivateName(); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(guardedObject()); - ASSERT(!arguments.hasOverflowed()); - - auto result = invokeWritableStreamFunction(globalObject, privateName, arguments); - if (result.hasException()) - return {}; - - return result.returnValue(); -} - -} diff --git a/src/bun.js/bindings/webcore/InternalWritableStream.h b/src/bun.js/bindings/webcore/InternalWritableStream.h deleted file mode 100644 index a768f959d7fb67..00000000000000 --- a/src/bun.js/bindings/webcore/InternalWritableStream.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2020-2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CANON INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "ExceptionOr.h" -#include "JSDOMGuardedObject.h" -#include - -namespace WebCore { -class InternalWritableStream final : public DOMGuarded { -public: - static ExceptionOr> createFromUnderlyingSink(JSDOMGlobalObject&, JSC::JSValue underlyingSink, JSC::JSValue strategy); - static Ref fromObject(JSDOMGlobalObject&, JSC::JSObject&); - - operator JSC::JSValue() const { return guarded(); } - - bool locked() const; - void lock(); - JSC::JSValue abort(JSC::JSGlobalObject&, JSC::JSValue); - JSC::JSValue close(JSC::JSGlobalObject&); - JSC::JSValue getWriter(JSC::JSGlobalObject&); - -private: - InternalWritableStream(JSDOMGlobalObject& globalObject, JSC::JSObject& jsObject) - : DOMGuarded(globalObject, jsObject) - { - } -}; - -} diff --git a/src/bun.js/bindings/webcore/JSDOMConstructorBase.cpp b/src/bun.js/bindings/webcore/JSDOMConstructorBase.cpp index 09556cf5c9280a..51cbb6f3fda138 100644 --- a/src/bun.js/bindings/webcore/JSDOMConstructorBase.cpp +++ b/src/bun.js/bindings/webcore/JSDOMConstructorBase.cpp @@ -36,13 +36,37 @@ JSC_DEFINE_HOST_FUNCTION(callThrowTypeErrorForJSDOMConstructor, (JSGlobalObject VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* callee = callframe->jsCallee(); - auto* constructor = jsDynamicCast(callee); + auto* constructor = jsDynamicCast(callee); const auto& name = constructor->name(); RETURN_IF_EXCEPTION(scope, {}); Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, makeString("Use `new "_s, name, "(...)` instead of `"_s, name, "(...)`"_s)); return {}; } +JSC_DEFINE_HOST_FUNCTION(callThrowTypeErrorForJSDOMConstructorNotConstructable, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + auto* callee = callframe->jsCallee(); + auto* constructor = jsDynamicCast(callee); + const auto& name = constructor->name(); + RETURN_IF_EXCEPTION(scope, {}); + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, makeString("Use `new "_s, name, "(...)` instead of `"_s, name, "(...)`"_s)); + return {}; +} + +JSC_DEFINE_HOST_FUNCTION(callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + auto* callee = callframe->jsCallee(); + auto* constructor = jsDynamicCast(callee); + const auto& name = constructor->name(); + RETURN_IF_EXCEPTION(scope, {}); + Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, makeString("Constructor for "_s, name, " cannot be constructed directly, but you can use it for instanceof."_s)); + return {}; +} + JSC::GCClient::IsoSubspace* JSDOMConstructorBase::subspaceForImpl(JSC::VM& vm) { return &static_cast(vm.clientData)->domConstructorSpace(); diff --git a/src/bun.js/bindings/webcore/JSDOMConstructorBase.h b/src/bun.js/bindings/webcore/JSDOMConstructorBase.h index 44c60e69ced8c6..75dd299ee0de8c 100644 --- a/src/bun.js/bindings/webcore/JSDOMConstructorBase.h +++ b/src/bun.js/bindings/webcore/JSDOMConstructorBase.h @@ -27,6 +27,7 @@ namespace WebCore { JSC_DECLARE_HOST_FUNCTION(callThrowTypeErrorForJSDOMConstructor); +JSC_DECLARE_HOST_FUNCTION(callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable); // Base class for all callable constructor objects in the JSC bindings. class JSDOMConstructorBase : public JSC::InternalFunction { @@ -53,8 +54,10 @@ class JSDOMConstructorBase : public JSC::InternalFunction { protected: JSDOMConstructorBase(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction functionForConstruct, JSC::NativeFunction functionForCall = nullptr) : Base(vm, structure, - functionForCall ? functionForCall : callThrowTypeErrorForJSDOMConstructor, - functionForConstruct ? functionForConstruct : callThrowTypeErrorForJSDOMConstructor) + !functionForCall && !functionForConstruct ? callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable : functionForCall ? functionForCall + : callThrowTypeErrorForJSDOMConstructor, + !functionForConstruct ? callThrowTypeErrorForJSDOMConstructorNotCallableOrConstructable : functionForConstruct ? functionForConstruct + : callThrowTypeErrorForJSDOMConstructor) { } }; diff --git a/src/bun.js/bindings/webcore/JSDOMConvertPromise.h b/src/bun.js/bindings/webcore/JSDOMConvertPromise.h index 5d307c86f62b6d..4542f3fdc4e77d 100644 --- a/src/bun.js/bindings/webcore/JSDOMConvertPromise.h +++ b/src/bun.js/bindings/webcore/JSDOMConvertPromise.h @@ -28,6 +28,7 @@ #include "IDLTypes.h" #include "JSDOMConvertBase.h" #include "JSDOMPromise.h" +#include "BunPromiseInlines.h" // #include "WorkerGlobalScope.h" namespace WebCore { @@ -47,7 +48,7 @@ template struct Converter> : DefaultConverterscriptExecutionContext(); // if (is(scriptExecutionContext)) { diff --git a/src/bun.js/bindings/webcore/JSReadableByteStreamController.cpp b/src/bun.js/bindings/webcore/JSReadableByteStreamController.cpp deleted file mode 100644 index 5c21c427922072..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableByteStreamController.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableByteStreamController.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableByteStreamControllerConstructor); - -class JSReadableByteStreamControllerPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableByteStreamControllerPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableByteStreamControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableByteStreamControllerPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableByteStreamControllerPrototype, Base); - 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: - JSReadableByteStreamControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableByteStreamControllerPrototype, JSReadableByteStreamControllerPrototype::Base); - -using JSReadableByteStreamControllerDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableByteStreamControllerDOMConstructor::s_info = { "ReadableByteStreamController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableByteStreamControllerDOMConstructor) }; - -template<> JSValue JSReadableByteStreamControllerDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableByteStreamControllerDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(3), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableByteStreamController"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableByteStreamController::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableByteStreamControllerDOMConstructor::initializeExecutable(VM& vm) -{ - return readableByteStreamControllerInitializeReadableByteStreamControllerCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableByteStreamControllerPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableByteStreamControllerConstructor, 0 } }, - { "byobRequest"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableByteStreamControllerByobRequestCodeGenerator, 0 } }, - { "desiredSize"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableByteStreamControllerDesiredSizeCodeGenerator, 0 } }, - { "enqueue"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableByteStreamControllerEnqueueCodeGenerator, 0 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableByteStreamControllerCloseCodeGenerator, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableByteStreamControllerErrorCodeGenerator, 0 } }, -}; - -const ClassInfo JSReadableByteStreamControllerPrototype::s_info = { "ReadableByteStreamController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableByteStreamControllerPrototype) }; - -void JSReadableByteStreamControllerPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableByteStreamController::info(), JSReadableByteStreamControllerPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableByteStreamController::s_info = { "ReadableByteStreamController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableByteStreamController) }; - -JSReadableByteStreamController::JSReadableByteStreamController(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableByteStreamController::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSReadableByteStreamController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableByteStreamControllerPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableByteStreamControllerPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableByteStreamController::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableByteStreamController::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableByteStreamController::destroy(JSC::JSCell* cell) -{ - JSReadableByteStreamController* thisObject = static_cast(cell); - thisObject->JSReadableByteStreamController::~JSReadableByteStreamController(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableByteStreamControllerConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableByteStreamController::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableByteStreamController::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableByteStreamController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableByteStreamController = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableByteStreamController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableByteStreamController = std::forward(space); }); -} -} diff --git a/src/bun.js/bindings/webcore/JSReadableByteStreamController.h b/src/bun.js/bindings/webcore/JSReadableByteStreamController.h deleted file mode 100644 index 6fbe0488f53e42..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableByteStreamController.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableByteStreamController : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSReadableByteStreamController* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableByteStreamController* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableByteStreamController(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSReadableByteStreamController(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStream.cpp b/src/bun.js/bindings/webcore/JSReadableStream.cpp deleted file mode 100644 index 8f79cf3c799b20..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStream.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStream.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include -#include "ZigGeneratedClasses.h" -#include "JavaScriptCore/BuiltinNames.h" - -namespace WebCore { -using namespace JSC; - -extern "C" void ReadableStream__incrementCount(void*, int32_t); - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamConstructor); - -class JSReadableStreamPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamPrototype, Base); - 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: - JSReadableStreamPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamPrototype, JSReadableStreamPrototype::Base); - -using JSReadableStreamDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableStreamDOMConstructor::s_info = { "ReadableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDOMConstructor) }; - -template<> JSValue JSReadableStreamDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableStreamDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableStream"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableStream::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableStreamDOMConstructor::initializeExecutable(VM& vm) -{ - return readableStreamInitializeReadableStreamCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamConstructor, 0 } }, - { "locked"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamLockedCodeGenerator, 0 } }, - { "cancel"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamCancelCodeGenerator, 0 } }, - { "getReader"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamGetReaderCodeGenerator, 0 } }, - { "pipeTo"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamPipeToCodeGenerator, 1 } }, - { "pipeThrough"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamPipeThroughCodeGenerator, 2 } }, - { "tee"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamTeeCodeGenerator, 0 } }, - -}; - -const ClassInfo JSReadableStreamPrototype::s_info = { "ReadableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamPrototype) }; - -static JSC_DEFINE_CUSTOM_SETTER(JSReadableStreamPrototype__nativePtrSetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::EncodedJSValue encodedJSValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - thisObject->setNativePtr(lexicalGlobalObject->vm(), JSValue::decode(encodedJSValue)); - return true; -} - -static JSC_DEFINE_CUSTOM_GETTER(JSReadableStreamPrototype__nativePtrGetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - - // Force it to be locked, even though the value is still really there. - if (thisObject->isNativeTypeTransferred()) { - return JSValue::encode(jsNumber(-1)); - } - - return JSValue::encode(thisObject->nativePtr()); -} - -static JSC_DEFINE_CUSTOM_SETTER(JSReadableStreamPrototype__nativeTypeSetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::EncodedJSValue encodedJSValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - thisObject->setNativeType(JSValue::decode(encodedJSValue).toInt32(lexicalGlobalObject)); - return true; -} - -static JSC_DEFINE_CUSTOM_GETTER(JSReadableStreamPrototype__nativeTypeGetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - return JSValue::encode(jsNumber(thisObject->nativeType())); -} - -static JSC_DEFINE_CUSTOM_SETTER(JSReadableStreamPrototype__disturbedSetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::EncodedJSValue encodedJSValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - thisObject->setDisturbed(JSValue::decode(encodedJSValue).toBoolean(lexicalGlobalObject)); - return true; -} - -static JSC_DEFINE_CUSTOM_GETTER(JSReadableStreamPrototype__disturbedGetterWrap, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue encodedThisValue, JSC::PropertyName)) -{ - JSReadableStream* thisObject = jsCast(JSValue::decode(encodedThisValue)); - return JSValue::encode(jsBoolean(thisObject->disturbed())); -} - -void JSReadableStreamPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - auto clientData = WebCore::clientData(vm); - - this->putDirectCustomAccessor(vm, clientData->builtinNames().bunNativePtrPrivateName(), DOMAttributeGetterSetter::create(vm, JSReadableStreamPrototype__nativePtrGetterWrap, JSReadableStreamPrototype__nativePtrSetterWrap, DOMAttributeAnnotation { JSReadableStream::info(), nullptr }), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete); - this->putDirectCustomAccessor(vm, clientData->builtinNames().bunNativeTypePrivateName(), DOMAttributeGetterSetter::create(vm, JSReadableStreamPrototype__nativeTypeGetterWrap, JSReadableStreamPrototype__nativeTypeSetterWrap, DOMAttributeAnnotation { JSReadableStream::info(), nullptr }), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete); - this->putDirectCustomAccessor(vm, clientData->builtinNames().disturbedPrivateName(), DOMAttributeGetterSetter::create(vm, JSReadableStreamPrototype__disturbedGetterWrap, JSReadableStreamPrototype__disturbedSetterWrap, DOMAttributeAnnotation { JSReadableStream::info(), nullptr }), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete); - - reifyStaticProperties(vm, JSReadableStream::info(), JSReadableStreamPrototypeTableValues, *this); - this->putDirectBuiltinFunction(vm, globalObject(), vm.propertyNames->asyncIteratorSymbol, readableStreamLazyAsyncIteratorCodeGenerator(vm), JSC::PropertyAttribute::DontDelete | 0); - this->putDirectBuiltinFunction(vm, globalObject(), vm.propertyNames->builtinNames().valuesPublicName(), readableStreamValuesCodeGenerator(vm), JSC::PropertyAttribute::DontDelete | 0); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableStream::s_info = { "ReadableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStream) }; - -JSReadableStream::JSReadableStream(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableStream::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -void JSReadableStream::setNativePtr(JSC::VM& vm, JSC::JSValue value) -{ - this->m_nativePtr.set(vm, this, value); -} - -JSObject* JSReadableStream::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStream::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableStream::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableStream::destroy(JSC::JSCell* cell) -{ - JSReadableStream* thisObject = static_cast(cell); - thisObject->JSReadableStream::~JSReadableStream(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableStream::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableStream::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStream = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStream = std::forward(space); }); -} - -template -void JSReadableStream::visitChildrenImpl(JSCell* cell, Visitor& visitor) -{ - JSReadableStream* stream = jsCast(cell); - ASSERT_GC_OBJECT_INHERITS(stream, info()); - Base::visitChildren(stream, visitor); - - visitor.append(stream->m_nativePtr); -} - -DEFINE_VISIT_CHILDREN(JSReadableStream); - -} diff --git a/src/bun.js/bindings/webcore/JSReadableStream.h b/src/bun.js/bindings/webcore/JSReadableStream.h deleted file mode 100644 index 45c14a9a7b6a2d..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStream.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableStream : public JSDOMObject { - -public: - using Base = JSDOMObject; - static JSReadableStream* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableStream* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStream(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - - int nativeType() const { return this->m_nativeType; } - bool disturbed() const { return this->m_disturbed; } - bool isNativeTypeTransferred() const { return this->m_transferred; } - void setTransferred() - { - this->m_transferred = true; - } - JSC::JSValue nativePtr() - { - return this->m_nativePtr.get(); - } - - void setNativePtr(JSC::VM&, JSC::JSValue value); - - void setNativeType(int value) - { - this->m_nativeType = value; - } - - void setDisturbed(bool value) - { - this->m_disturbed = value; - } - - DECLARE_VISIT_CHILDREN; - -protected: - mutable JSC::WriteBarrier m_nativePtr; - int m_nativeType { 0 }; - bool m_disturbed = false; - bool m_transferred = false; - - JSReadableStream(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.cpp b/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.cpp deleted file mode 100644 index 9568df1bcf0ba1..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamBYOBReader.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamBYOBReaderConstructor); - -class JSReadableStreamBYOBReaderPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamBYOBReaderPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamBYOBReaderPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamBYOBReaderPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamBYOBReaderPrototype, Base); - 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: - JSReadableStreamBYOBReaderPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamBYOBReaderPrototype, JSReadableStreamBYOBReaderPrototype::Base); - -using JSReadableStreamBYOBReaderDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableStreamBYOBReaderDOMConstructor::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReaderDOMConstructor) }; - -template<> JSValue JSReadableStreamBYOBReaderDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableStreamBYOBReaderDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(1), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableStreamBYOBReader"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableStreamBYOBReader::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableStreamBYOBReaderDOMConstructor::initializeExecutable(VM& vm) -{ - return readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamBYOBReaderPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamBYOBReaderConstructor, 0 } }, - { "closed"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamBYOBReaderClosedCodeGenerator, 0 } }, - { "read"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamBYOBReaderReadCodeGenerator, 0 } }, - { "cancel"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamBYOBReaderCancelCodeGenerator, 0 } }, - { "releaseLock"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamBYOBReaderReleaseLockCodeGenerator, 0 } }, -}; - -const ClassInfo JSReadableStreamBYOBReaderPrototype::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReaderPrototype) }; - -void JSReadableStreamBYOBReaderPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableStreamBYOBReader::info(), JSReadableStreamBYOBReaderPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableStreamBYOBReader::s_info = { "ReadableStreamBYOBReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBReader) }; - -JSReadableStreamBYOBReader::JSReadableStreamBYOBReader(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableStreamBYOBReader::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSReadableStreamBYOBReader::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamBYOBReaderPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamBYOBReaderPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamBYOBReader::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableStreamBYOBReader::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableStreamBYOBReader::destroy(JSC::JSCell* cell) -{ - JSReadableStreamBYOBReader* thisObject = static_cast(cell); - thisObject->JSReadableStreamBYOBReader::~JSReadableStreamBYOBReader(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamBYOBReaderConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableStreamBYOBReader::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamBYOBReader::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamBYOBReader.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamBYOBReader = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamBYOBReader.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamBYOBReader = std::forward(space); }); -} -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.h b/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.h deleted file mode 100644 index b206a3beed1260..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableStreamBYOBReader : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSReadableStreamBYOBReader* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableStreamBYOBReader* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamBYOBReader(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSReadableStreamBYOBReader(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.cpp b/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.cpp deleted file mode 100644 index 18f7c8834dbbd0..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamBYOBRequest.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamBYOBRequestConstructor); - -class JSReadableStreamBYOBRequestPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamBYOBRequestPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamBYOBRequestPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamBYOBRequestPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamBYOBRequestPrototype, Base); - 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: - JSReadableStreamBYOBRequestPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamBYOBRequestPrototype, JSReadableStreamBYOBRequestPrototype::Base); - -using JSReadableStreamBYOBRequestDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableStreamBYOBRequestDOMConstructor::s_info = { "ReadableStreamBYOBRequest"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBRequestDOMConstructor) }; - -template<> JSValue JSReadableStreamBYOBRequestDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableStreamBYOBRequestDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(2), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableStreamBYOBRequest"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableStreamBYOBRequest::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableStreamBYOBRequestDOMConstructor::initializeExecutable(VM& vm) -{ - return readableStreamBYOBRequestInitializeReadableStreamBYOBRequestCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamBYOBRequestPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamBYOBRequestConstructor, 0 } }, - { "view"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamBYOBRequestViewCodeGenerator, 0 } }, - { "respond"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamBYOBRequestRespondCodeGenerator, 0 } }, - { "respondWithNewView"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamBYOBRequestRespondWithNewViewCodeGenerator, 0 } }, -}; - -const ClassInfo JSReadableStreamBYOBRequestPrototype::s_info = { "ReadableStreamBYOBRequest"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBRequestPrototype) }; - -void JSReadableStreamBYOBRequestPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableStreamBYOBRequest::info(), JSReadableStreamBYOBRequestPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableStreamBYOBRequest::s_info = { "ReadableStreamBYOBRequest"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamBYOBRequest) }; - -JSReadableStreamBYOBRequest::JSReadableStreamBYOBRequest(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableStreamBYOBRequest::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSReadableStreamBYOBRequest::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamBYOBRequestPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamBYOBRequestPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamBYOBRequest::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableStreamBYOBRequest::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableStreamBYOBRequest::destroy(JSC::JSCell* cell) -{ - JSReadableStreamBYOBRequest* thisObject = static_cast(cell); - thisObject->JSReadableStreamBYOBRequest::~JSReadableStreamBYOBRequest(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamBYOBRequestConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableStreamBYOBRequest::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamBYOBRequest::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamBYOBRequest.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamBYOBRequest = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamBYOBRequest.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamBYOBRequest = std::forward(space); }); -} -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.h b/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.h deleted file mode 100644 index 94bb293b442f7d..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableStreamBYOBRequest : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSReadableStreamBYOBRequest* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableStreamBYOBRequest* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamBYOBRequest(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSReadableStreamBYOBRequest(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp b/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp deleted file mode 100644 index b69dde2844cc46..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamDefaultController.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamDefaultControllerConstructor); - -class JSReadableStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamDefaultControllerPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamDefaultControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultControllerPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultControllerPrototype, Base); - 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: - JSReadableStreamDefaultControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultControllerPrototype, JSReadableStreamDefaultControllerPrototype::Base); - -using JSReadableStreamDefaultControllerDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableStreamDefaultControllerDOMConstructor::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultControllerDOMConstructor) }; - -template<> JSValue JSReadableStreamDefaultControllerDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableStreamDefaultControllerDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(4), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableStreamDefaultController"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableStreamDefaultController::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableStreamDefaultControllerDOMConstructor::initializeExecutable(VM& vm) -{ - return readableStreamDefaultControllerInitializeReadableStreamDefaultControllerCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamDefaultControllerPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamDefaultControllerConstructor, 0 } }, - { "desiredSize"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamDefaultControllerDesiredSizeCodeGenerator, 0 } }, - { "enqueue"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerEnqueueCodeGenerator, 0 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerCloseCodeGenerator, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerErrorCodeGenerator, 0 } }, -}; - -const ClassInfo JSReadableStreamDefaultControllerPrototype::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultControllerPrototype) }; - -void JSReadableStreamDefaultControllerPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableStreamDefaultController::info(), JSReadableStreamDefaultControllerPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); - - auto clientData = WebCore::clientData(vm); - this->putDirect(vm, clientData->builtinNames().sinkPublicName(), jsUndefined(), JSC::PropertyAttribute::DontDelete | 0); -} - -const ClassInfo JSReadableStreamDefaultController::s_info = { "ReadableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultController) }; - -JSReadableStreamDefaultController::JSReadableStreamDefaultController(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableStreamDefaultController::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSReadableStreamDefaultController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamDefaultControllerPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamDefaultControllerPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamDefaultController::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableStreamDefaultController::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableStreamDefaultController::destroy(JSC::JSCell* cell) -{ - JSReadableStreamDefaultController* thisObject = static_cast(cell); - thisObject->JSReadableStreamDefaultController::~JSReadableStreamDefaultController(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableStreamDefaultController::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamDefaultController::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamDefaultController = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamDefaultController = std::forward(space); }); -} - -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.h b/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.h deleted file mode 100644 index 4279e712f1e58c..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableStreamDefaultController : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSReadableStreamDefaultController* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableStreamDefaultController* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamDefaultController(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSReadableStreamDefaultController(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp b/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp deleted file mode 100644 index e86af40e38e3a6..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamDefaultReader.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamDefaultReaderConstructor); - -class JSReadableStreamDefaultReaderPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamDefaultReaderPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamDefaultReaderPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamDefaultReaderPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultReaderPrototype, Base); - 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: - JSReadableStreamDefaultReaderPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamDefaultReaderPrototype, JSReadableStreamDefaultReaderPrototype::Base); - -using JSReadableStreamDefaultReaderDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSReadableStreamDefaultReaderDOMConstructor::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderDOMConstructor) }; - -template<> JSValue JSReadableStreamDefaultReaderDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSReadableStreamDefaultReaderDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(1), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "ReadableStreamDefaultReader"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSReadableStreamDefaultReader::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSReadableStreamDefaultReaderDOMConstructor::initializeExecutable(VM& vm) -{ - return readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamDefaultReaderPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamDefaultReaderConstructor, 0 } }, - { "closed"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamDefaultReaderClosedCodeGenerator, 0 } }, - { "read"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderReadCodeGenerator, 0 } }, - { "readMany"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderReadManyCodeGenerator, 0 } }, - { "cancel"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderCancelCodeGenerator, 0 } }, - { "releaseLock"_s, static_cast(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderReleaseLockCodeGenerator, 0 } }, -}; - -const ClassInfo JSReadableStreamDefaultReaderPrototype::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderPrototype) }; - -void JSReadableStreamDefaultReaderPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableStreamDefaultReader::info(), JSReadableStreamDefaultReaderPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); - // As suggested by https://github.com/tc39/proposal-explicit-resource-management#relation-to-dom-apis - // putDirectWithoutTransition(vm, vm.propertyNames->disposeSymbol, get(globalObject(), PropertyName(Identifier::fromString(vm, "releaseLock"_s))), JSC::PropertyAttribute::DontEnum | 0); -} - -const ClassInfo JSReadableStreamDefaultReader::s_info = { "ReadableStreamDefaultReader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamDefaultReader) }; - -JSReadableStreamDefaultReader::JSReadableStreamDefaultReader(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSReadableStreamDefaultReader::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSReadableStreamDefaultReader::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamDefaultReaderPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamDefaultReaderPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamDefaultReader::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSReadableStreamDefaultReader::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSReadableStreamDefaultReader::destroy(JSC::JSCell* cell) -{ - JSReadableStreamDefaultReader* thisObject = static_cast(cell); - thisObject->JSReadableStreamDefaultReader::~JSReadableStreamDefaultReader(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamDefaultReaderConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSReadableStreamDefaultReader::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamDefaultReader::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamDefaultReader.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamDefaultReader = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamDefaultReader.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamDefaultReader = std::forward(space); }); -} - -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.h b/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.h deleted file mode 100644 index 4178cf2be986f1..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSReadableStreamDefaultReader : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSReadableStreamDefaultReader* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSReadableStreamDefaultReader* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamDefaultReader(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSReadableStreamDefaultReader(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamSink.cpp b/src/bun.js/bindings/webcore/JSReadableStreamSink.cpp deleted file mode 100644 index 55e24a462ca03a..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamSink.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamSink.h" - -#include "ActiveDOMObject.h" -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "IDLTypes.h" -#include "JSDOMBinding.h" -#include "JSDOMConvertBase.h" -#include "JSDOMConvertBufferSource.h" -#include "JSDOMConvertStrings.h" -#include "JSDOMConvertUnion.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "ScriptExecutionContext.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_enqueue); -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_close); -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_error); - -class JSReadableStreamSinkPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamSinkPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamSinkPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamSinkPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamSinkPrototype, Base); - 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: - JSReadableStreamSinkPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamSinkPrototype, JSReadableStreamSinkPrototype::Base); - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamSinkPrototypeTableValues[] = { - { "enqueue"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSinkPrototypeFunction_enqueue, 1 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSinkPrototypeFunction_close, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSinkPrototypeFunction_error, 1 } }, -}; - -const ClassInfo JSReadableStreamSinkPrototype::s_info = { "ReadableStreamSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamSinkPrototype) }; - -void JSReadableStreamSinkPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSReadableStreamSink::info(), JSReadableStreamSinkPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableStreamSink::s_info = { "ReadableStreamSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamSink) }; - -JSReadableStreamSink::JSReadableStreamSink(Structure* structure, JSDOMGlobalObject& globalObject, Ref&& impl) - : JSDOMWrapper(structure, globalObject, WTFMove(impl)) -{ -} - -void JSReadableStreamSink::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - // static_assert(!std::is_base_of::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); -} - -JSObject* JSReadableStreamSink::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamSinkPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamSinkPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamSink::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -void JSReadableStreamSink::destroy(JSC::JSCell* cell) -{ - JSReadableStreamSink* thisObject = static_cast(cell); - thisObject->JSReadableStreamSink::~JSReadableStreamSink(); -} - -static inline JSC::EncodedJSValue jsReadableStreamSinkPrototypeFunction_enqueueBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - if (UNLIKELY(callFrame->argumentCount() < 1)) - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto chunk = convert>(*lexicalGlobalObject, argument0.value()); - RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.enqueue(WTFMove(chunk)); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_enqueue, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "enqueue"); -} - -static inline JSC::EncodedJSValue jsReadableStreamSinkPrototypeFunction_closeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.close(); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_close, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "close"); -} - -static inline JSC::EncodedJSValue jsReadableStreamSinkPrototypeFunction_errorBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - if (UNLIKELY(callFrame->argumentCount() < 1)) - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto message = convert(*lexicalGlobalObject, argument0.value()); - RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.error(WTFMove(message)); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSinkPrototypeFunction_error, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "error"); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamSink::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamSink.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamSink = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamSink.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamSink = std::forward(space); }); -} - -void JSReadableStreamSink::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) -{ - auto* thisObject = jsCast(cell); - analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped()); - if (thisObject->scriptExecutionContext()) - analyzer.setLabelForCell(cell, makeString("url "_s, thisObject->scriptExecutionContext()->url().string())); - Base::analyzeHeap(cell, analyzer); -} - -bool JSReadableStreamSinkOwner::isReachableFromOpaqueRoots(JSC::Handle handle, void*, AbstractSlotVisitor& visitor, ASCIILiteral* reason) -{ - UNUSED_PARAM(handle); - UNUSED_PARAM(visitor); - UNUSED_PARAM(reason); - return false; -} - -void JSReadableStreamSinkOwner::finalize(JSC::Handle handle, void* context) -{ - auto* jsReadableStreamSink = static_cast(handle.slot()->asCell()); - auto& world = *static_cast(context); - uncacheWrapper(world, &jsReadableStreamSink->wrapped(), jsReadableStreamSink); -} - -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref&& impl) -{ - return createWrapper(globalObject, WTFMove(impl)); -} - -JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, ReadableStreamSink& impl) -{ - return wrap(lexicalGlobalObject, globalObject, impl); -} - -ReadableStreamSink* JSReadableStreamSink::toWrapped(JSC::VM&, JSC::JSValue value) -{ - if (auto* wrapper = jsDynamicCast(value)) - return &wrapper->wrapped(); - return nullptr; -} - -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamSink.h b/src/bun.js/bindings/webcore/JSReadableStreamSink.h deleted file mode 100644 index 66c77c2c7091d1..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamSink.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" -#include "ReadableStreamSink.h" -#include - -namespace WebCore { - -class JSReadableStreamSink : public JSDOMWrapper { -public: - using Base = JSDOMWrapper; - static JSReadableStreamSink* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref&& impl) - { - JSReadableStreamSink* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamSink(structure, *globalObject, WTFMove(impl)); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static ReadableStreamSink* toWrapped(JSC::VM&, JSC::JSValue); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - -protected: - JSReadableStreamSink(JSC::Structure*, JSDOMGlobalObject&, Ref&&); - - void finishCreation(JSC::VM&); -}; - -class JSReadableStreamSinkOwner final : public JSC::WeakHandleOwner { -public: - bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::AbstractSlotVisitor&, ASCIILiteral*) final; - void finalize(JSC::Handle, void* context) final; -}; - -inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, ReadableStreamSink*) -{ - static NeverDestroyed owner; - return &owner.get(); -} - -inline void* wrapperKey(ReadableStreamSink* wrappableObject) -{ - return wrappableObject; -} - -JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, ReadableStreamSink&); -inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, ReadableStreamSink* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); } -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref&&); -inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); } - -template<> struct JSDOMWrapperConverterTraits { - using WrapperClass = JSReadableStreamSink; - using ToWrappedReturnType = ReadableStreamSink*; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamSource.cpp b/src/bun.js/bindings/webcore/JSReadableStreamSource.cpp deleted file mode 100644 index 0dfba1534392a8..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamSource.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSReadableStreamSource.h" - -#include "ActiveDOMObject.h" -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "IDLTypes.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMConvertAny.h" -#include "JSDOMConvertBase.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMOperation.h" -#include "JSDOMOperationReturningPromise.h" -#include "JSDOMWrapperCache.h" -#include "ScriptExecutionContext.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_start); -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_pull); -static JSC_DECLARE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_cancel); - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsReadableStreamSource_controller); - -class JSReadableStreamSourcePrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSReadableStreamSourcePrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSReadableStreamSourcePrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSReadableStreamSourcePrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamSourcePrototype, Base); - 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: - JSReadableStreamSourcePrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStreamSourcePrototype, JSReadableStreamSourcePrototype::Base); - -/* Hash table for prototype */ - -static const HashTableValue JSReadableStreamSourcePrototypeTableValues[] = { - { "controller"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamSource_controller, 0 } }, - { "start"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSourcePrototypeFunction_start, 1 } }, - { "pull"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSourcePrototypeFunction_pull, 1 } }, - { "cancel"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsReadableStreamSourcePrototypeFunction_cancel, 1 } }, -}; - -const ClassInfo JSReadableStreamSourcePrototype::s_info = { "ReadableStreamSource"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamSourcePrototype) }; - -void JSReadableStreamSourcePrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - // -- BUN ADDITION -- - auto clientData = WebCore::clientData(vm); - this->putDirect(vm, clientData->builtinNames().bunNativePtrPrivateName(), jsNumber(0), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | 0); - this->putDirect(vm, clientData->builtinNames().bunNativeTypePrivateName(), jsNumber(0), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | 0); - // -- BUN ADDITION -- - - reifyStaticProperties(vm, JSReadableStreamSource::info(), JSReadableStreamSourcePrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSReadableStreamSource::s_info = { "ReadableStreamSource"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStreamSource) }; - -JSReadableStreamSource::JSReadableStreamSource(Structure* structure, JSDOMGlobalObject& globalObject, Ref&& impl) - : JSDOMWrapper(structure, globalObject, WTFMove(impl)) -{ -} - -void JSReadableStreamSource::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - // static_assert(!std::is_base_of::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); -} - -JSObject* JSReadableStreamSource::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSReadableStreamSourcePrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSReadableStreamSourcePrototype::create(vm, &globalObject, structure); -} - -JSObject* JSReadableStreamSource::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -void JSReadableStreamSource::destroy(JSC::JSCell* cell) -{ - JSReadableStreamSource* thisObject = static_cast(cell); - thisObject->JSReadableStreamSource::~JSReadableStreamSource(); -} - -static inline JSValue jsReadableStreamSource_controllerGetter(JSGlobalObject& lexicalGlobalObject, JSReadableStreamSource& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return thisObject.controller(lexicalGlobalObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsReadableStreamSource_controller, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute::get(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSC::EncodedJSValue jsReadableStreamSourcePrototypeFunction_startBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperationReturningPromise::ClassParameter castedThis, Ref&& promise) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - RELEASE_AND_RETURN(throwScope, (JSValue::encode(castedThis->start(*lexicalGlobalObject, *callFrame, WTFMove(promise))))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_start, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperationReturningPromise::call(*lexicalGlobalObject, *callFrame, "start"); -} - -static inline JSC::EncodedJSValue jsReadableStreamSourcePrototypeFunction_pullBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperationReturningPromise::ClassParameter castedThis, Ref&& promise) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - RELEASE_AND_RETURN(throwScope, (JSValue::encode(castedThis->pull(*lexicalGlobalObject, *callFrame, WTFMove(promise))))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_pull, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperationReturningPromise::call(*lexicalGlobalObject, *callFrame, "pull"); -} - -static inline JSC::EncodedJSValue jsReadableStreamSourcePrototypeFunction_cancelBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - if (UNLIKELY(callFrame->argumentCount() < 1)) - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto reason = convert(*lexicalGlobalObject, argument0.value()); - RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.cancel(WTFMove(reason)); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsReadableStreamSourcePrototypeFunction_cancel, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "cancel"); -} - -JSC::GCClient::IsoSubspace* JSReadableStreamSource::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForReadableStreamSource.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableStreamSource = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForReadableStreamSource.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableStreamSource = std::forward(space); }); -} - -template -void JSReadableStreamSource::visitChildrenImpl(JSCell* cell, Visitor& visitor) -{ - auto* thisObject = jsCast(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - visitor.append(thisObject->m_controller); -} - -DEFINE_VISIT_CHILDREN(JSReadableStreamSource); - -void JSReadableStreamSource::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) -{ - auto* thisObject = jsCast(cell); - analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped()); - if (thisObject->scriptExecutionContext()) - analyzer.setLabelForCell(cell, makeString("url "_s, thisObject->scriptExecutionContext()->url().string())); - Base::analyzeHeap(cell, analyzer); -} - -bool JSReadableStreamSourceOwner::isReachableFromOpaqueRoots(JSC::Handle handle, void*, AbstractSlotVisitor& visitor, ASCIILiteral* reason) -{ - UNUSED_PARAM(handle); - UNUSED_PARAM(visitor); - UNUSED_PARAM(reason); - return false; -} - -void JSReadableStreamSourceOwner::finalize(JSC::Handle handle, void* context) -{ - auto* jsReadableStreamSource = static_cast(handle.slot()->asCell()); - auto& world = *static_cast(context); - uncacheWrapper(world, &jsReadableStreamSource->wrapped(), jsReadableStreamSource); -} - -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref&& impl) -{ - return createWrapper(globalObject, WTFMove(impl)); -} - -JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, ReadableStreamSource& impl) -{ - return wrap(lexicalGlobalObject, globalObject, impl); -} - -ReadableStreamSource* JSReadableStreamSource::toWrapped(JSC::VM&, JSC::JSValue value) -{ - if (auto* wrapper = jsDynamicCast(value)) - return &wrapper->wrapped(); - return nullptr; -} - -} diff --git a/src/bun.js/bindings/webcore/JSReadableStreamSource.h b/src/bun.js/bindings/webcore/JSReadableStreamSource.h deleted file mode 100644 index 6cd8f933f6316d..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamSource.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" -#include "ReadableStreamSource.h" -#include - -namespace WebCore { - -class JSReadableStreamSource : public JSDOMWrapper { -public: - using Base = JSDOMWrapper; - static JSReadableStreamSource* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref&& impl) - { - JSReadableStreamSource* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSReadableStreamSource(structure, *globalObject, WTFMove(impl)); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static ReadableStreamSource* toWrapped(JSC::VM&, JSC::JSValue); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - mutable JSC::WriteBarrier m_controller; - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - DECLARE_VISIT_CHILDREN; - - static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - - // Custom attributes - JSC::JSValue controller(JSC::JSGlobalObject&) const; - - // Custom functions - JSC::JSValue start(JSC::JSGlobalObject&, JSC::CallFrame&, Ref&&); - JSC::JSValue pull(JSC::JSGlobalObject&, JSC::CallFrame&, Ref&&); - -protected: - JSReadableStreamSource(JSC::Structure*, JSDOMGlobalObject&, Ref&&); - - void finishCreation(JSC::VM&); -}; - -class JSReadableStreamSourceOwner final : public JSC::WeakHandleOwner { -public: - bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::AbstractSlotVisitor&, ASCIILiteral*) final; - void finalize(JSC::Handle, void* context) final; -}; - -inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, ReadableStreamSource*) -{ - static NeverDestroyed owner; - return &owner.get(); -} - -inline void* wrapperKey(ReadableStreamSource* wrappableObject) -{ - return wrappableObject; -} - -JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, ReadableStreamSource&); -inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, ReadableStreamSource* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); } -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref&&); -inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); } - -template<> struct JSDOMWrapperConverterTraits { - using WrapperClass = JSReadableStreamSource; - using ToWrappedReturnType = ReadableStreamSource*; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSReadableStreamSourceCustom.cpp b/src/bun.js/bindings/webcore/JSReadableStreamSourceCustom.cpp deleted file mode 100644 index 7082fd6f293c01..00000000000000 --- a/src/bun.js/bindings/webcore/JSReadableStreamSourceCustom.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions - * are required to be met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Canon Inc. nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSReadableStreamSource.h" - -#include "JSDOMPromiseDeferred.h" - -namespace WebCore { -using namespace JSC; - -JSValue JSReadableStreamSource::start(JSGlobalObject& lexicalGlobalObject, CallFrame& callFrame, Ref&& promise) -{ - VM& vm = lexicalGlobalObject.vm(); - - // FIXME: Why is it ok to ASSERT the argument count here? - ASSERT(callFrame.argumentCount()); - JSReadableStreamDefaultController* controller = jsDynamicCast(callFrame.uncheckedArgument(0)); - ASSERT(controller); - - m_controller.set(vm, this, controller); - - wrapped().start(ReadableStreamDefaultController(controller), WTFMove(promise)); - - return jsUndefined(); -} - -JSValue JSReadableStreamSource::pull(JSGlobalObject&, CallFrame&, Ref&& promise) -{ - wrapped().pull(WTFMove(promise)); - return jsUndefined(); -} - -JSValue JSReadableStreamSource::controller(JSGlobalObject&) const -{ - ASSERT_NOT_REACHED(); - return jsUndefined(); -} - -} diff --git a/src/bun.js/bindings/webcore/JSTransformStream.cpp b/src/bun.js/bindings/webcore/JSTransformStream.cpp deleted file mode 100644 index 76488775aa0253..00000000000000 --- a/src/bun.js/bindings/webcore/JSTransformStream.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSTransformStream.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamConstructor); - -class JSTransformStreamPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSTransformStreamPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSTransformStreamPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSTransformStreamPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamPrototype, Base); - 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: - JSTransformStreamPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamPrototype, JSTransformStreamPrototype::Base); - -using JSTransformStreamDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSTransformStreamDOMConstructor::s_info = { "TransformStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDOMConstructor) }; - -template<> JSValue JSTransformStreamDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSTransformStreamDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "TransformStream"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSTransformStream::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSTransformStreamDOMConstructor::initializeExecutable(VM& vm) -{ - return transformStreamInitializeTransformStreamCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSTransformStreamPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsTransformStreamConstructor, 0 } }, - { "readable"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, transformStreamReadableCodeGenerator, 0 } }, - { "writable"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, transformStreamWritableCodeGenerator, 0 } }, -}; - -const ClassInfo JSTransformStreamPrototype::s_info = { "TransformStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamPrototype) }; - -void JSTransformStreamPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSTransformStream::info(), JSTransformStreamPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSTransformStream::s_info = { "TransformStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStream) }; - -JSTransformStream::JSTransformStream(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSTransformStream::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSTransformStream::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSTransformStreamPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSTransformStreamPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSTransformStream::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSTransformStream::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSTransformStream::destroy(JSC::JSCell* cell) -{ - JSTransformStream* thisObject = static_cast(cell); - thisObject->JSTransformStream::~JSTransformStream(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsTransformStreamConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSTransformStream::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSTransformStream::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForTransformStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTransformStream = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForTransformStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForTransformStream = std::forward(space); }); -} - -} diff --git a/src/bun.js/bindings/webcore/JSTransformStream.h b/src/bun.js/bindings/webcore/JSTransformStream.h deleted file mode 100644 index a68e7da4761d1e..00000000000000 --- a/src/bun.js/bindings/webcore/JSTransformStream.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSTransformStream : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSTransformStream* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSTransformStream* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSTransformStream(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSTransformStream(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp b/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp deleted file mode 100644 index 67309e62f1823a..00000000000000 --- a/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSTransformStreamDefaultController.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsTransformStreamDefaultControllerConstructor); - -class JSTransformStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSTransformStreamDefaultControllerPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSTransformStreamDefaultControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSTransformStreamDefaultControllerPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamDefaultControllerPrototype, Base); - 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: - JSTransformStreamDefaultControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTransformStreamDefaultControllerPrototype, JSTransformStreamDefaultControllerPrototype::Base); - -using JSTransformStreamDefaultControllerDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSTransformStreamDefaultControllerDOMConstructor::s_info = { "TransformStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultControllerDOMConstructor) }; - -template<> JSValue JSTransformStreamDefaultControllerDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSTransformStreamDefaultControllerDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "TransformStreamDefaultController"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSTransformStreamDefaultController::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSTransformStreamDefaultControllerDOMConstructor::initializeExecutable(VM& vm) -{ - return transformStreamDefaultControllerInitializeTransformStreamDefaultControllerCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSTransformStreamDefaultControllerPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsTransformStreamDefaultControllerConstructor, 0 } }, - { "desiredSize"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, transformStreamDefaultControllerDesiredSizeCodeGenerator, 0 } }, - { "enqueue"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, transformStreamDefaultControllerEnqueueCodeGenerator, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, transformStreamDefaultControllerErrorCodeGenerator, 0 } }, - { "terminate"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, transformStreamDefaultControllerTerminateCodeGenerator, 0 } }, -}; - -const ClassInfo JSTransformStreamDefaultControllerPrototype::s_info = { "TransformStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultControllerPrototype) }; - -void JSTransformStreamDefaultControllerPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSTransformStreamDefaultController::info(), JSTransformStreamDefaultControllerPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSTransformStreamDefaultController::s_info = { "TransformStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTransformStreamDefaultController) }; - -JSTransformStreamDefaultController::JSTransformStreamDefaultController(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSTransformStreamDefaultController::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSTransformStreamDefaultController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSTransformStreamDefaultControllerPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSTransformStreamDefaultControllerPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSTransformStreamDefaultController::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSTransformStreamDefaultController::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSTransformStreamDefaultController::destroy(JSC::JSCell* cell) -{ - JSTransformStreamDefaultController* thisObject = static_cast(cell); - thisObject->JSTransformStreamDefaultController::~JSTransformStreamDefaultController(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsTransformStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSTransformStreamDefaultController::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSTransformStreamDefaultController::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForTransformStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTransformStreamDefaultController = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForTransformStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForTransformStreamDefaultController = std::forward(space); }); -} -} diff --git a/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.h b/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.h deleted file mode 100644 index 9fe4c0568fe377..00000000000000 --- a/src/bun.js/bindings/webcore/JSTransformStreamDefaultController.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSTransformStreamDefaultController : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSTransformStreamDefaultController* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSTransformStreamDefaultController* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSTransformStreamDefaultController(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSTransformStreamDefaultController(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSWritableStream.cpp b/src/bun.js/bindings/webcore/JSWritableStream.cpp deleted file mode 100644 index 14c202ab89a948..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStream.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSWritableStream.h" - -#include "ActiveDOMObject.h" -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMConstructor.h" -#include "JSDOMConvertBoolean.h" -#include "JSDOMConvertInterface.h" -#include "JSDOMConvertObject.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMOperationReturningPromise.h" -#include "JSDOMWrapperCache.h" -#include "ScriptExecutionContext.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_abort); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_close); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_getWriter); - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamConstructor); -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStream_locked); - -class JSWritableStreamPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSWritableStreamPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSWritableStreamPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamPrototype, Base); - 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: - JSWritableStreamPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamPrototype, JSWritableStreamPrototype::Base); - -using JSWritableStreamDOMConstructor = JSDOMConstructor; - -template<> JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) -{ - VM& vm = lexicalGlobalObject->vm(); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* castedThis = jsCast(callFrame->jsCallee()); - ASSERT(castedThis); - EnsureStillAliveScope argument0 = callFrame->argument(0); - auto underlyingSink = argument0.value().isUndefined() ? std::optional::ReturnType>() : std::optional::ReturnType>(convert(*lexicalGlobalObject, argument0.value())); - RETURN_IF_EXCEPTION(throwScope, {}); - EnsureStillAliveScope argument1 = callFrame->argument(1); - auto strategy = argument1.value().isUndefined() ? std::optional::ReturnType>() : std::optional::ReturnType>(convert(*lexicalGlobalObject, argument1.value())); - RETURN_IF_EXCEPTION(throwScope, {}); - auto object = WritableStream::create(*castedThis->globalObject(), WTFMove(underlyingSink), WTFMove(strategy)); - if constexpr (IsExceptionOr) - RETURN_IF_EXCEPTION(throwScope, {}); - static_assert(TypeOrExceptionOrUnderlyingType::isRef); - auto jsValue = toJSNewlyCreated>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object)); - if constexpr (IsExceptionOr) - RETURN_IF_EXCEPTION(throwScope, {}); - setSubclassStructureIfNeeded(lexicalGlobalObject, callFrame, asObject(jsValue)); - RETURN_IF_EXCEPTION(throwScope, {}); - return JSValue::encode(jsValue); -} -JSC_ANNOTATE_HOST_FUNCTION(JSWritableStreamDOMConstructorConstruct, JSWritableStreamDOMConstructor::construct); - -template<> const ClassInfo JSWritableStreamDOMConstructor::s_info = { "WritableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDOMConstructor) }; - -template<> JSValue JSWritableStreamDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSWritableStreamDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "WritableStream"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSWritableStream::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -/* Hash table for prototype */ - -static const HashTableValue JSWritableStreamPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsWritableStreamConstructor, 0 } }, - { "locked"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsWritableStream_locked, 0 } }, - { "abort"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_abort, 0 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_close, 0 } }, - { "getWriter"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamPrototypeFunction_getWriter, 0 } }, -}; - -const ClassInfo JSWritableStreamPrototype::s_info = { "WritableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamPrototype) }; - -void JSWritableStreamPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSWritableStream::info(), JSWritableStreamPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSWritableStream::s_info = { "WritableStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStream) }; - -JSWritableStream::JSWritableStream(Structure* structure, JSDOMGlobalObject& globalObject, Ref&& impl) - : JSDOMWrapper(structure, globalObject, WTFMove(impl)) -{ -} - -void JSWritableStream::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - // static_assert(!std::is_base_of::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); -} - -JSObject* JSWritableStream::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSWritableStreamPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSWritableStreamPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSWritableStream::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSWritableStream::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSWritableStream::destroy(JSC::JSCell* cell) -{ - JSWritableStream* thisObject = static_cast(cell); - thisObject->JSWritableStream::~JSWritableStream(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSWritableStream::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -static inline JSValue jsWritableStream_lockedGetter(JSGlobalObject& lexicalGlobalObject, JSWritableStream& thisObject) -{ - auto& vm = JSC::getVM(&lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto& impl = thisObject.wrapped(); - RELEASE_AND_RETURN(throwScope, (toJS(lexicalGlobalObject, throwScope, impl.locked()))); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStream_locked, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute::get(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSC::EncodedJSValue jsWritableStreamPrototypeFunction_abortBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperationReturningPromise::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - RELEASE_AND_RETURN(throwScope, (JSValue::encode(castedThis->abort(*lexicalGlobalObject, *callFrame)))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_abort, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperationReturningPromise::callReturningOwnPromise(*lexicalGlobalObject, *callFrame, "abort"); -} - -static inline JSC::EncodedJSValue jsWritableStreamPrototypeFunction_closeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperationReturningPromise::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - RELEASE_AND_RETURN(throwScope, (JSValue::encode(castedThis->close(*lexicalGlobalObject, *callFrame)))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_close, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperationReturningPromise::callReturningOwnPromise(*lexicalGlobalObject, *callFrame, "close"); -} - -static inline JSC::EncodedJSValue jsWritableStreamPrototypeFunction_getWriterBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - RELEASE_AND_RETURN(throwScope, (JSValue::encode(castedThis->getWriter(*lexicalGlobalObject, *callFrame)))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamPrototypeFunction_getWriter, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "getWriter"); -} - -JSC::GCClient::IsoSubspace* JSWritableStream::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForWritableStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStream = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForWritableStream.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStream = std::forward(space); }); -} - -void JSWritableStream::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) -{ - auto* thisObject = jsCast(cell); - analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped()); - if (thisObject->scriptExecutionContext()) - analyzer.setLabelForCell(cell, makeString("url "_s, thisObject->scriptExecutionContext()->url().string())); - Base::analyzeHeap(cell, analyzer); -} - -bool JSWritableStreamOwner::isReachableFromOpaqueRoots(JSC::Handle handle, void*, AbstractSlotVisitor& visitor, ASCIILiteral* reason) -{ - UNUSED_PARAM(handle); - UNUSED_PARAM(visitor); - UNUSED_PARAM(reason); - return false; -} - -void JSWritableStreamOwner::finalize(JSC::Handle handle, void* context) -{ - auto* jsWritableStream = static_cast(handle.slot()->asCell()); - auto& world = *static_cast(context); - uncacheWrapper(world, &jsWritableStream->wrapped(), jsWritableStream); -} - -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref&& impl) -{ - return createWrapper(globalObject, WTFMove(impl)); -} - -JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, WritableStream& impl) -{ - return wrap(lexicalGlobalObject, globalObject, impl); -} - -WritableStream* JSWritableStream::toWrapped(JSC::VM&, JSC::JSValue value) -{ - if (auto* wrapper = jsDynamicCast(value)) - return &wrapper->wrapped(); - return nullptr; -} - -} diff --git a/src/bun.js/bindings/webcore/JSWritableStream.h b/src/bun.js/bindings/webcore/JSWritableStream.h deleted file mode 100644 index dd5cbc885fc1f4..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStream.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" -#include "WritableStream.h" -#include - -namespace WebCore { - -class JSWritableStream : public JSDOMWrapper { -public: - using Base = JSDOMWrapper; - static JSWritableStream* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref&& impl) - { - JSWritableStream* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSWritableStream(structure, *globalObject, WTFMove(impl)); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static WritableStream* toWrapped(JSC::VM&, JSC::JSValue); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - - // Custom functions - JSC::JSValue abort(JSC::JSGlobalObject&, JSC::CallFrame&); - JSC::JSValue close(JSC::JSGlobalObject&, JSC::CallFrame&); - JSC::JSValue getWriter(JSC::JSGlobalObject&, JSC::CallFrame&); - -protected: - JSWritableStream(JSC::Structure*, JSDOMGlobalObject&, Ref&&); - - void finishCreation(JSC::VM&); -}; - -class JSWritableStreamOwner final : public JSC::WeakHandleOwner { -public: - bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::AbstractSlotVisitor&, ASCIILiteral*) final; - void finalize(JSC::Handle, void* context) final; -}; - -inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, WritableStream*) -{ - static NeverDestroyed owner; - return &owner.get(); -} - -inline void* wrapperKey(WritableStream* wrappableObject) -{ - return wrappableObject; -} - -JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, WritableStream&); -inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, WritableStream* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); } -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref&&); -inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); } - -template<> struct JSDOMWrapperConverterTraits { - using WrapperClass = JSWritableStream; - using ToWrappedReturnType = WritableStream*; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.cpp b/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.cpp deleted file mode 100644 index 15b0097a6a2ff2..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSWritableStreamDefaultController.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultControllerConstructor); - -class JSWritableStreamDefaultControllerPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSWritableStreamDefaultControllerPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSWritableStreamDefaultControllerPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultControllerPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultControllerPrototype, Base); - 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: - JSWritableStreamDefaultControllerPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultControllerPrototype, JSWritableStreamDefaultControllerPrototype::Base); - -using JSWritableStreamDefaultControllerDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSWritableStreamDefaultControllerDOMConstructor::s_info = { "WritableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultControllerDOMConstructor) }; - -template<> JSValue JSWritableStreamDefaultControllerDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSWritableStreamDefaultControllerDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "WritableStreamDefaultController"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSWritableStreamDefaultController::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSWritableStreamDefaultControllerDOMConstructor::initializeExecutable(VM& vm) -{ - return writableStreamDefaultControllerInitializeWritableStreamDefaultControllerCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSWritableStreamDefaultControllerPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsWritableStreamDefaultControllerConstructor, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, writableStreamDefaultControllerErrorCodeGenerator, 0 } }, -}; - -const ClassInfo JSWritableStreamDefaultControllerPrototype::s_info = { "WritableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultControllerPrototype) }; - -void JSWritableStreamDefaultControllerPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSWritableStreamDefaultController::info(), JSWritableStreamDefaultControllerPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSWritableStreamDefaultController::s_info = { "WritableStreamDefaultController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultController) }; - -JSWritableStreamDefaultController::JSWritableStreamDefaultController(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSWritableStreamDefaultController::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSWritableStreamDefaultController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSWritableStreamDefaultControllerPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSWritableStreamDefaultControllerPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSWritableStreamDefaultController::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSWritableStreamDefaultController::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSWritableStreamDefaultController::destroy(JSC::JSCell* cell) -{ - JSWritableStreamDefaultController* thisObject = static_cast(cell); - thisObject->JSWritableStreamDefaultController::~JSWritableStreamDefaultController(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSWritableStreamDefaultController::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSWritableStreamDefaultController::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForWritableStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStreamDefaultController = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForWritableStreamDefaultController.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStreamDefaultController = std::forward(space); }); -} - -} diff --git a/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.h b/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.h deleted file mode 100644 index c695f439b94843..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamDefaultController.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSWritableStreamDefaultController : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSWritableStreamDefaultController* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSWritableStreamDefaultController* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSWritableStreamDefaultController(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSWritableStreamDefaultController(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.cpp b/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.cpp deleted file mode 100644 index a9e758f6f11044..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSWritableStreamDefaultWriter.h" - -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "JSDOMAttribute.h" -#include "JSDOMBinding.h" -#include "JSDOMBuiltinConstructor.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObjectInlines.h" -#include "JSDOMOperation.h" -#include "JSDOMWrapperCache.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -// Attributes - -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterConstructor); - -class JSWritableStreamDefaultWriterPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSWritableStreamDefaultWriterPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSWritableStreamDefaultWriterPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultWriterPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriterPrototype, Base); - 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: - JSWritableStreamDefaultWriterPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriterPrototype, JSWritableStreamDefaultWriterPrototype::Base); - -using JSWritableStreamDefaultWriterDOMConstructor = JSDOMBuiltinConstructor; - -template<> const ClassInfo JSWritableStreamDefaultWriterDOMConstructor::s_info = { "WritableStreamDefaultWriter"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterDOMConstructor) }; - -template<> JSValue JSWritableStreamDefaultWriterDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) -{ - UNUSED_PARAM(vm); - return globalObject.functionPrototype(); -} - -template<> void JSWritableStreamDefaultWriterDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) -{ - putDirect(vm, vm.propertyNames->length, jsNumber(1), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - JSString* nameString = jsNontrivialString(vm, "WritableStreamDefaultWriter"_s); - m_originalName.set(vm, this, nameString); - putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); - putDirect(vm, vm.propertyNames->prototype, JSWritableStreamDefaultWriter::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); -} - -template<> FunctionExecutable* JSWritableStreamDefaultWriterDOMConstructor::initializeExecutable(VM& vm) -{ - return writableStreamDefaultWriterInitializeWritableStreamDefaultWriterCodeGenerator(vm); -} - -/* Hash table for prototype */ - -static const HashTableValue JSWritableStreamDefaultWriterPrototypeTableValues[] = { - { "constructor"_s, static_cast(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterConstructor, 0 } }, - { "closed"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, writableStreamDefaultWriterClosedCodeGenerator, 0 } }, - { "desiredSize"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, writableStreamDefaultWriterDesiredSizeCodeGenerator, 0 } }, - { "ready"_s, static_cast(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, writableStreamDefaultWriterReadyCodeGenerator, 0 } }, - { "abort"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, writableStreamDefaultWriterAbortCodeGenerator, 0 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, writableStreamDefaultWriterCloseCodeGenerator, 0 } }, - { "releaseLock"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, writableStreamDefaultWriterReleaseLockCodeGenerator, 0 } }, - { "write"_s, static_cast(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, writableStreamDefaultWriterWriteCodeGenerator, 0 } }, -}; - -const ClassInfo JSWritableStreamDefaultWriterPrototype::s_info = { "WritableStreamDefaultWriter"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterPrototype) }; - -void JSWritableStreamDefaultWriterPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSWritableStreamDefaultWriter::info(), JSWritableStreamDefaultWriterPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSWritableStreamDefaultWriter::s_info = { "WritableStreamDefaultWriter"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamDefaultWriter) }; - -JSWritableStreamDefaultWriter::JSWritableStreamDefaultWriter(Structure* structure, JSDOMGlobalObject& globalObject) - : JSDOMObject(structure, globalObject) -{ -} - -void JSWritableStreamDefaultWriter::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -JSObject* JSWritableStreamDefaultWriter::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSWritableStreamDefaultWriterPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSWritableStreamDefaultWriterPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSWritableStreamDefaultWriter::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -JSValue JSWritableStreamDefaultWriter::getConstructor(VM& vm, const JSGlobalObject* globalObject) -{ - return getDOMConstructor(vm, *jsCast(globalObject)); -} - -void JSWritableStreamDefaultWriter::destroy(JSC::JSCell* cell) -{ - JSWritableStreamDefaultWriter* thisObject = static_cast(cell); - thisObject->JSWritableStreamDefaultWriter::~JSWritableStreamDefaultWriter(); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - auto* prototype = jsDynamicCast(JSValue::decode(thisValue)); - if (UNLIKELY(!prototype)) - return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(JSWritableStreamDefaultWriter::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject())); -} - -JSC::GCClient::IsoSubspace* JSWritableStreamDefaultWriter::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForWritableStreamDefaultWriter.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStreamDefaultWriter = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForWritableStreamDefaultWriter.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStreamDefaultWriter = std::forward(space); }); -} -} diff --git a/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.h b/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.h deleted file mode 100644 index 3434df33a2e0bf..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" - -namespace WebCore { - -class JSWritableStreamDefaultWriter : public JSDOMObject { -public: - using Base = JSDOMObject; - static JSWritableStreamDefaultWriter* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSWritableStreamDefaultWriter* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSWritableStreamDefaultWriter(structure, *globalObject); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - -protected: - JSWritableStreamDefaultWriter(JSC::Structure*, JSDOMGlobalObject&); - - void finishCreation(JSC::VM&); -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSWritableStreamSink.cpp b/src/bun.js/bindings/webcore/JSWritableStreamSink.cpp deleted file mode 100644 index 49c779a9ced54b..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamSink.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "JSWritableStreamSink.h" - -#include "ActiveDOMObject.h" -#include "DOMPromiseProxy.h" -#include "ExtendedDOMClientIsoSubspaces.h" -#include "ExtendedDOMIsoSubspaces.h" -#include "IDLTypes.h" -#include "JSDOMBinding.h" -#include "JSDOMConvertAny.h" -#include "JSDOMConvertBase.h" -#include "JSDOMConvertPromise.h" -#include "JSDOMConvertStrings.h" -#include "JSDOMExceptionHandling.h" -#include "JSDOMGlobalObject.h" -#include "JSDOMOperation.h" -#include "JSDOMOperationReturningPromise.h" -#include "JSDOMWrapperCache.h" -#include "ScriptExecutionContext.h" -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebCore { -using namespace JSC; - -// Functions - -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_write); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_close); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_error); - -class JSWritableStreamSinkPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - static JSWritableStreamSinkPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) - { - JSWritableStreamSinkPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamSinkPrototype(vm, globalObject, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamSinkPrototype, Base); - 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: - JSWritableStreamSinkPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) - : JSC::JSNonFinalObject(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamSinkPrototype, JSWritableStreamSinkPrototype::Base); - -/* Hash table for prototype */ - -static const HashTableValue JSWritableStreamSinkPrototypeTableValues[] = { - { "write"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamSinkPrototypeFunction_write, 1 } }, - { "close"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamSinkPrototypeFunction_close, 0 } }, - { "error"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsWritableStreamSinkPrototypeFunction_error, 1 } }, -}; - -const ClassInfo JSWritableStreamSinkPrototype::s_info = { "WritableStreamSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamSinkPrototype) }; - -void JSWritableStreamSinkPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, JSWritableStreamSink::info(), JSWritableStreamSinkPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -const ClassInfo JSWritableStreamSink::s_info = { "WritableStreamSink"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWritableStreamSink) }; - -JSWritableStreamSink::JSWritableStreamSink(Structure* structure, JSDOMGlobalObject& globalObject, Ref&& impl) - : JSDOMWrapper(structure, globalObject, WTFMove(impl)) -{ -} - -void JSWritableStreamSink::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - // static_assert(!std::is_base_of::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); -} - -JSObject* JSWritableStreamSink::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - auto* structure = JSWritableStreamSinkPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()); - structure->setMayBePrototype(true); - return JSWritableStreamSinkPrototype::create(vm, &globalObject, structure); -} - -JSObject* JSWritableStreamSink::prototype(VM& vm, JSDOMGlobalObject& globalObject) -{ - return getDOMPrototype(vm, globalObject); -} - -void JSWritableStreamSink::destroy(JSC::JSCell* cell) -{ - JSWritableStreamSink* thisObject = static_cast(cell); - thisObject->JSWritableStreamSink::~JSWritableStreamSink(); -} - -static inline JSC::EncodedJSValue jsWritableStreamSinkPrototypeFunction_writeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperationReturningPromise::ClassParameter castedThis, Ref&& promise) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - if (UNLIKELY(callFrame->argumentCount() < 1)) - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - auto* context = jsCast(lexicalGlobalObject)->scriptExecutionContext(); - if (UNLIKELY(!context)) - return JSValue::encode(jsUndefined()); - EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto value = convert(*lexicalGlobalObject, argument0.value()); - RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, [&]() -> decltype(auto) { return impl.write(*context, WTFMove(value), WTFMove(promise)); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_write, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperationReturningPromise::call(*lexicalGlobalObject, *callFrame, "write"); -} - -static inline JSC::EncodedJSValue jsWritableStreamSinkPrototypeFunction_closeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.close(); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_close, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "close"); -} - -static inline JSC::EncodedJSValue jsWritableStreamSinkPrototypeFunction_errorBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation::ClassParameter castedThis) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); - auto& impl = castedThis->wrapped(); - if (UNLIKELY(callFrame->argumentCount() < 1)) - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); - EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto message = convert(*lexicalGlobalObject, argument0.value()); - RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.error(WTFMove(message)); }))); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamSinkPrototypeFunction_error, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - return IDLOperation::call(*lexicalGlobalObject, *callFrame, "error"); -} - -JSC::GCClient::IsoSubspace* JSWritableStreamSink::subspaceForImpl(JSC::VM& vm) -{ - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForWritableStreamSink.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForWritableStreamSink = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForWritableStreamSink.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForWritableStreamSink = std::forward(space); }); -} - -void JSWritableStreamSink::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) -{ - auto* thisObject = jsCast(cell); - analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped()); - if (thisObject->scriptExecutionContext()) - analyzer.setLabelForCell(cell, makeString("url "_s, thisObject->scriptExecutionContext()->url().string())); - Base::analyzeHeap(cell, analyzer); -} - -bool JSWritableStreamSinkOwner::isReachableFromOpaqueRoots(JSC::Handle handle, void*, AbstractSlotVisitor& visitor, ASCIILiteral* reason) -{ - UNUSED_PARAM(handle); - UNUSED_PARAM(visitor); - UNUSED_PARAM(reason); - return false; -} - -void JSWritableStreamSinkOwner::finalize(JSC::Handle handle, void* context) -{ - auto* jsWritableStreamSink = static_cast(handle.slot()->asCell()); - auto& world = *static_cast(context); - uncacheWrapper(world, &jsWritableStreamSink->wrapped(), jsWritableStreamSink); -} - -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref&& impl) -{ - return createWrapper(globalObject, WTFMove(impl)); -} - -JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, WritableStreamSink& impl) -{ - return wrap(lexicalGlobalObject, globalObject, impl); -} - -WritableStreamSink* JSWritableStreamSink::toWrapped(JSC::VM&, JSC::JSValue value) -{ - if (auto* wrapper = jsDynamicCast(value)) - return &wrapper->wrapped(); - return nullptr; -} - -} diff --git a/src/bun.js/bindings/webcore/JSWritableStreamSink.h b/src/bun.js/bindings/webcore/JSWritableStreamSink.h deleted file mode 100644 index a6cac9d2372678..00000000000000 --- a/src/bun.js/bindings/webcore/JSWritableStreamSink.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of the WebKit open source project. - This file has been generated by generate-bindings.pl. DO NOT MODIFY! - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#pragma once - -#include "JSDOMWrapper.h" -#include "WritableStreamSink.h" -#include - -namespace WebCore { - -class JSWritableStreamSink : public JSDOMWrapper { -public: - using Base = JSDOMWrapper; - static JSWritableStreamSink* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref&& impl) - { - JSWritableStreamSink* ptr = new (NotNull, JSC::allocateCell(globalObject->vm())) JSWritableStreamSink(structure, *globalObject, WTFMove(impl)); - ptr->finishCreation(globalObject->vm()); - return ptr; - } - - static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); - static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); - static WritableStreamSink* toWrapped(JSC::VM&, JSC::JSValue); - static void destroy(JSC::JSCell*); - - DECLARE_INFO; - - 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(), JSC::NonArray); - } - - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return subspaceForImpl(vm); - } - static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); - static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - -protected: - JSWritableStreamSink(JSC::Structure*, JSDOMGlobalObject&, Ref&&); - - void finishCreation(JSC::VM&); -}; - -class JSWritableStreamSinkOwner final : public JSC::WeakHandleOwner { -public: - bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::AbstractSlotVisitor&, ASCIILiteral*) final; - void finalize(JSC::Handle, void* context) final; -}; - -inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, WritableStreamSink*) -{ - static NeverDestroyed owner; - return &owner.get(); -} - -inline void* wrapperKey(WritableStreamSink* wrappableObject) -{ - return wrappableObject; -} - -JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, WritableStreamSink&); -inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, WritableStreamSink* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); } -JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref&&); -inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); } - -template<> struct JSDOMWrapperConverterTraits { - using WrapperClass = JSWritableStreamSink; - using ToWrappedReturnType = WritableStreamSink*; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStream.cpp b/src/bun.js/bindings/webcore/ReadableStream.cpp deleted file mode 100644 index 36828aaf156f4c..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStream.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2017-2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CANON INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ReadableStream.h" - -#include "Exception.h" -#include "ExceptionCode.h" -#include "JSDOMConvertSequences.h" -#include "JSReadableStreamSink.h" -#include "JSReadableStreamSource.h" -#include "WebCoreJSClientData.h" - -namespace WebCore { -using namespace JSC; - -static inline ExceptionOr invokeConstructor(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier, const Function& buildArguments) -{ - VM& vm = lexicalGlobalObject.vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - auto& globalObject = *JSC::jsCast(&lexicalGlobalObject); - - auto constructorValue = globalObject.get(&lexicalGlobalObject, identifier); - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError }); - auto constructor = JSC::asObject(constructorValue); - - auto constructData = JSC::getConstructData(constructor); - ASSERT(constructData.type != CallData::Type::None); - - MarkedArgumentBuffer args; - buildArguments(args, lexicalGlobalObject, globalObject); - ASSERT(!args.hasOverflowed()); - - JSObject* object = JSC::construct(&lexicalGlobalObject, constructor, constructData, args); - ASSERT(!!scope.exception() == !object); - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError }); - - return object; -} - -ExceptionOr> ReadableStream::create(JSC::JSGlobalObject& lexicalGlobalObject, RefPtr&& source) -{ - auto& builtinNames = WebCore::builtinNames(lexicalGlobalObject.vm()); - - auto objectOrException = invokeConstructor(lexicalGlobalObject, builtinNames.ReadableStreamPrivateName(), [&source](auto& args, auto& lexicalGlobalObject, auto& globalObject) { - args.append(source ? toJSNewlyCreated(&lexicalGlobalObject, &globalObject, source.releaseNonNull()) : JSC::jsUndefined()); - }); - - if (objectOrException.hasException()) - return objectOrException.releaseException(); - - return create(*JSC::jsCast(&lexicalGlobalObject), *jsCast(objectOrException.releaseReturnValue())); -} - -ExceptionOr> ReadableStream::create(JSC::JSGlobalObject& lexicalGlobalObject, RefPtr&& source, JSC::JSValue nativePtr) -{ - auto& builtinNames = WebCore::builtinNames(lexicalGlobalObject.vm()); - RELEASE_ASSERT(source != nullptr); - - auto objectOrException = invokeConstructor(lexicalGlobalObject, builtinNames.ReadableStreamPrivateName(), [&source, nativePtr](auto& args, auto& lexicalGlobalObject, auto& globalObject) { - auto sourceStream = toJSNewlyCreated(&lexicalGlobalObject, &globalObject, source.releaseNonNull()); - auto tag = WebCore::clientData(lexicalGlobalObject.vm())->builtinNames().bunNativePtrPrivateName(); - sourceStream.getObject()->putDirect(lexicalGlobalObject.vm(), tag, nativePtr, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum); - args.append(sourceStream); - }); - - if (objectOrException.hasException()) - return objectOrException.releaseException(); - - return create(*JSC::jsCast(&lexicalGlobalObject), *jsCast(objectOrException.releaseReturnValue())); -} - -static inline std::optional invokeReadableStreamFunction(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier, JSC::JSValue thisValue, const JSC::MarkedArgumentBuffer& arguments) -{ - JSC::VM& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - - auto function = lexicalGlobalObject.get(&lexicalGlobalObject, identifier); - ASSERT(function.isCallable()); - - auto scope = DECLARE_CATCH_SCOPE(vm); - auto callData = JSC::getCallData(function); - auto result = call(&lexicalGlobalObject, function, callData, thisValue, arguments); - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - if (scope.exception()) - return {}; - return result; -} - -void ReadableStream::pipeTo(ReadableStreamSink& sink) -{ - auto& lexicalGlobalObject = *m_globalObject; - auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamPipeToPrivateName(); - - MarkedArgumentBuffer arguments; - arguments.append(readableStream()); - arguments.append(toJS(&lexicalGlobalObject, m_globalObject.get(), sink)); - ASSERT(!arguments.hasOverflowed()); - invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments); -} - -std::optional, Ref>> ReadableStream::tee() -{ - auto& lexicalGlobalObject = *m_globalObject; - auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamTeePrivateName(); - - MarkedArgumentBuffer arguments; - arguments.append(readableStream()); - arguments.append(JSC::jsBoolean(true)); - ASSERT(!arguments.hasOverflowed()); - auto returnedValue = invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments); - if (!returnedValue) - return {}; - - auto results = Detail::SequenceConverter>::convert(lexicalGlobalObject, *returnedValue); - - ASSERT(results.size() == 2); - return std::make_pair(results[0].releaseNonNull(), results[1].releaseNonNull()); -} - -void ReadableStream::lock() -{ - auto& builtinNames = WebCore::builtinNames(m_globalObject->vm()); - invokeConstructor(*m_globalObject, builtinNames.ReadableStreamDefaultReaderPrivateName(), [this](auto& args, auto&, auto&) { - args.append(readableStream()); - }); -} - -void ReadableStream::cancel(const Exception& exception) -{ - auto& lexicalGlobalObject = *m_globalObject; - auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamCancelPrivateName(); - - auto& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto value = createDOMException(&lexicalGlobalObject, exception.code(), exception.message()); - if (UNLIKELY(scope.exception())) { - ASSERT(vm.hasPendingTerminationException()); - return; - } - - MarkedArgumentBuffer arguments; - arguments.append(readableStream()); - arguments.append(value); - ASSERT(!arguments.hasOverflowed()); - invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments); -} - -void ReadableStream::cancel(WebCore::JSDOMGlobalObject& globalObject, JSReadableStream* readableStream, const Exception& exception) -{ - auto* clientData = static_cast(globalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamCancelPrivateName(); - - auto& vm = globalObject.vm(); - JSC::JSLockHolder lock(vm); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto value = createDOMException(&globalObject, exception.code(), exception.message()); - if (UNLIKELY(scope.exception())) { - ASSERT(vm.hasPendingTerminationException()); - return; - } - - MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(value); - ASSERT(!arguments.hasOverflowed()); - invokeReadableStreamFunction(globalObject, privateName, JSC::jsUndefined(), arguments); -} - -static inline bool checkReadableStream(JSDOMGlobalObject& globalObject, JSReadableStream* readableStream, JSC::JSValue function) -{ - auto& lexicalGlobalObject = globalObject; - - ASSERT(function); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - ASSERT(!arguments.hasOverflowed()); - - auto& vm = lexicalGlobalObject.vm(); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto callData = JSC::getCallData(function); - ASSERT(callData.type != JSC::CallData::Type::None); - - auto result = call(&lexicalGlobalObject, function, callData, JSC::jsUndefined(), arguments); - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - - return result.isTrue() || scope.exception(); -} - -bool ReadableStream::isLocked() const -{ - auto clientData = WebCore::clientData(m_globalObject->vm()); - auto& privateName = clientData->builtinNames().readerPrivateName(); - return readableStream()->getDirect(m_globalObject->vm(), privateName).isTrue(); -} - -bool ReadableStream::isLocked(JSGlobalObject* globalObject, JSReadableStream* readableStream) -{ - auto clientData = WebCore::clientData(globalObject->vm()); - auto& privateName = clientData->builtinNames().readerPrivateName(); - return readableStream->getDirect(globalObject->vm(), privateName).isTrue(); -} - -bool ReadableStream::isDisturbed(JSGlobalObject* globalObject, JSReadableStream* readableStream) -{ - return readableStream->disturbed(); -} - -bool ReadableStream::isDisturbed() const -{ - return readableStream()->disturbed(); -} - -JSC_DEFINE_HOST_FUNCTION(jsFunctionTransferToNativeReadableStream, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) -{ - auto& vm = lexicalGlobalObject->vm(); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - auto* readableStream = jsDynamicCast(callFrame->argument(0)); - readableStream->setTransferred(); - readableStream->setDisturbed(true); - return JSValue::encode(jsUndefined()); -} - -} diff --git a/src/bun.js/bindings/webcore/ReadableStream.h b/src/bun.js/bindings/webcore/ReadableStream.h deleted file mode 100644 index 3bd9463918a3dc..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStream.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2017-2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CANON INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "ExceptionOr.h" -#include "JSDOMBinding.h" -#include "JSDOMConvert.h" -#include "JSDOMGuardedObject.h" -#include "JSReadableStream.h" - -namespace WebCore { - -class ReadableStreamSink; -class ReadableStreamSource; - -class ReadableStream final : public DOMGuarded { -public: - static Ref create(JSDOMGlobalObject& globalObject, JSReadableStream& readableStream) { return adoptRef(*new ReadableStream(globalObject, readableStream)); } - - static ExceptionOr> create(JSC::JSGlobalObject&, RefPtr&&); - static ExceptionOr> create(JSC::JSGlobalObject& lexicalGlobalObject, RefPtr&& source, JSC::JSValue nativePtr); - - WEBCORE_EXPORT static bool isDisturbed(JSC::JSGlobalObject*, JSReadableStream*); - WEBCORE_EXPORT static bool isLocked(JSC::JSGlobalObject*, JSReadableStream*); - WEBCORE_EXPORT static void cancel(WebCore::JSDOMGlobalObject& globalObject, JSReadableStream*, const WebCore::Exception& exception); - - std::optional, Ref>> tee(); - - void cancel(const Exception&); - void lock(); - void pipeTo(ReadableStreamSink&); - bool isLocked() const; - bool isDisturbed() const; - - JSReadableStream* readableStream() const - { - return guarded(); - } - - ReadableStream(JSDOMGlobalObject& globalObject, JSReadableStream& readableStream) - : DOMGuarded(globalObject, readableStream) - { - } -}; - -struct JSReadableStreamWrapperConverter { - static RefPtr toWrapped(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) - { - auto* globalObject = JSC::jsDynamicCast(&lexicalGlobalObject); - if (!globalObject) - return nullptr; - - auto* readableStream = JSC::jsDynamicCast(value); - if (!readableStream) - return nullptr; - - return ReadableStream::create(*globalObject, *readableStream); - } -}; - -template<> struct JSDOMWrapperConverterTraits { - using WrapperClass = JSReadableStreamWrapperConverter; - using ToWrappedReturnType = RefPtr; - static constexpr bool needsState = true; -}; - -inline JSC::JSValue toJS(JSC::JSGlobalObject*, JSC::JSGlobalObject*, ReadableStream* stream) -{ - return stream ? stream->readableStream() : JSC::jsUndefined(); -} - -inline JSC::JSValue toJS(JSC::JSGlobalObject*, JSC::JSGlobalObject*, ReadableStream& stream) -{ - return stream.readableStream(); -} - -inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref&& stream) -{ - return stream->readableStream(); -} - -JSC_DECLARE_HOST_FUNCTION(jsFunctionTransferToNativeReadableStream); - -} diff --git a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp b/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp deleted file mode 100644 index c601884eae2d78..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * Copyright (C) 2016-2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions - * are required to be met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Canon Inc. nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ReadableStreamDefaultController.h" - -#include "WebCoreJSClientData.h" -#include -#include -#include -#include -#include - -namespace WebCore { - -static bool invokeReadableStreamDefaultControllerFunction(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier, const JSC::MarkedArgumentBuffer& arguments) -{ - JSC::VM& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - - auto scope = DECLARE_CATCH_SCOPE(vm); - auto function = lexicalGlobalObject.get(&lexicalGlobalObject, identifier); - - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - RETURN_IF_EXCEPTION(scope, false); - - ASSERT(function.isCallable()); - - auto callData = JSC::getCallData(function); - call(&lexicalGlobalObject, function, callData, JSC::jsUndefined(), arguments); - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - return !scope.exception(); -} - -void ReadableStreamDefaultController::close() -{ - JSC::MarkedArgumentBuffer arguments; - arguments.append(&jsController()); - - auto* clientData = static_cast(globalObject().vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamDefaultControllerClosePrivateName(); - - invokeReadableStreamDefaultControllerFunction(globalObject(), privateName, arguments); -} - -void ReadableStreamDefaultController::error(const Exception& exception) -{ - JSC::JSGlobalObject& lexicalGlobalObject = this->globalObject(); - auto& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto value = createDOMException(&lexicalGlobalObject, exception.code(), exception.message()); - - if (UNLIKELY(scope.exception())) { - ASSERT(vm.hasPendingTerminationException()); - return; - } - - JSC::MarkedArgumentBuffer arguments; - arguments.append(&jsController()); - arguments.append(value); - - auto* clientData = static_cast(vm.clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamDefaultControllerErrorPrivateName(); - - invokeReadableStreamDefaultControllerFunction(globalObject(), privateName, arguments); -} - -void ReadableStreamDefaultController::error(JSC::JSValue error) -{ - JSC::JSGlobalObject& lexicalGlobalObject = this->globalObject(); - auto& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - auto scope = DECLARE_THROW_SCOPE(vm); - auto value = JSC::Exception::create(vm, error); - - if (UNLIKELY(scope.exception())) { - ASSERT(vm.hasPendingTerminationException()); - return; - } - - JSC::MarkedArgumentBuffer arguments; - arguments.append(&jsController()); - arguments.append(value); - - auto* clientData = static_cast(vm.clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamDefaultControllerErrorPrivateName(); - - invokeReadableStreamDefaultControllerFunction(globalObject(), privateName, arguments); -} - -bool ReadableStreamDefaultController::enqueue(JSC::JSValue value) -{ - JSC::JSGlobalObject& lexicalGlobalObject = this->globalObject(); - auto& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - - JSC::MarkedArgumentBuffer arguments; - arguments.append(&jsController()); - arguments.append(value); - - auto* clientData = static_cast(lexicalGlobalObject.vm().clientData); - auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamDefaultControllerEnqueuePrivateName(); - - return invokeReadableStreamDefaultControllerFunction(globalObject(), privateName, arguments); -} - -bool ReadableStreamDefaultController::enqueue(RefPtr&& buffer) -{ - if (!buffer) { - error(Exception { OutOfMemoryError }); - return false; - } - - JSC::JSGlobalObject& lexicalGlobalObject = this->globalObject(); - auto& vm = lexicalGlobalObject.vm(); - JSC::JSLockHolder lock(vm); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto length = buffer->byteLength(); - auto value = JSC::JSUint8Array::create(&lexicalGlobalObject, lexicalGlobalObject.typedArrayStructure(JSC::TypeUint8, true), WTFMove(buffer), 0, length); - - EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); - RETURN_IF_EXCEPTION(scope, false); - - return enqueue(value); -} - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.h b/src/bun.js/bindings/webcore/ReadableStreamDefaultController.h deleted file mode 100644 index bb3bc9409ac4d6..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * Copyright (C) 2017 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions - * are required to be met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Canon Inc. nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "JSDOMConvertBufferSource.h" -#include "JSReadableStreamDefaultController.h" -#include -#include -#include - -namespace WebCore { - -class ReadableStreamSource; - -class ReadableStreamDefaultController { -public: - explicit ReadableStreamDefaultController(JSReadableStreamDefaultController* controller) - : m_jsController(controller) - { - } - - bool enqueue(RefPtr&&); - bool enqueue(JSC::JSValue); - void error(const Exception&); - void error(JSC::JSValue error); - void close(); - JSDOMGlobalObject& globalObject() const; - JSReadableStreamDefaultController& jsController() const; - // The owner of ReadableStreamDefaultController is responsible to keep uncollected the JSReadableStreamDefaultController. - JSReadableStreamDefaultController* m_jsController { nullptr }; - -private: -}; - -inline JSReadableStreamDefaultController& ReadableStreamDefaultController::jsController() const -{ - ASSERT(m_jsController); - return *m_jsController; -} - -inline JSDOMGlobalObject& ReadableStreamDefaultController::globalObject() const -{ - ASSERT(m_jsController); - ASSERT(m_jsController->globalObject()); - return *static_cast(m_jsController->globalObject()); -} - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStreamSink.cpp b/src/bun.js/bindings/webcore/ReadableStreamSink.cpp deleted file mode 100644 index d79e7d3581c1ce..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamSink.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ReadableStreamSink.h" - -#include "BufferSource.h" -#include "DOMException.h" -#include "ReadableStream.h" - -namespace WebCore { - -ReadableStreamToSharedBufferSink::ReadableStreamToSharedBufferSink(Callback&& callback) - : m_callback { WTFMove(callback) } -{ -} - -void ReadableStreamToSharedBufferSink::pipeFrom(ReadableStream& stream) -{ - stream.pipeTo(*this); -} - -void ReadableStreamToSharedBufferSink::enqueue(const BufferSource& buffer) -{ - if (!buffer.length()) - return; - - if (m_callback) { - std::span chunk { buffer.data(), buffer.length() }; - m_callback(&chunk); - } -} - -void ReadableStreamToSharedBufferSink::close() -{ - if (m_callback) - m_callback(nullptr); -} - -void ReadableStreamToSharedBufferSink::error(String&& message) -{ - if (auto callback = WTFMove(m_callback)) - callback(Exception { TypeError, WTFMove(message) }); -} - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStreamSink.h b/src/bun.js/bindings/webcore/ReadableStreamSink.h deleted file mode 100644 index 7db31e38abd425..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamSink.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2017 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "ExceptionOr.h" -#include -#include -#include - -namespace WebCore { - -class BufferSource; -class ReadableStream; - -class ReadableStreamSink : public RefCounted { -public: - virtual ~ReadableStreamSink() = default; - - virtual void enqueue(const BufferSource&) = 0; - virtual void close() = 0; - virtual void error(String&&) = 0; -}; - -class ReadableStreamToSharedBufferSink final : public ReadableStreamSink { -public: - using Callback = Function*>&&)>; - static Ref create(Callback&& callback) { return adoptRef(*new ReadableStreamToSharedBufferSink(WTFMove(callback))); } - void pipeFrom(ReadableStream&); - void clearCallback() { m_callback = {}; } - -private: - explicit ReadableStreamToSharedBufferSink(Callback&&); - - void enqueue(const BufferSource&) final; - void close() final; - void error(String&&) final; - - Callback m_callback; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStreamSource.cpp b/src/bun.js/bindings/webcore/ReadableStreamSource.cpp deleted file mode 100644 index e0537b418872b7..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamSource.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2017 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ReadableStreamSource.h" -namespace WebCore { - -ReadableStreamSource::~ReadableStreamSource() = default; - -void ReadableStreamSource::start(ReadableStreamDefaultController&& controller, DOMPromiseDeferred&& promise) -{ - ASSERT(!m_promise); - m_promise = makeUnique>(WTFMove(promise)); - m_controller = WTFMove(controller); - - setActive(); - doStart(); -} - -void ReadableStreamSource::pull(DOMPromiseDeferred&& promise) -{ - ASSERT(!m_promise); - ASSERT(m_controller); - - m_promise = makeUnique>(WTFMove(promise)); - - setActive(); - doPull(); -} - -void ReadableStreamSource::startFinished() -{ - ASSERT(m_promise); - m_promise->resolve(); - m_promise = nullptr; - setInactive(); -} - -void ReadableStreamSource::pullFinished() -{ - ASSERT(m_promise); - m_promise->resolve(); - m_promise = nullptr; - setInactive(); -} - -void ReadableStreamSource::cancel(JSC::JSValue) -{ - clean(); - doCancel(); -} - -void ReadableStreamSource::clean() -{ - if (m_promise) { - m_promise = nullptr; - setInactive(); - } -} - -void ReadableStreamSource::error(JSC::JSValue value) -{ - if (m_promise) { - m_promise->reject(value, RejectAsHandled::Yes); - m_promise = nullptr; - setInactive(); - } else { - controller().error(value); - } -} - -void SimpleReadableStreamSource::doCancel() -{ - m_isCancelled = true; -} - -void SimpleReadableStreamSource::close() -{ - if (!m_isCancelled) - controller().close(); -} - -void SimpleReadableStreamSource::enqueue(JSC::JSValue value) -{ - if (!m_isCancelled) - controller().enqueue(value); -} - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/ReadableStreamSource.h b/src/bun.js/bindings/webcore/ReadableStreamSource.h deleted file mode 100644 index 0886ab4234e016..00000000000000 --- a/src/bun.js/bindings/webcore/ReadableStreamSource.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions - * are required to be met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Canon Inc. nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "JSDOMPromiseDeferred.h" -#include "ReadableStreamDefaultController.h" -#include - -namespace WebCore { - -class ReadableStreamSource : public RefCounted { -public: - virtual ~ReadableStreamSource(); - - void start(ReadableStreamDefaultController&&, DOMPromiseDeferred&&); - void pull(DOMPromiseDeferred&&); - void cancel(JSC::JSValue); - void error(JSC::JSValue error); - - bool hasController() const { return !!m_controller; } - - bool isPulling() const { return !!m_promise; } - -protected: - ReadableStreamDefaultController& controller() { return m_controller.value(); } - const ReadableStreamDefaultController& controller() const { return m_controller.value(); } - - void startFinished(); - void pullFinished(); - void cancelFinished(); - void clean(); - - virtual void setActive() = 0; - virtual void setInactive() = 0; - - virtual void doStart() = 0; - virtual void doPull() = 0; - virtual void doCancel() = 0; - - std::unique_ptr> m_promise; - -private: - std::optional m_controller; -}; - -class SimpleReadableStreamSource - : public ReadableStreamSource, - public CanMakeWeakPtr { -public: - static Ref create() { return adoptRef(*new SimpleReadableStreamSource); } - - void close(); - void enqueue(JSC::JSValue); - -private: - SimpleReadableStreamSource() = default; - - // ReadableStreamSource - void setActive() final {} - void setInactive() final {} - void doStart() final {} - void doPull() final {} - void doCancel() final; - - bool m_isCancelled { false }; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/StructuredClone.cpp b/src/bun.js/bindings/webcore/StructuredClone.cpp index f0f8691bd23ba3..65c79ca3126d21 100644 --- a/src/bun.js/bindings/webcore/StructuredClone.cpp +++ b/src/bun.js/bindings/webcore/StructuredClone.cpp @@ -34,55 +34,42 @@ namespace WebCore { using namespace JSC; -enum class CloneMode { - Full, - Partial, -}; - -static JSC::EncodedJSValue cloneArrayBufferImpl(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame, CloneMode mode) +JSC::JSValue cloneArrayBuffer(JSGlobalObject* lexicalGlobalObject, const JSC::ArgList& args, CloneMode mode) { VM& vm = lexicalGlobalObject->vm(); ASSERT(lexicalGlobalObject); - ASSERT(callFrame->argumentCount()); - ASSERT(callFrame->lexicalGlobalObject(vm) == lexicalGlobalObject); + ASSERT(args.size()); - auto* buffer = toUnsharedArrayBuffer(vm, callFrame->uncheckedArgument(0)); + auto* buffer = toUnsharedArrayBuffer(vm, args.at(0)); if (!buffer) { auto scope = DECLARE_THROW_SCOPE(vm); throwDataCloneError(*lexicalGlobalObject, scope); return {}; } if (mode == CloneMode::Partial) { - ASSERT(callFrame->argumentCount() == 3); - int srcByteOffset = static_cast(callFrame->uncheckedArgument(1).toNumber(lexicalGlobalObject)); - int srcLength = static_cast(callFrame->uncheckedArgument(2).toNumber(lexicalGlobalObject)); - return JSValue::encode(JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), buffer->slice(srcByteOffset, srcByteOffset + srcLength))); + ASSERT(args.size() == 3); + int srcByteOffset = static_cast(args.at(1).toNumber(lexicalGlobalObject)); + int srcLength = static_cast(args.at(2).toNumber(lexicalGlobalObject)); + return JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), buffer->slice(srcByteOffset, srcByteOffset + srcLength)); } - return JSValue::encode(JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), buffer->slice(0))); -} - -JSC_DEFINE_HOST_FUNCTION(cloneArrayBuffer, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - return cloneArrayBufferImpl(globalObject, callFrame, CloneMode::Partial); + return JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), buffer->slice(0)); } -JSC_DEFINE_HOST_FUNCTION(structuredCloneForStream, (JSGlobalObject * globalObject, CallFrame* callFrame)) +JSC::JSValue structuredCloneForStream(JSGlobalObject* globalObject, const JSC::ArgList& args) { - ASSERT(callFrame); - ASSERT(callFrame->argumentCount()); VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); - JSValue value = callFrame->uncheckedArgument(0); + JSValue value = args.at(0); if (value.isPrimitive()) { - return JSValue::encode(value); + return value; } if (value.inherits()) - RELEASE_AND_RETURN(scope, cloneArrayBufferImpl(globalObject, callFrame, CloneMode::Full)); + return cloneArrayBuffer(globalObject, args, CloneMode::Full); if (value.inherits()) { auto* bufferView = jsCast(value); @@ -96,10 +83,10 @@ JSC_DEFINE_HOST_FUNCTION(structuredCloneForStream, (JSGlobalObject * globalObjec auto bufferClone = buffer->slice(0); Structure* structure = bufferView->structure(); -#define CLONE_TYPED_ARRAY(name) \ - do { \ - if (bufferView->inherits()) \ - RELEASE_AND_RETURN(scope, JSValue::encode(JS##name##Array::create(globalObject, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()))); \ +#define CLONE_TYPED_ARRAY(name) \ + do { \ + if (bufferView->inherits()) \ + return JS##name##Array::create(globalObject, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()); \ } while (0); FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CLONE_TYPED_ARRAY) @@ -107,11 +94,22 @@ JSC_DEFINE_HOST_FUNCTION(structuredCloneForStream, (JSGlobalObject * globalObjec #undef CLONE_TYPED_ARRAY if (value.inherits()) - RELEASE_AND_RETURN(scope, JSValue::encode(JSDataView::create(globalObject, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()))); + return JSDataView::create(globalObject, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()); } throwTypeError(globalObject, scope, "structuredClone not implemented for non-ArrayBuffer / non-ArrayBufferView"_s); return {}; } +JSC_DEFINE_HOST_FUNCTION(jsFunctionCloneArrayBuffer, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + return JSValue::encode(cloneArrayBuffer(globalObject, ArgList(callFrame), CloneMode::Partial)); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionStructuredCloneForStream, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + + return JSValue::encode(structuredCloneForStream(globalObject, ArgList(callFrame))); +} + } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/StructuredClone.h b/src/bun.js/bindings/webcore/StructuredClone.h index af14c0873872a8..73b18a4c6a4b42 100644 --- a/src/bun.js/bindings/webcore/StructuredClone.h +++ b/src/bun.js/bindings/webcore/StructuredClone.h @@ -30,11 +30,21 @@ namespace JSC { class CallFrame; class JSGlobalObject; using EncodedJSValue = int64_t; +class ArgList; +class JSValue; } namespace WebCore { -JSC_DECLARE_HOST_FUNCTION(cloneArrayBuffer); -JSC_DECLARE_HOST_FUNCTION(structuredCloneForStream); +enum class CloneMode { + Full, + Partial, +}; + +JSC::JSValue cloneArrayBuffer(JSC::JSGlobalObject* lexicalGlobalObject, const JSC::ArgList& args, CloneMode mode); +JSC::JSValue structuredCloneForStream(JSC::JSGlobalObject* lexicalGlobalObject, const JSC::ArgList& args); + +JSC_DECLARE_HOST_FUNCTION(jsFunctionCloneArrayBuffer); +JSC_DECLARE_HOST_FUNCTION(jsFunctionStructuredCloneForStream); } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/WritableStream.cpp b/src/bun.js/bindings/webcore/WritableStream.cpp deleted file mode 100644 index 97d56b47611f03..00000000000000 --- a/src/bun.js/bindings/webcore/WritableStream.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WritableStream.h" - -#include "JSWritableStream.h" -#include "JSWritableStreamSink.h" - -namespace WebCore { - -ExceptionOr> WritableStream::create(JSC::JSGlobalObject& globalObject, std::optional>&& underlyingSink, std::optional>&& strategy) -{ - JSC::JSValue underlyingSinkValue = JSC::jsUndefined(); - if (underlyingSink) - underlyingSinkValue = underlyingSink->get(); - - JSC::JSValue strategyValue = JSC::jsUndefined(); - if (strategy) - strategyValue = strategy->get(); - - return create(globalObject, underlyingSinkValue, strategyValue); -} - -ExceptionOr> WritableStream::create(JSC::JSGlobalObject& globalObject, JSC::JSValue underlyingSink, JSC::JSValue strategy) -{ - auto result = InternalWritableStream::createFromUnderlyingSink(*JSC::jsCast(&globalObject), underlyingSink, strategy); - if (result.hasException()) - return result.releaseException(); - - return adoptRef(*new WritableStream(result.releaseReturnValue())); -} - -ExceptionOr> WritableStream::create(JSDOMGlobalObject& globalObject, Ref&& sink) -{ - return create(globalObject, toJSNewlyCreated(&globalObject, &globalObject, WTFMove(sink)), JSC::jsUndefined()); -} - -Ref WritableStream::create(Ref&& internalWritableStream) -{ - return adoptRef(*new WritableStream(WTFMove(internalWritableStream))); -} - -WritableStream::WritableStream(Ref&& internalWritableStream) - : m_internalWritableStream(WTFMove(internalWritableStream)) -{ -} - -JSC::JSValue JSWritableStream::abort(JSC::JSGlobalObject& globalObject, JSC::CallFrame& callFrame) -{ - return wrapped().internalWritableStream().abort(globalObject, callFrame.argument(0)); -} - -JSC::JSValue JSWritableStream::close(JSC::JSGlobalObject& globalObject, JSC::CallFrame&) -{ - return wrapped().internalWritableStream().close(globalObject); -} - -JSC::JSValue JSWritableStream::getWriter(JSC::JSGlobalObject& globalObject, JSC::CallFrame&) -{ - return wrapped().internalWritableStream().getWriter(globalObject); -} - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/WritableStream.h b/src/bun.js/bindings/webcore/WritableStream.h deleted file mode 100644 index 63a4b33778c0f3..00000000000000 --- a/src/bun.js/bindings/webcore/WritableStream.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2021 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "root.h" - -#include "InternalWritableStream.h" -#include -#include - -namespace WebCore { - -class InternalWritableStream; -class WritableStreamSink; - -class WritableStream : public RefCounted { -public: - static ExceptionOr> create(JSC::JSGlobalObject&, std::optional>&&, std::optional>&&); - static ExceptionOr> create(JSDOMGlobalObject&, Ref&&); - static Ref create(Ref&&); - - ~WritableStream() = default; - - void lock() { m_internalWritableStream->lock(); } - bool locked() const { return m_internalWritableStream->locked(); } - - InternalWritableStream& internalWritableStream() { return m_internalWritableStream.get(); } - -private: - static ExceptionOr> create(JSC::JSGlobalObject&, JSC::JSValue, JSC::JSValue); - explicit WritableStream(Ref&&); - - Ref m_internalWritableStream; -}; - -} // namespace WebCore diff --git a/src/bun.js/bindings/webcore/WritableStream.idl b/src/bun.js/bindings/webcore/WritableStream.idl deleted file mode 100644 index cd32d17f0280b2..00000000000000 --- a/src/bun.js/bindings/webcore/WritableStream.idl +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia S.L. - * Copyright (C) 2020-2021 Apple Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions - * are required to be met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Canon Inc. nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - Exposed=*, - PrivateIdentifier, - PublicIdentifier, - SkipVTableValidation -] interface WritableStream { - // FIXME: Tighten parameter matching - [CallWith=CurrentGlobalObject] constructor(optional object underlyingSink, optional object strategy); - - readonly attribute boolean locked; - - [Custom, ReturnsOwnPromise] Promise abort(optional any reason); - [Custom, ReturnsOwnPromise] Promise close(); - [Custom] WritableStreamDefaultWriter getWriter(); -}; diff --git a/src/bun.js/bindings/webcore/WritableStreamSink.h b/src/bun.js/bindings/webcore/WritableStreamSink.h deleted file mode 100644 index b15e34d91eced8..00000000000000 --- a/src/bun.js/bindings/webcore/WritableStreamSink.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "JSDOMPromiseDeferred.h" -#include -#include - -namespace JSC { -class JSValue; -} - -namespace WebCore { - -class WritableStreamSink : public RefCounted { -public: - virtual ~WritableStreamSink() = default; - - virtual void write(ScriptExecutionContext&, JSC::JSValue, DOMPromiseDeferred&&) = 0; - virtual void close() = 0; - virtual void error(String&&) = 0; -}; - -class SimpleWritableStreamSink : public WritableStreamSink { -public: - using WriteCallback = Function(ScriptExecutionContext&, JSC::JSValue)>; - static Ref create(WriteCallback&& writeCallback) { return adoptRef(*new SimpleWritableStreamSink(WTFMove(writeCallback))); } - -private: - explicit SimpleWritableStreamSink(WriteCallback&&); - - void write(ScriptExecutionContext&, JSC::JSValue, DOMPromiseDeferred&&) final; - void close() final {} - void error(String&&) final {} - - WriteCallback m_writeCallback; -}; - -inline SimpleWritableStreamSink::SimpleWritableStreamSink(WriteCallback&& writeCallback) - : m_writeCallback(WTFMove(writeCallback)) -{ -} - -inline void SimpleWritableStreamSink::write(ScriptExecutionContext& context, JSC::JSValue value, DOMPromiseDeferred&& promise) -{ - promise.settle(m_writeCallback(context, value)); -} - -} // namespace WebCore diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 55926dde59b191..8cd7979cc234c1 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -34,7 +34,7 @@ #include #include #include - +#include "BunPromiseInlines.h" #include "BunProcess.h" #include #if ENABLE(REMOTE_INSPECTOR) @@ -706,7 +706,7 @@ JSC_DEFINE_HOST_FUNCTION(functionRunProfiler, (JSGlobalObject * globalObject, Ca JSNativeStdFunction* resolve = JSNativeStdFunction::create( vm, globalObject, 0, "resolve"_s, [report](JSGlobalObject* globalObject, CallFrame* callFrame) { - return JSValue::encode(JSPromise::resolvedPromise( + return JSValue::encode(Bun::createFulfilledPromise( globalObject, report(globalObject->vm(), globalObject))); }); JSNativeStdFunction* reject = JSNativeStdFunction::create( diff --git a/src/codegen/generate-jssink.ts b/src/codegen/generate-jssink.ts index 4271cd12122638..f94a002f19fc13 100644 --- a/src/codegen/generate-jssink.ts +++ b/src/codegen/generate-jssink.ts @@ -275,7 +275,7 @@ async function implementation() { // #include #include -#include "JSReadableStream.h" +#include "BunReadableStream.h" #include "BunClientData.h" #include #include diff --git a/src/js/builtins/BunBuiltinNames.h b/src/js/builtins/BunBuiltinNames.h index b3cb19b8164aba..b50ce8734e933b 100644 --- a/src/js/builtins/BunBuiltinNames.h +++ b/src/js/builtins/BunBuiltinNames.h @@ -21,9 +21,24 @@ namespace WebCore { using namespace JSC; #define BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \ + macro(AbortSignal) \ + macro(Buffer) \ + macro(Bun) \ + macro(Loader) \ + macro(ReadableByteStreamController) \ + macro(ReadableStream) \ + macro(ReadableStreamBYOBReader) \ + macro(ReadableStreamBYOBRequest) \ + macro(ReadableStreamDefaultController) \ + macro(ReadableStreamDefaultReader) \ + macro(TextEncoderStreamEncoder) \ + macro(TransformStream) \ + macro(TransformStreamDefaultController) \ + macro(WritableStream) \ + macro(WritableStreamDefaultController) \ + macro(WritableStreamDefaultWriter) \ macro(_events) \ macro(abortAlgorithm) \ - macro(AbortSignal) \ macro(abortSteps) \ macro(addAbortAlgorithmToSignal) \ macro(addEventListener) \ @@ -36,8 +51,6 @@ using namespace JSC; macro(backpressureChangePromise) \ macro(basename) \ macro(body) \ - macro(Buffer) \ - macro(Bun) \ macro(bunNativePtr) \ macro(bunNativeType) \ macro(byobRequest) \ @@ -47,11 +60,11 @@ using namespace JSC; macro(cloneArrayBuffer) \ macro(close) \ macro(closeAlgorithm) \ + macro(closeRequest) \ + macro(closeRequested) \ macro(closed) \ macro(closedPromise) \ macro(closedPromiseCapability) \ - macro(closeRequest) \ - macro(closeRequested) \ macro(code) \ macro(connect) \ macro(controlledReadableStream) \ @@ -129,7 +142,6 @@ using namespace JSC; macro(lazyStreamPrototypeMap) \ macro(lineText) \ macro(loadCJS2ESM) \ - macro(Loader) \ macro(localStreams) \ macro(main) \ macro(makeDOMException) \ @@ -138,6 +150,8 @@ using namespace JSC; macro(makeThisTypeError) \ macro(method) \ macro(mockedFunction) \ + macro(napiDlopenHandle) \ + macro(napiWrappedContents) \ macro(nextTick) \ macro(normalize) \ macro(on) \ @@ -173,18 +187,12 @@ using namespace JSC; macro(put) \ macro(queue) \ macro(read) \ + macro(readIntoRequests) \ + macro(readRequests) \ macro(readable) \ - macro(ReadableByteStreamController) \ - macro(ReadableStream) \ - macro(ReadableStreamBYOBReader) \ - macro(ReadableStreamBYOBRequest) \ macro(readableStreamController) \ - macro(ReadableStreamDefaultController) \ - macro(ReadableStreamDefaultReader) \ macro(readableStreamToArray) \ macro(reader) \ - macro(readIntoRequests) \ - macro(readRequests) \ macro(readyPromise) \ macro(readyPromiseCapability) \ macro(redirect) \ @@ -225,14 +233,12 @@ using namespace JSC; macro(textDecoderStreamDecoder) \ macro(textDecoderStreamTransform) \ macro(textEncoderStreamEncoder) \ - macro(TextEncoderStreamEncoder) \ macro(textEncoderStreamTransform) \ macro(toClass) \ macro(toNamespacedPath) \ macro(trace) \ + macro(transform) \ macro(transformAlgorithm) \ - macro(TransformStream) \ - macro(TransformStreamDefaultController) \ macro(uncork) \ macro(underlyingByteSource) \ macro(underlyingSink) \ @@ -245,17 +251,12 @@ using namespace JSC; macro(versions) \ macro(view) \ macro(writable) \ - macro(WritableStream) \ - macro(WritableStreamDefaultController) \ - macro(WritableStreamDefaultWriter) \ macro(write) \ macro(writeAlgorithm) \ - macro(writer) \ macro(writeRequests) \ + macro(writer) \ macro(writing) \ macro(written) \ - macro(napiDlopenHandle) \ - macro(napiWrappedContents) \ BUN_ADDITIONAL_BUILTIN_NAMES(macro) // --- END of BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME --- diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index 1c7f2a06708e96..42f02f97782062 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -119,8 +119,15 @@ export function getStdinStream(fd) { } const tty = require("node:tty"); - const ReadStream = tty.isatty(fd) ? tty.ReadStream : require("node:fs").ReadStream; - const stream = new ReadStream(fd); + // TODO: undo this. + // const ReadStream = tty.isatty(fd) ? tty.ReadStream : require("node:fs").ReadStream; + const nodeStream = require("node:stream"); + const ReadStream = nodeStream.Readable; + const stream = new ReadStream({ + _read() { + ref(); + }, + }); const originalOn = stream.on; diff --git a/src/js/builtins/ReadableByteStreamController.ts b/src/js/builtins/ReadableByteStreamController.ts deleted file mode 100644 index 888f241bca5c1a..00000000000000 --- a/src/js/builtins/ReadableByteStreamController.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableByteStreamController(this, stream, underlyingByteSource, highWaterMark) { - if (arguments.length !== 4 && arguments[3] !== $isReadableStream) - throw new TypeError("ReadableByteStreamController constructor should not be called directly"); - - return $privateInitializeReadableByteStreamController.$call(this, stream, underlyingByteSource, highWaterMark); -} - -export function enqueue(this, chunk) { - if (!$isReadableByteStreamController(this)) throw $makeThisTypeError("ReadableByteStreamController", "enqueue"); - - if ($getByIdDirectPrivate(this, "closeRequested")) - throw new TypeError("ReadableByteStreamController is requested to close"); - - if ($getByIdDirectPrivate($getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== $streamReadable) - throw new TypeError("ReadableStream is not readable"); - - if (!$isObject(chunk) || !ArrayBuffer.$isView(chunk)) throw new TypeError("Provided chunk is not a TypedArray"); - - return $readableByteStreamControllerEnqueue(this, chunk); -} - -export function error(this, error) { - if (!$isReadableByteStreamController(this)) throw $makeThisTypeError("ReadableByteStreamController", "error"); - - if ($getByIdDirectPrivate($getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== $streamReadable) - throw new TypeError("ReadableStream is not readable"); - - $readableByteStreamControllerError(this, error); -} - -export function close(this) { - if (!$isReadableByteStreamController(this)) throw $makeThisTypeError("ReadableByteStreamController", "close"); - - if ($getByIdDirectPrivate(this, "closeRequested")) throw new TypeError("Close has already been requested"); - - if ($getByIdDirectPrivate($getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== $streamReadable) - throw new TypeError("ReadableStream is not readable"); - - $readableByteStreamControllerClose(this); -} - -$getter; -export function byobRequest(this) { - if (!$isReadableByteStreamController(this)) throw $makeGetterTypeError("ReadableByteStreamController", "byobRequest"); - - var request = $getByIdDirectPrivate(this, "byobRequest"); - if (request === undefined) { - var pending = $getByIdDirectPrivate(this, "pendingPullIntos"); - const firstDescriptor = pending.peek(); - if (firstDescriptor) { - const view = new Uint8Array( - firstDescriptor.buffer, - firstDescriptor.byteOffset + firstDescriptor.bytesFilled, - firstDescriptor.byteLength - firstDescriptor.bytesFilled, - ); - $putByIdDirectPrivate(this, "byobRequest", new ReadableStreamBYOBRequest(this, view, $isReadableStream)); - } - } - - return $getByIdDirectPrivate(this, "byobRequest"); -} - -$getter; -export function desiredSize(this) { - if (!$isReadableByteStreamController(this)) throw $makeGetterTypeError("ReadableByteStreamController", "desiredSize"); - - return $readableByteStreamControllerGetDesiredSize(this); -} diff --git a/src/js/builtins/ReadableByteStreamInternals.ts b/src/js/builtins/ReadableByteStreamInternals.ts deleted file mode 100644 index 1a87c977ee1568..00000000000000 --- a/src/js/builtins/ReadableByteStreamInternals.ts +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -// @internal - -export function privateInitializeReadableByteStreamController(this, stream, underlyingByteSource, highWaterMark) { - if (!$isReadableStream(stream)) throw new TypeError("ReadableByteStreamController needs a ReadableStream"); - - // readableStreamController is initialized with null value. - if ($getByIdDirectPrivate(stream, "readableStreamController") !== null) - throw new TypeError("ReadableStream already has a controller"); - - $putByIdDirectPrivate(this, "controlledReadableStream", stream); - $putByIdDirectPrivate(this, "underlyingByteSource", underlyingByteSource); - $putByIdDirectPrivate(this, "pullAgain", false); - $putByIdDirectPrivate(this, "pulling", false); - $readableByteStreamControllerClearPendingPullIntos(this); - $putByIdDirectPrivate(this, "queue", $newQueue()); - $putByIdDirectPrivate(this, "started", 0); - $putByIdDirectPrivate(this, "closeRequested", false); - - let hwm = $toNumber(highWaterMark); - if (hwm !== hwm || hwm < 0) throw new RangeError("highWaterMark value is negative or not a number"); - $putByIdDirectPrivate(this, "strategyHWM", hwm); - - let autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; - if (autoAllocateChunkSize !== undefined) { - autoAllocateChunkSize = $toNumber(autoAllocateChunkSize); - if (autoAllocateChunkSize <= 0 || autoAllocateChunkSize === Infinity || autoAllocateChunkSize === -Infinity) - throw new RangeError("autoAllocateChunkSize value is negative or equal to positive or negative infinity"); - } - $putByIdDirectPrivate(this, "autoAllocateChunkSize", autoAllocateChunkSize); - $putByIdDirectPrivate(this, "pendingPullIntos", $createFIFO()); - - const controller = this; - $promiseInvokeOrNoopNoCatch($getByIdDirectPrivate(controller, "underlyingByteSource"), "start", [controller]).$then( - () => { - $putByIdDirectPrivate(controller, "started", 1); - $assert(!$getByIdDirectPrivate(controller, "pulling")); - $assert(!$getByIdDirectPrivate(controller, "pullAgain")); - $readableByteStreamControllerCallPullIfNeeded(controller); - }, - error => { - if ($getByIdDirectPrivate(stream, "state") === $streamReadable) - $readableByteStreamControllerError(controller, error); - }, - ); - - $putByIdDirectPrivate(this, "cancel", $readableByteStreamControllerCancel); - $putByIdDirectPrivate(this, "pull", $readableByteStreamControllerPull); - - return this; -} - -export function readableStreamByteStreamControllerStart(this, controller) { - $putByIdDirectPrivate(controller, "start", undefined); -} - -export function privateInitializeReadableStreamBYOBRequest(this, controller, view) { - $putByIdDirectPrivate(this, "associatedReadableByteStreamController", controller); - $putByIdDirectPrivate(this, "view", view); -} - -export function isReadableByteStreamController(controller) { - // Same test mechanism as in isReadableStreamDefaultController (ReadableStreamInternals.js). - // See corresponding function for explanations. - return $isObject(controller) && !!$getByIdDirectPrivate(controller, "underlyingByteSource"); -} - -export function isReadableStreamBYOBRequest(byobRequest) { - // Same test mechanism as in isReadableStreamDefaultController (ReadableStreamInternals.js). - // See corresponding function for explanations. - return $isObject(byobRequest) && !!$getByIdDirectPrivate(byobRequest, "associatedReadableByteStreamController"); -} - -export function isReadableStreamBYOBReader(reader) { - // Spec tells to return true only if reader has a readIntoRequests internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Since readIntoRequests is initialized with an empty array, the following test is ok. - return $isObject(reader) && !!$getByIdDirectPrivate(reader, "readIntoRequests"); -} - -export function readableByteStreamControllerCancel(controller, reason) { - var pendingPullIntos = $getByIdDirectPrivate(controller, "pendingPullIntos"); - var first = pendingPullIntos.peek(); - if (first) first.bytesFilled = 0; - - $putByIdDirectPrivate(controller, "queue", $newQueue()); - return $promiseInvokeOrNoop($getByIdDirectPrivate(controller, "underlyingByteSource"), "cancel", [reason]); -} - -export function readableByteStreamControllerError(controller, e) { - $assert( - $getByIdDirectPrivate($getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === $streamReadable, - ); - $readableByteStreamControllerClearPendingPullIntos(controller); - $putByIdDirectPrivate(controller, "queue", $newQueue()); - $readableStreamError($getByIdDirectPrivate(controller, "controlledReadableStream"), e); -} - -export function readableByteStreamControllerClose(controller) { - $assert(!$getByIdDirectPrivate(controller, "closeRequested")); - $assert( - $getByIdDirectPrivate($getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === $streamReadable, - ); - - if ($getByIdDirectPrivate(controller, "queue").size > 0) { - $putByIdDirectPrivate(controller, "closeRequested", true); - return; - } - - var first = $getByIdDirectPrivate(controller, "pendingPullIntos")?.peek(); - if (first) { - if (first.bytesFilled > 0) { - const e = $makeTypeError("Close requested while there remain pending bytes"); - $readableByteStreamControllerError(controller, e); - throw e; - } - } - - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); -} - -export function readableByteStreamControllerClearPendingPullIntos(controller) { - $readableByteStreamControllerInvalidateBYOBRequest(controller); - var existing = $getByIdDirectPrivate(controller, "pendingPullIntos"); - if (existing !== undefined) { - existing.clear(); - } else { - $putByIdDirectPrivate(controller, "pendingPullIntos", $createFIFO()); - } -} - -export function readableByteStreamControllerGetDesiredSize(controller) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - const state = $getByIdDirectPrivate(stream, "state"); - - if (state === $streamErrored) return null; - if (state === $streamClosed) return 0; - - return $getByIdDirectPrivate(controller, "strategyHWM") - $getByIdDirectPrivate(controller, "queue").size; -} - -export function readableStreamHasBYOBReader(stream) { - const reader = $getByIdDirectPrivate(stream, "reader"); - return reader !== undefined && $isReadableStreamBYOBReader(reader); -} - -export function readableStreamHasDefaultReader(stream) { - const reader = $getByIdDirectPrivate(stream, "reader"); - return reader !== undefined && $isReadableStreamDefaultReader(reader); -} - -export function readableByteStreamControllerHandleQueueDrain(controller) { - $assert( - $getByIdDirectPrivate($getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === $streamReadable, - ); - if (!$getByIdDirectPrivate(controller, "queue").size && $getByIdDirectPrivate(controller, "closeRequested")) - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); - else $readableByteStreamControllerCallPullIfNeeded(controller); -} - -export function readableByteStreamControllerPull(controller) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - $assert($readableStreamHasDefaultReader(stream)); - if ($getByIdDirectPrivate(controller, "queue").content?.isNotEmpty()) { - const entry = $getByIdDirectPrivate(controller, "queue").content.shift(); - $getByIdDirectPrivate(controller, "queue").size -= entry.byteLength; - $readableByteStreamControllerHandleQueueDrain(controller); - let view; - try { - view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); - } catch (error) { - return Promise.$reject(error); - } - return $createFulfilledPromise({ value: view, done: false }); - } - - if ($getByIdDirectPrivate(controller, "autoAllocateChunkSize") !== undefined) { - let buffer; - try { - buffer = $createUninitializedArrayBuffer($getByIdDirectPrivate(controller, "autoAllocateChunkSize")); - } catch (error) { - return Promise.$reject(error); - } - const pullIntoDescriptor = { - buffer, - byteOffset: 0, - byteLength: $getByIdDirectPrivate(controller, "autoAllocateChunkSize"), - bytesFilled: 0, - elementSize: 1, - ctor: Uint8Array, - readerType: "default", - }; - $getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); - } - - const promise = $readableStreamAddReadRequest(stream); - $readableByteStreamControllerCallPullIfNeeded(controller); - return promise; -} - -export function readableByteStreamControllerShouldCallPull(controller) { - $assert(controller); - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - if (!stream) { - return false; - } - - if ($getByIdDirectPrivate(stream, "state") !== $streamReadable) return false; - if ($getByIdDirectPrivate(controller, "closeRequested")) return false; - if (!($getByIdDirectPrivate(controller, "started") > 0)) return false; - const reader = $getByIdDirectPrivate(stream, "reader"); - - if (reader && ($getByIdDirectPrivate(reader, "readRequests")?.isNotEmpty() || !!reader.$bunNativePtr)) return true; - if ( - $readableStreamHasBYOBReader(stream) && - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readIntoRequests")?.isNotEmpty() - ) - return true; - if ($readableByteStreamControllerGetDesiredSize(controller) > 0) return true; - return false; -} - -export function readableByteStreamControllerCallPullIfNeeded(controller) { - $assert(controller); - if (!$readableByteStreamControllerShouldCallPull(controller)) return; - - if ($getByIdDirectPrivate(controller, "pulling")) { - $putByIdDirectPrivate(controller, "pullAgain", true); - return; - } - - $assert(!$getByIdDirectPrivate(controller, "pullAgain")); - $putByIdDirectPrivate(controller, "pulling", true); - $promiseInvokeOrNoop($getByIdDirectPrivate(controller, "underlyingByteSource"), "pull", [controller]).$then( - () => { - $putByIdDirectPrivate(controller, "pulling", false); - if ($getByIdDirectPrivate(controller, "pullAgain")) { - $putByIdDirectPrivate(controller, "pullAgain", false); - $readableByteStreamControllerCallPullIfNeeded(controller); - } - }, - error => { - if ( - $getByIdDirectPrivate($getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === - $streamReadable - ) - $readableByteStreamControllerError(controller, error); - }, - ); -} - -export function transferBufferToCurrentRealm(buffer) { - // FIXME: Determine what should be done here exactly (what is already existing in current - // codebase and what has to be added). According to spec, Transfer operation should be - // performed in order to transfer buffer to current realm. For the moment, simply return - // received buffer. - return buffer; -} - -export function readableStreamReaderKind(reader) { - if (!!$getByIdDirectPrivate(reader, "readRequests")) return reader.$bunNativePtr ? 3 : 1; - - if (!!$getByIdDirectPrivate(reader, "readIntoRequests")) return 2; - - return 0; -} - -export function readableByteStreamControllerEnqueue(controller, chunk) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - $assert(!$getByIdDirectPrivate(controller, "closeRequested")); - $assert($getByIdDirectPrivate(stream, "state") === $streamReadable); - - switch ( - $getByIdDirectPrivate(stream, "reader") ? $readableStreamReaderKind($getByIdDirectPrivate(stream, "reader")) : 0 - ) { - /* default reader */ - case 1: { - if (!$getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) - $readableByteStreamControllerEnqueueChunk( - controller, - $transferBufferToCurrentRealm(chunk.buffer), - chunk.byteOffset, - chunk.byteLength, - ); - else { - $assert(!$getByIdDirectPrivate(controller, "queue").content.size()); - const transferredView = - chunk.constructor === Uint8Array ? chunk : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); - $readableStreamFulfillReadRequest(stream, transferredView, false); - } - break; - } - - /* BYOB */ - case 2: { - $readableByteStreamControllerEnqueueChunk( - controller, - $transferBufferToCurrentRealm(chunk.buffer), - chunk.byteOffset, - chunk.byteLength, - ); - $readableByteStreamControllerProcessPullDescriptors(controller); - break; - } - - /* NativeReader */ - case 3: { - // reader.$enqueueNative($getByIdDirectPrivate(reader, "bunNativePtr"), chunk); - - break; - } - - default: { - $assert(!$isReadableStreamLocked(stream)); - $readableByteStreamControllerEnqueueChunk( - controller, - $transferBufferToCurrentRealm(chunk.buffer), - chunk.byteOffset, - chunk.byteLength, - ); - break; - } - } -} - -// Spec name: readableByteStreamControllerEnqueueChunkToQueue. -export function readableByteStreamControllerEnqueueChunk(controller, buffer, byteOffset, byteLength) { - $getByIdDirectPrivate(controller, "queue").content.push({ - buffer: buffer, - byteOffset: byteOffset, - byteLength: byteLength, - }); - $getByIdDirectPrivate(controller, "queue").size += byteLength; -} - -export function readableByteStreamControllerRespondWithNewView(controller, view) { - $assert($getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); - - let firstDescriptor = $getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - - if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) - throw new RangeError("Invalid value for view.byteOffset"); - - if (firstDescriptor.byteLength !== view.byteLength) throw new RangeError("Invalid value for view.byteLength"); - - firstDescriptor.buffer = view.buffer; - $readableByteStreamControllerRespondInternal(controller, view.byteLength); -} - -export function readableByteStreamControllerRespond(controller, bytesWritten) { - bytesWritten = $toNumber(bytesWritten); - - if (bytesWritten !== bytesWritten || bytesWritten === Infinity || bytesWritten < 0) - throw new RangeError("bytesWritten has an incorrect value"); - - $assert($getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); - - $readableByteStreamControllerRespondInternal(controller, bytesWritten); -} - -export function readableByteStreamControllerRespondInternal(controller, bytesWritten) { - let firstDescriptor = $getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - let stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - - if ($getByIdDirectPrivate(stream, "state") === $streamClosed) { - $readableByteStreamControllerRespondInClosedState(controller, firstDescriptor); - } else { - $assert($getByIdDirectPrivate(stream, "state") === $streamReadable); - $readableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); - } -} - -export function readableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { - if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) - throw new RangeError("bytesWritten value is too great"); - - $assert( - $getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || - $getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor, - ); - $readableByteStreamControllerInvalidateBYOBRequest(controller); - pullIntoDescriptor.bytesFilled += bytesWritten; - - if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) return; - - $readableByteStreamControllerShiftPendingDescriptor(controller); - const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; - - if (remainderSize > 0) { - const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - const remainder = $cloneArrayBuffer(pullIntoDescriptor.buffer, end - remainderSize, remainderSize); - $readableByteStreamControllerEnqueueChunk(controller, remainder, 0, remainder.byteLength); - } - - pullIntoDescriptor.buffer = $transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - pullIntoDescriptor.bytesFilled -= remainderSize; - $readableByteStreamControllerCommitDescriptor( - $getByIdDirectPrivate(controller, "controlledReadableStream"), - pullIntoDescriptor, - ); - $readableByteStreamControllerProcessPullDescriptors(controller); -} - -export function readableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - firstDescriptor.buffer = $transferBufferToCurrentRealm(firstDescriptor.buffer); - $assert(firstDescriptor.bytesFilled === 0); - - if ($readableStreamHasBYOBReader($getByIdDirectPrivate(controller, "controlledReadableStream"))) { - while ( - $getByIdDirectPrivate( - $getByIdDirectPrivate($getByIdDirectPrivate(controller, "controlledReadableStream"), "reader"), - "readIntoRequests", - )?.isNotEmpty() - ) { - let pullIntoDescriptor = $readableByteStreamControllerShiftPendingDescriptor(controller); - $readableByteStreamControllerCommitDescriptor( - $getByIdDirectPrivate(controller, "controlledReadableStream"), - pullIntoDescriptor, - ); - } - } -} - -// Spec name: readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue (shortened for readability). -export function readableByteStreamControllerProcessPullDescriptors(controller) { - $assert(!$getByIdDirectPrivate(controller, "closeRequested")); - while ($getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()) { - if ($getByIdDirectPrivate(controller, "queue").size === 0) return; - let pullIntoDescriptor = $getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - if ($readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) { - $readableByteStreamControllerShiftPendingDescriptor(controller); - $readableByteStreamControllerCommitDescriptor( - $getByIdDirectPrivate(controller, "controlledReadableStream"), - pullIntoDescriptor, - ); - } - } -} - -// Spec name: readableByteStreamControllerFillPullIntoDescriptorFromQueue (shortened for readability). -export function readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor) { - const currentAlignedBytes = - pullIntoDescriptor.bytesFilled - (pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize); - const maxBytesToCopy = - $getByIdDirectPrivate(controller, "queue").size < pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled - ? $getByIdDirectPrivate(controller, "queue").size - : pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled; - const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; - const maxAlignedBytes = maxBytesFilled - (maxBytesFilled % pullIntoDescriptor.elementSize); - let totalBytesToCopyRemaining = maxBytesToCopy; - let ready = false; - - if (maxAlignedBytes > currentAlignedBytes) { - totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - ready = true; - } - - while (totalBytesToCopyRemaining > 0) { - let headOfQueue = $getByIdDirectPrivate(controller, "queue").content.peek(); - const bytesToCopy = - totalBytesToCopyRemaining < headOfQueue.byteLength ? totalBytesToCopyRemaining : headOfQueue.byteLength; - // Copy appropriate part of pullIntoDescriptor.buffer to headOfQueue.buffer. - // Remark: this implementation is not completely aligned on the definition of CopyDataBlockBytes - // operation of ECMAScript (the case of Shared Data Block is not considered here, but it doesn't seem to be an issue). - const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - // FIXME: As indicated in comments of bug 172717, access to set is not safe. However, using prototype.$set.$call does - // not work ($set is undefined). A safe way to do that is needed. - new Uint8Array(pullIntoDescriptor.buffer).set( - new Uint8Array(headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy), - destStart, - ); - - if (headOfQueue.byteLength === bytesToCopy) $getByIdDirectPrivate(controller, "queue").content.shift(); - else { - headOfQueue.byteOffset += bytesToCopy; - headOfQueue.byteLength -= bytesToCopy; - } - - $getByIdDirectPrivate(controller, "queue").size -= bytesToCopy; - $assert( - $getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || - $getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor, - ); - $readableByteStreamControllerInvalidateBYOBRequest(controller); - pullIntoDescriptor.bytesFilled += bytesToCopy; - totalBytesToCopyRemaining -= bytesToCopy; - } - - if (!ready) { - $assert($getByIdDirectPrivate(controller, "queue").size === 0); - $assert(pullIntoDescriptor.bytesFilled > 0); - $assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); - } - - return ready; -} - -// Spec name: readableByteStreamControllerShiftPendingPullInto (renamed for consistency). -export function readableByteStreamControllerShiftPendingDescriptor(controller) { - let descriptor = $getByIdDirectPrivate(controller, "pendingPullIntos").shift(); - $readableByteStreamControllerInvalidateBYOBRequest(controller); - return descriptor; -} - -export function readableByteStreamControllerInvalidateBYOBRequest(controller) { - if ($getByIdDirectPrivate(controller, "byobRequest") === undefined) return; - const byobRequest = $getByIdDirectPrivate(controller, "byobRequest"); - $putByIdDirectPrivate(byobRequest, "associatedReadableByteStreamController", undefined); - $putByIdDirectPrivate(byobRequest, "view", undefined); - $putByIdDirectPrivate(controller, "byobRequest", undefined); -} - -// Spec name: readableByteStreamControllerCommitPullIntoDescriptor (shortened for readability). -export function readableByteStreamControllerCommitDescriptor(stream, pullIntoDescriptor) { - $assert($getByIdDirectPrivate(stream, "state") !== $streamErrored); - let done = false; - if ($getByIdDirectPrivate(stream, "state") === $streamClosed) { - $assert(!pullIntoDescriptor.bytesFilled); - done = true; - } - let filledView = $readableByteStreamControllerConvertDescriptor(pullIntoDescriptor); - if (pullIntoDescriptor.readerType === "default") $readableStreamFulfillReadRequest(stream, filledView, done); - else { - $assert(pullIntoDescriptor.readerType === "byob"); - $readableStreamFulfillReadIntoRequest(stream, filledView, done); - } -} - -// Spec name: readableByteStreamControllerConvertPullIntoDescriptor (shortened for readability). -export function readableByteStreamControllerConvertDescriptor(pullIntoDescriptor) { - $assert(pullIntoDescriptor.bytesFilled <= pullIntoDescriptor.byteLength); - $assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); - - return new pullIntoDescriptor.ctor( - pullIntoDescriptor.buffer, - pullIntoDescriptor.byteOffset, - pullIntoDescriptor.bytesFilled / pullIntoDescriptor.elementSize, - ); -} - -export function readableStreamFulfillReadIntoRequest(stream, chunk, done) { - const readIntoRequest = $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readIntoRequests").shift(); - $fulfillPromise(readIntoRequest, { value: chunk, done: done }); -} - -export function readableStreamBYOBReaderRead(reader, view) { - const stream = $getByIdDirectPrivate(reader, "ownerReadableStream"); - $assert(!!stream); - - $putByIdDirectPrivate(stream, "disturbed", true); - if ($getByIdDirectPrivate(stream, "state") === $streamErrored) - return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - - return $readableByteStreamControllerPullInto($getByIdDirectPrivate(stream, "readableStreamController"), view); -} - -export function readableByteStreamControllerPullInto(controller, view) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - let elementSize = 1; - // Spec describes that in the case where view is a TypedArray, elementSize - // should be set to the size of an element (e.g. 2 for UInt16Array). For - // DataView, BYTES_PER_ELEMENT is undefined, contrary to the same property - // for TypedArrays. - // FIXME: Getting BYTES_PER_ELEMENT like this is not safe (property is read-only - // but can be modified if the prototype is redefined). A safe way of getting - // it would be to determine which type of ArrayBufferView view is an instance - // of based on typed arrays private variables. However, this is not possible due - // to bug 167697, which prevents access to typed arrays through their private - // names unless public name has already been met before. - if (view.BYTES_PER_ELEMENT !== undefined) elementSize = view.BYTES_PER_ELEMENT; - - // FIXME: Getting constructor like this is not safe. A safe way of getting - // it would be to determine which type of ArrayBufferView view is an instance - // of, and to assign appropriate constructor based on this (e.g. ctor = - // $Uint8Array). However, this is not possible due to bug 167697, which - // prevents access to typed arrays through their private names unless public - // name has already been met before. - const ctor = view.constructor; - - const pullIntoDescriptor = { - buffer: view.buffer, - byteOffset: view.byteOffset, - byteLength: view.byteLength, - bytesFilled: 0, - elementSize, - ctor, - readerType: "byob", - }; - - var pending = $getByIdDirectPrivate(controller, "pendingPullIntos"); - if (pending?.isNotEmpty()) { - pullIntoDescriptor.buffer = $transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - pending.push(pullIntoDescriptor); - return $readableStreamAddReadIntoRequest(stream); - } - - if ($getByIdDirectPrivate(stream, "state") === $streamClosed) { - const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); - return $createFulfilledPromise({ value: emptyView, done: true }); - } - - if ($getByIdDirectPrivate(controller, "queue").size > 0) { - if ($readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) { - const filledView = $readableByteStreamControllerConvertDescriptor(pullIntoDescriptor); - $readableByteStreamControllerHandleQueueDrain(controller); - return $createFulfilledPromise({ value: filledView, done: false }); - } - if ($getByIdDirectPrivate(controller, "closeRequested")) { - const e = $makeTypeError("Closing stream has been requested"); - $readableByteStreamControllerError(controller, e); - return Promise.$reject(e); - } - } - - pullIntoDescriptor.buffer = $transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - $getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); - const promise = $readableStreamAddReadIntoRequest(stream); - $readableByteStreamControllerCallPullIfNeeded(controller); - return promise; -} - -export function readableStreamAddReadIntoRequest(stream) { - $assert($isReadableStreamBYOBReader($getByIdDirectPrivate(stream, "reader"))); - $assert( - $getByIdDirectPrivate(stream, "state") === $streamReadable || - $getByIdDirectPrivate(stream, "state") === $streamClosed, - ); - - const readRequest = $newPromise(); - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readIntoRequests").push(readRequest); - - return readRequest; -} diff --git a/src/js/builtins/ReadableStream.ts b/src/js/builtins/ReadableStream.ts index 6e7e2d5951d310..e7a4f50681ce79 100644 --- a/src/js/builtins/ReadableStream.ts +++ b/src/js/builtins/ReadableStream.ts @@ -1,515 +1,21 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableStream( - this: ReadableStream, - underlyingSource: UnderlyingSource, - strategy: QueuingStrategy, -) { - if (underlyingSource === undefined) underlyingSource = { $bunNativePtr: undefined, $lazy: false } as UnderlyingSource; - if (strategy === undefined) strategy = {}; - - if (!$isObject(underlyingSource)) throw new TypeError("ReadableStream constructor takes an object as first argument"); - - if (strategy !== undefined && !$isObject(strategy)) - throw new TypeError("ReadableStream constructor takes an object as second argument, if any"); - - $putByIdDirectPrivate(this, "state", $streamReadable); - - $putByIdDirectPrivate(this, "reader", undefined); - - $putByIdDirectPrivate(this, "storedError", undefined); - - this.$disturbed = false; - - // Initialized with null value to enable distinction with undefined case. - $putByIdDirectPrivate(this, "readableStreamController", null); - this.$bunNativePtr = $getByIdDirectPrivate(underlyingSource, "bunNativePtr") ?? undefined; - - $putByIdDirectPrivate(this, "asyncContext", $getInternalField($asyncContext, 0)); - - const isDirect = underlyingSource.type === "direct"; - // direct streams are always lazy - const isUnderlyingSourceLazy = !!underlyingSource.$lazy; - const isLazy = isDirect || isUnderlyingSourceLazy; - let pullFn; - - // FIXME: We should introduce https://streams.spec.whatwg.org/#create-readable-stream. - // For now, we emulate this with underlyingSource with private properties. - if (!isLazy && (pullFn = $getByIdDirectPrivate(underlyingSource, "pull")) !== undefined) { - const size = $getByIdDirectPrivate(strategy, "size"); - const highWaterMark = $getByIdDirectPrivate(strategy, "highWaterMark"); - $putByIdDirectPrivate(this, "highWaterMark", highWaterMark); - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $setupReadableStreamDefaultController( - this, - underlyingSource, - size, - highWaterMark !== undefined ? highWaterMark : 1, - $getByIdDirectPrivate(underlyingSource, "start"), - pullFn, - $getByIdDirectPrivate(underlyingSource, "cancel"), - ); - - return this; - } - if (isDirect) { - $putByIdDirectPrivate(this, "underlyingSource", underlyingSource); - $putByIdDirectPrivate(this, "highWaterMark", $getByIdDirectPrivate(strategy, "highWaterMark")); - $putByIdDirectPrivate(this, "start", () => $createReadableStreamController(this, underlyingSource, strategy)); - } else if (isLazy) { - const autoAllocateChunkSize = underlyingSource.autoAllocateChunkSize; - $putByIdDirectPrivate(this, "highWaterMark", undefined); - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $putByIdDirectPrivate( - this, - "highWaterMark", - autoAllocateChunkSize || $getByIdDirectPrivate(strategy, "highWaterMark"), - ); - - $putByIdDirectPrivate(this, "start", () => { - const instance = $lazyLoadStream(this, autoAllocateChunkSize); - if (instance) { - $createReadableStreamController(this, instance, strategy); - } - }); - } else { - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $putByIdDirectPrivate(this, "highWaterMark", $getByIdDirectPrivate(strategy, "highWaterMark")); - $putByIdDirectPrivate(this, "start", undefined); - $createReadableStreamController(this, underlyingSource, strategy); - } - - return this; +export function readableStreamToArray(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToArray(stream: ReadableStream): Promise { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - // this is a direct stream - var underlyingSource = $getByIdDirectPrivate(stream, "underlyingSource"); - if (underlyingSource !== undefined) { - return $readableStreamToArrayDirect(stream, underlyingSource); - } - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - return $readableStreamIntoArray(stream); +export function readableStreamToArrayBuffer(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToText(stream: ReadableStream): Promise { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - // this is a direct stream - var underlyingSource = $getByIdDirectPrivate(stream, "underlyingSource"); - if (underlyingSource !== undefined) { - return $readableStreamToTextDirect(stream, underlyingSource); - } - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - const result = $tryUseReadableStreamBufferedFastPath(stream, "text"); - - if (result) { - return result; - } - - return $readableStreamIntoText(stream); +export function readableStreamToBytes(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToArrayBuffer(stream: ReadableStream): Promise | ArrayBuffer { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - // this is a direct stream - var underlyingSource = $getByIdDirectPrivate(stream, "underlyingSource"); - if (underlyingSource !== undefined) { - return $readableStreamToArrayBufferDirect(stream, underlyingSource, false); - } - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - let result = $tryUseReadableStreamBufferedFastPath(stream, "arrayBuffer"); - - if (result) { - return result; - } - - result = Bun.readableStreamToArray(stream); - - function toArrayBuffer(result: unknown[]) { - switch (result.length) { - case 0: { - return new ArrayBuffer(0); - } - case 1: { - const view = result[0]; - if (view instanceof ArrayBuffer || view instanceof SharedArrayBuffer) { - return view; - } - - if (ArrayBuffer.isView(view)) { - const buffer = view.buffer; - const byteOffset = view.byteOffset; - const byteLength = view.byteLength; - if (byteOffset === 0 && byteLength === buffer.byteLength) { - return buffer; - } - - return buffer.slice(byteOffset, byteOffset + byteLength); - } - - if (typeof view === "string") { - return new TextEncoder().encode(view); - } - } - default: { - let anyStrings = false; - for (const chunk of result) { - if (typeof chunk === "string") { - anyStrings = true; - break; - } - } - - if (!anyStrings) { - return Bun.concatArrayBuffers(result, false); - } - - const sink = new Bun.ArrayBufferSink(); - sink.start(); - - for (const chunk of result) { - sink.write(chunk); - } - - return sink.end() as Uint8Array; - } - } - } - - if ($isPromise(result)) { - const completedResult = Bun.peek(result); - if (completedResult !== result) { - result = completedResult; - } else { - return result.then(toArrayBuffer); - } - } - return $createFulfilledPromise(toArrayBuffer(result)); +export function readableStreamToBlob(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToBytes(stream: ReadableStream): Promise | Uint8Array { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - // this is a direct stream - var underlyingSource = $getByIdDirectPrivate(stream, "underlyingSource"); - - if (underlyingSource !== undefined) { - return $readableStreamToArrayBufferDirect(stream, underlyingSource, true); - } - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - let result = $tryUseReadableStreamBufferedFastPath(stream, "bytes"); - - if (result) { - return result; - } - - result = Bun.readableStreamToArray(stream); - - function toBytes(result: unknown[]) { - switch (result.length) { - case 0: { - return new Uint8Array(0); - } - case 1: { - const view = result[0]; - if (view instanceof Uint8Array) { - return view; - } - - if (ArrayBuffer.isView(view)) { - return new Uint8Array(view.buffer, view.byteOffset, view.byteLength); - } - - if (view instanceof ArrayBuffer || view instanceof SharedArrayBuffer) { - return new Uint8Array(view); - } - - if (typeof view === "string") { - return new TextEncoder().encode(view); - } - } - default: { - let anyStrings = false; - for (const chunk of result) { - if (typeof chunk === "string") { - anyStrings = true; - break; - } - } - - if (!anyStrings) { - return Bun.concatArrayBuffers(result, true); - } - - const sink = new Bun.ArrayBufferSink(); - sink.start({ asUint8Array: true }); - - for (const chunk of result) { - sink.write(chunk); - } - - return sink.end() as Uint8Array; - } - } - } - - if ($isPromise(result)) { - const completedResult = Bun.peek(result); - if (completedResult !== result) { - result = completedResult; - } else { - return result.then(toBytes); - } - } - - return $createFulfilledPromise(toBytes(result)); +export function readableStreamToFormData(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToFormData( - stream: ReadableStream, - contentType: string | ArrayBuffer | ArrayBufferView, -): Promise { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - return Bun.readableStreamToBlob(stream).then(blob => { - return FormData.from(blob, contentType); - }); +export function readableStreamToJSON(stream) { + throw new Error("TODO: add this back"); } - -$linkTimeConstant; -export function readableStreamToJSON(stream: ReadableStream): unknown { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - let result = $tryUseReadableStreamBufferedFastPath(stream, "json"); - if (result) { - return result; - } - - let text = Bun.readableStreamToText(stream); - const peeked = Bun.peek(text); - if (peeked !== text) { - try { - return $createFulfilledPromise(globalThis.JSON.parse(peeked)); - } catch (e) { - return Promise.reject(e); - } - } - - return text.then(globalThis.JSON.parse); -} - -$linkTimeConstant; -export function readableStreamToBlob(stream: ReadableStream): Promise { - if (!$isReadableStream(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "ReadableStream", typeof stream); - if ($isReadableStreamLocked(stream)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - return ( - $tryUseReadableStreamBufferedFastPath(stream, "blob") || - Promise.resolve(Bun.readableStreamToArray(stream)).then(array => new Blob(array)) - ); -} - -$linkTimeConstant; -export function createEmptyReadableStream() { - var stream = new ReadableStream({ - pull() {}, - } as any); - $readableStreamClose(stream); - return stream; -} - -$linkTimeConstant; -export function createUsedReadableStream() { - var stream = new ReadableStream({ - pull() {}, - } as any); - stream.getReader(); - return stream; -} - -$linkTimeConstant; -export function createNativeReadableStream(nativePtr, autoAllocateChunkSize) { - $assert(nativePtr, "nativePtr must be a valid pointer"); - return new ReadableStream({ - $lazy: true, - $bunNativePtr: nativePtr, - autoAllocateChunkSize: autoAllocateChunkSize, - }); -} - -export function cancel(this, reason) { - if (!$isReadableStream(this)) return Promise.$reject($makeThisTypeError("ReadableStream", "cancel")); - - if ($isReadableStreamLocked(this)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - return $readableStreamCancel(this, reason); -} - -export function getReader(this, options) { - if (!$isReadableStream(this)) throw $makeThisTypeError("ReadableStream", "getReader"); - - const mode = $toDictionary(options, {}, "ReadableStream.getReader takes an object as first argument").mode; - if (mode === undefined) { - var start_ = $getByIdDirectPrivate(this, "start"); - if (start_) { - $putByIdDirectPrivate(this, "start", undefined); - start_(); - } - - return new ReadableStreamDefaultReader(this); - } - // String conversion is required by spec, hence double equals. - if (mode == "byob") { - return new ReadableStreamBYOBReader(this); - } - - throw new TypeError("Invalid mode is specified"); -} - -export function pipeThrough(this, streams, options) { - const transforms = streams; - - const readable = transforms["readable"]; - if (!$isReadableStream(readable)) throw $makeTypeError("readable should be ReadableStream"); - - const writable = transforms["writable"]; - const internalWritable = $getInternalWritableStream(writable); - if (!$isWritableStream(internalWritable)) throw $makeTypeError("writable should be WritableStream"); - - let preventClose = false; - let preventAbort = false; - let preventCancel = false; - let signal; - if (!$isUndefinedOrNull(options)) { - if (!$isObject(options)) throw $makeTypeError("options must be an object"); - - preventAbort = !!options["preventAbort"]; - preventCancel = !!options["preventCancel"]; - preventClose = !!options["preventClose"]; - - signal = options["signal"]; - if (signal !== undefined && !$isAbortSignal(signal)) throw $makeTypeError("options.signal must be AbortSignal"); - } - - if (!$isReadableStream(this)) throw $makeThisTypeError("ReadableStream", "pipeThrough"); - - if ($isReadableStreamLocked(this)) throw $makeTypeError("ReadableStream is locked"); - - if ($isWritableStreamLocked(internalWritable)) throw $makeTypeError("WritableStream is locked"); - - const promise = $readableStreamPipeToWritableStream( - this, - internalWritable, - preventClose, - preventAbort, - preventCancel, - signal, - ); - $markPromiseAsHandled(promise); - - return readable; -} - -export function pipeTo(this, destination) { - if (!$isReadableStream(this)) return Promise.$reject($makeThisTypeError("ReadableStream", "pipeTo")); - - if ($isReadableStreamLocked(this)) return Promise.$reject($makeTypeError("ReadableStream is locked")); - - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=159869. - // Built-in generator should be able to parse function signature to compute the function length correctly. - let options = $argument(1); - - let preventClose = false; - let preventAbort = false; - let preventCancel = false; - let signal; - if (!$isUndefinedOrNull(options)) { - if (!$isObject(options)) return Promise.$reject($makeTypeError("options must be an object")); - - try { - preventAbort = !!options["preventAbort"]; - preventCancel = !!options["preventCancel"]; - preventClose = !!options["preventClose"]; - - signal = options["signal"]; - } catch (e) { - return Promise.$reject(e); - } - - if (signal !== undefined && !$isAbortSignal(signal)) - return Promise.$reject(new TypeError("options.signal must be AbortSignal")); - } - - const internalDestination = $getInternalWritableStream(destination); - if (!$isWritableStream(internalDestination)) - return Promise.$reject(new TypeError("ReadableStream pipeTo requires a WritableStream")); - - if ($isWritableStreamLocked(internalDestination)) return Promise.$reject(new TypeError("WritableStream is locked")); - - return $readableStreamPipeToWritableStream( - this, - internalDestination, - preventClose, - preventAbort, - preventCancel, - signal, - ); -} - -export function tee(this) { - if (!$isReadableStream(this)) throw $makeThisTypeError("ReadableStream", "tee"); - - return $readableStreamTee(this, false); -} - -$getter; -export function locked(this) { - if (!$isReadableStream(this)) throw $makeGetterTypeError("ReadableStream", "locked"); - - return $isReadableStreamLocked(this); -} - -export function values(this, options) { - var prototype = ReadableStream.prototype; - $readableStreamDefineLazyIterators(prototype); - return prototype.values.$call(this, options); -} - -$linkTimeConstant; -export function lazyAsyncIterator(this) { - var prototype = ReadableStream.prototype; - $readableStreamDefineLazyIterators(prototype); - return prototype[globalThis.Symbol.asyncIterator].$call(this); +export function readableStreamToText(stream) { + throw new Error("TODO: add this back"); } diff --git a/src/js/builtins/ReadableStreamBYOBReader.ts b/src/js/builtins/ReadableStreamBYOBReader.ts deleted file mode 100644 index 62a04d8a3d18ab..00000000000000 --- a/src/js/builtins/ReadableStreamBYOBReader.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2017 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableStreamBYOBReader(this, stream) { - if (!$isReadableStream(stream)) throw new TypeError("ReadableStreamBYOBReader needs a ReadableStream"); - if (!$isReadableByteStreamController($getByIdDirectPrivate(stream, "readableStreamController"))) - throw new TypeError("ReadableStreamBYOBReader needs a ReadableByteStreamController"); - if ($isReadableStreamLocked(stream)) throw new TypeError("ReadableStream is locked"); - - $readableStreamReaderGenericInitialize(this, stream); - $putByIdDirectPrivate(this, "readIntoRequests", $createFIFO()); - - return this; -} - -export function cancel(this, reason) { - if (!$isReadableStreamBYOBReader(this)) - return Promise.$reject($makeThisTypeError("ReadableStreamBYOBReader", "cancel")); - - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) - return Promise.$reject($makeTypeError("cancel() called on a reader owned by no readable stream")); - - return $readableStreamReaderGenericCancel(this, reason); -} - -export function read(this, view: DataView) { - if (!$isReadableStreamBYOBReader(this)) - return Promise.$reject($makeThisTypeError("ReadableStreamBYOBReader", "read")); - - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) - return Promise.$reject($makeTypeError("read() called on a reader owned by no readable stream")); - - if (!$isObject(view)) return Promise.$reject($makeTypeError("Provided view is not an object")); - - if (!ArrayBuffer.$isView(view)) return Promise.$reject($makeTypeError("Provided view is not an ArrayBufferView")); - - if (view.byteLength === 0) return Promise.$reject($makeTypeError("Provided view cannot have a 0 byteLength")); - - return $readableStreamBYOBReaderRead(this, view); -} - -export function releaseLock(this) { - if (!$isReadableStreamBYOBReader(this)) throw $makeThisTypeError("ReadableStreamBYOBReader", "releaseLock"); - - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) return; - - if ($getByIdDirectPrivate(this, "readIntoRequests")?.isNotEmpty()) - throw new TypeError("There are still pending read requests, cannot release the lock"); - - $readableStreamReaderGenericRelease(this); -} - -$getter; -export function closed(this) { - if (!$isReadableStreamBYOBReader(this)) - return Promise.$reject($makeGetterTypeError("ReadableStreamBYOBReader", "closed")); - - return $getByIdDirectPrivate(this, "closedPromiseCapability").promise; -} diff --git a/src/js/builtins/ReadableStreamBYOBRequest.ts b/src/js/builtins/ReadableStreamBYOBRequest.ts deleted file mode 100644 index 1354f934991c5b..00000000000000 --- a/src/js/builtins/ReadableStreamBYOBRequest.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2017 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableStreamBYOBRequest(this, controller, view) { - if (arguments.length !== 3 && arguments[2] !== $isReadableStream) - throw new TypeError("ReadableStreamBYOBRequest constructor should not be called directly"); - - return $privateInitializeReadableStreamBYOBRequest.$call(this, controller, view); -} - -export function respond(this, bytesWritten) { - if (!$isReadableStreamBYOBRequest(this)) throw $makeThisTypeError("ReadableStreamBYOBRequest", "respond"); - - if ($getByIdDirectPrivate(this, "associatedReadableByteStreamController") === undefined) - throw new TypeError("ReadableStreamBYOBRequest.associatedReadableByteStreamController is undefined"); - - return $readableByteStreamControllerRespond( - $getByIdDirectPrivate(this, "associatedReadableByteStreamController"), - bytesWritten, - ); -} - -export function respondWithNewView(this, view) { - if (!$isReadableStreamBYOBRequest(this)) throw $makeThisTypeError("ReadableStreamBYOBRequest", "respond"); - - if ($getByIdDirectPrivate(this, "associatedReadableByteStreamController") === undefined) - throw new TypeError("ReadableStreamBYOBRequest.associatedReadableByteStreamController is undefined"); - - if (!$isObject(view)) throw new TypeError("Provided view is not an object"); - - if (!ArrayBuffer.$isView(view)) throw new TypeError("Provided view is not an ArrayBufferView"); - - return $readableByteStreamControllerRespondWithNewView( - $getByIdDirectPrivate(this, "associatedReadableByteStreamController"), - view, - ); -} - -$getter; -export function view(this) { - if (!$isReadableStreamBYOBRequest(this)) throw $makeGetterTypeError("ReadableStreamBYOBRequest", "view"); - - return $getByIdDirectPrivate(this, "view"); -} diff --git a/src/js/builtins/ReadableStreamDefaultController.ts b/src/js/builtins/ReadableStreamDefaultController.ts deleted file mode 100644 index 6a04addc337d4a..00000000000000 --- a/src/js/builtins/ReadableStreamDefaultController.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableStreamDefaultController(this, stream, underlyingSource, size, highWaterMark) { - if (arguments.length !== 5 && arguments[4] !== $isReadableStream) - throw new TypeError("ReadableStreamDefaultController constructor should not be called directly"); - - return $privateInitializeReadableStreamDefaultController.$call(this, stream, underlyingSource, size, highWaterMark); -} - -export function enqueue(this, chunk) { - if (!$isReadableStreamDefaultController(this)) throw $makeThisTypeError("ReadableStreamDefaultController", "enqueue"); - - if (!$readableStreamDefaultControllerCanCloseOrEnqueue(this)) { - throw $ERR_INVALID_STATE("ReadableStreamDefaultController is not in a state where chunk can be enqueued"); - } - - return $readableStreamDefaultControllerEnqueue(this, chunk); -} - -export function error(this, err) { - if (!$isReadableStreamDefaultController(this)) throw $makeThisTypeError("ReadableStreamDefaultController", "error"); - $readableStreamDefaultControllerError(this, err); -} - -export function close(this) { - if (!$isReadableStreamDefaultController(this)) throw $makeThisTypeError("ReadableStreamDefaultController", "close"); - - if (!$readableStreamDefaultControllerCanCloseOrEnqueue(this)) - throw new TypeError("ReadableStreamDefaultController is not in a state where it can be closed"); - - $readableStreamDefaultControllerClose(this); -} - -$getter; -export function desiredSize(this) { - if (!$isReadableStreamDefaultController(this)) - throw $makeGetterTypeError("ReadableStreamDefaultController", "desiredSize"); - - return $readableStreamDefaultControllerGetDesiredSize(this); -} diff --git a/src/js/builtins/ReadableStreamDefaultReader.ts b/src/js/builtins/ReadableStreamDefaultReader.ts deleted file mode 100644 index 9ddb3e3f38d33d..00000000000000 --- a/src/js/builtins/ReadableStreamDefaultReader.ts +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeReadableStreamDefaultReader(this, stream) { - if (!$isReadableStream(stream)) throw new TypeError("ReadableStreamDefaultReader needs a ReadableStream"); - if ($isReadableStreamLocked(stream)) throw new TypeError("ReadableStream is locked"); - - $readableStreamReaderGenericInitialize(this, stream); - $putByIdDirectPrivate(this, "readRequests", $createFIFO()); - - return this; -} - -export function cancel(this, reason) { - if (!$isReadableStreamDefaultReader(this)) - return Promise.$reject($makeThisTypeError("ReadableStreamDefaultReader", "cancel")); - - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) - return Promise.$reject(new TypeError("cancel() called on a reader owned by no readable stream")); - - return $readableStreamReaderGenericCancel(this, reason); -} - -export function readMany(this: ReadableStreamDefaultReader): ReadableStreamDefaultReadManyResult { - if (!$isReadableStreamDefaultReader(this)) - throw new TypeError("ReadableStreamDefaultReader.readMany() should not be called directly"); - - const stream = $getByIdDirectPrivate(this, "ownerReadableStream"); - if (!stream) throw new TypeError("readMany() called on a reader owned by no readable stream"); - - const state = $getByIdDirectPrivate(stream, "state"); - stream.$disturbed = true; - if (state === $streamClosed) return { value: [], size: 0, done: true }; - else if (state === $streamErrored) { - throw $getByIdDirectPrivate(stream, "storedError"); - } - - var controller = $getByIdDirectPrivate(stream, "readableStreamController"); - var queue = $getByIdDirectPrivate(controller, "queue"); - if (!queue) { - // This is a ReadableStream direct controller implemented in JS - // It hasn't been started yet. - return controller.$pull(controller).$then(function ({ done, value }) { - return done ? { done: true, value: [], size: 0 } : { value: [value], size: 1, done: false }; - }); - } - - const content = queue.content; - var size = queue.size; - var values = content.toArray(false); - - var length = values.length; - - if (length > 0) { - var outValues = $newArrayWithSize(length); - if ($isReadableByteStreamController(controller)) { - { - const buf = values[0]; - if (!(ArrayBuffer.$isView(buf) || buf instanceof ArrayBuffer)) { - $putByValDirect(outValues, 0, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)); - } else { - $putByValDirect(outValues, 0, buf); - } - } - - for (var i = 1; i < length; i++) { - const buf = values[i]; - if (!(ArrayBuffer.$isView(buf) || buf instanceof ArrayBuffer)) { - $putByValDirect(outValues, i, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)); - } else { - $putByValDirect(outValues, i, buf); - } - } - } else { - $putByValDirect(outValues, 0, values[0].value); - for (var i = 1; i < length; i++) { - $putByValDirect(outValues, i, values[i].value); - } - } - $resetQueue($getByIdDirectPrivate(controller, "queue")); - - if ($getByIdDirectPrivate(controller, "closeRequested")) { - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); - } else if ($isReadableStreamDefaultController(controller)) { - $readableStreamDefaultControllerCallPullIfNeeded(controller); - } else if ($isReadableByteStreamController(controller)) { - $readableByteStreamControllerCallPullIfNeeded(controller); - } - - return { value: outValues, size, done: false }; - } - - var onPullMany = result => { - if (result.done) { - return { value: [], size: 0, done: true }; - } - var controller = $getByIdDirectPrivate(stream, "readableStreamController"); - - var queue = $getByIdDirectPrivate(controller, "queue"); - var value = [result.value].concat(queue.content.toArray(false)); - var length = value.length; - - if ($isReadableByteStreamController(controller)) { - for (var i = 0; i < length; i++) { - const buf = value[i]; - if (!(ArrayBuffer.$isView(buf) || buf instanceof ArrayBuffer)) { - const { buffer, byteOffset, byteLength } = buf; - $putByValDirect(value, i, new Uint8Array(buffer, byteOffset, byteLength)); - } - } - } else { - for (var i = 1; i < length; i++) { - $putByValDirect(value, i, value[i].value); - } - } - - var size = queue.size; - $resetQueue(queue); - - if ($getByIdDirectPrivate(controller, "closeRequested")) { - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); - } else if ($isReadableStreamDefaultController(controller)) { - $readableStreamDefaultControllerCallPullIfNeeded(controller); - } else if ($isReadableByteStreamController(controller)) { - $readableByteStreamControllerCallPullIfNeeded(controller); - } - - return { value: value, size: size, done: false }; - }; - - var pullResult = controller.$pull(controller); - if (pullResult && $isPromise(pullResult)) { - return pullResult.$then(onPullMany) as any; - } - - return onPullMany(pullResult); -} - -export function read(this) { - if (!$isReadableStreamDefaultReader(this)) - return Promise.$reject($makeThisTypeError("ReadableStreamDefaultReader", "read")); - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) - return Promise.$reject(new TypeError("read() called on a reader owned by no readable stream")); - - return $readableStreamDefaultReaderRead(this); -} - -export function releaseLock(this) { - if (!$isReadableStreamDefaultReader(this)) throw $makeThisTypeError("ReadableStreamDefaultReader", "releaseLock"); - - if (!$getByIdDirectPrivate(this, "ownerReadableStream")) return; - - $readableStreamDefaultReaderRelease(this); -} - -$getter; -export function closed(this) { - if (!$isReadableStreamDefaultReader(this)) - return Promise.$reject($makeGetterTypeError("ReadableStreamDefaultReader", "closed")); - - return $getByIdDirectPrivate(this, "closedPromiseCapability").promise; -} diff --git a/src/js/builtins/ReadableStreamInternals.ts b/src/js/builtins/ReadableStreamInternals.ts deleted file mode 100644 index f81b71d6bdcd1b..00000000000000 --- a/src/js/builtins/ReadableStreamInternals.ts +++ /dev/null @@ -1,2178 +0,0 @@ -// @ts-nocheck -/* - * Copyright (C) 2015 Canon Inc. All rights reserved. - * Copyright (C) 2015 Igalia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -export function readableStreamReaderGenericInitialize(reader, stream) { - $putByIdDirectPrivate(reader, "ownerReadableStream", stream); - $putByIdDirectPrivate(stream, "reader", reader); - if ($getByIdDirectPrivate(stream, "state") === $streamReadable) - $putByIdDirectPrivate(reader, "closedPromiseCapability", $newPromiseCapability(Promise)); - else if ($getByIdDirectPrivate(stream, "state") === $streamClosed) - $putByIdDirectPrivate(reader, "closedPromiseCapability", { - promise: Promise.$resolve(), - }); - else { - $assert($getByIdDirectPrivate(stream, "state") === $streamErrored); - $putByIdDirectPrivate(reader, "closedPromiseCapability", { - promise: $newHandledRejectedPromise($getByIdDirectPrivate(stream, "storedError")), - }); - } -} - -export function privateInitializeReadableStreamDefaultController(this, stream, underlyingSource, size, highWaterMark) { - if (!$isReadableStream(stream)) throw new TypeError("ReadableStreamDefaultController needs a ReadableStream"); - - // readableStreamController is initialized with null value. - if ($getByIdDirectPrivate(stream, "readableStreamController") !== null) - throw new TypeError("ReadableStream already has a controller"); - - $putByIdDirectPrivate(this, "controlledReadableStream", stream); - $putByIdDirectPrivate(this, "underlyingSource", underlyingSource); - $putByIdDirectPrivate(this, "queue", $newQueue()); - $putByIdDirectPrivate(this, "started", -1); - $putByIdDirectPrivate(this, "closeRequested", false); - $putByIdDirectPrivate(this, "pullAgain", false); - $putByIdDirectPrivate(this, "pulling", false); - $putByIdDirectPrivate(this, "strategy", $validateAndNormalizeQueuingStrategy(size, highWaterMark)); - - return this; -} - -export function readableStreamDefaultControllerError(controller, error) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - if (!$isObject(stream) || $getByIdDirectPrivate(stream, "state") !== $streamReadable) return; - $putByIdDirectPrivate(controller, "queue", $newQueue()); - - $readableStreamError(stream, error); -} - -export function readableStreamPipeTo(stream, sink) { - $assert($isReadableStream(stream)); - - const reader = new ReadableStreamDefaultReader(stream); - - $getByIdDirectPrivate(reader, "closedPromiseCapability").promise.$then( - () => {}, - e => { - sink.error(e); - }, - ); - - function doPipe() { - $readableStreamDefaultReaderRead(reader).$then( - function (result) { - if (result.done) { - sink.close(); - return; - } - try { - sink.enqueue(result.value); - } catch (e) { - sink.error("ReadableStream chunk enqueueing in the sink failed"); - return; - } - doPipe(); - }, - function (e) { - sink.error(e); - }, - ); - } - doPipe(); -} - -export function acquireReadableStreamDefaultReader(stream) { - var start = $getByIdDirectPrivate(stream, "start"); - if (start) { - start.$call(stream); - } - - return new ReadableStreamDefaultReader(stream); -} - -// https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller, starting from step 6. -// The other part is implemented in privateInitializeReadableStreamDefaultController. -export function setupReadableStreamDefaultController( - stream, - underlyingSource, - size, - highWaterMark, - startMethod, - pullMethod, - cancelMethod, -) { - const controller = new ReadableStreamDefaultController( - stream, - underlyingSource, - size, - highWaterMark, - $isReadableStream, - ); - - var asyncContext = stream.$asyncContext; - const pullAlgorithm = () => $promiseInvokeOrNoopMethod(underlyingSource, pullMethod, [controller]); - const cancelAlgorithm = asyncContext - ? reason => { - var prev = $getInternalField($asyncContext, 0); - $putInternalField($asyncContext, 0, asyncContext); - // this does not throw, but can returns a rejected promise - var result = $promiseInvokeOrNoopMethod(underlyingSource, cancelMethod, [reason]); - $putInternalField($asyncContext, 0, prev); - return result; - } - : reason => $promiseInvokeOrNoopMethod(underlyingSource, cancelMethod, [reason]); - - $putByIdDirectPrivate(controller, "pullAlgorithm", pullAlgorithm); - $putByIdDirectPrivate(controller, "cancelAlgorithm", cancelAlgorithm); - $putByIdDirectPrivate(controller, "pull", $readableStreamDefaultControllerPull); - $putByIdDirectPrivate(controller, "cancel", $readableStreamDefaultControllerCancel); - $putByIdDirectPrivate(stream, "readableStreamController", controller); - - $readableStreamDefaultControllerStart(controller); -} - -export function createReadableStreamController(stream, underlyingSource, strategy) { - const type = underlyingSource.type; - const typeString = $toString(type); - - if (typeString === "bytes") { - // if (!$readableByteStreamAPIEnabled()) - // $throwTypeError("ReadableByteStreamController is not implemented"); - - if (strategy.highWaterMark === undefined) strategy.highWaterMark = 0; - if (strategy.size !== undefined) $throwRangeError("Strategy for a ReadableByteStreamController cannot have a size"); - - $putByIdDirectPrivate( - stream, - "readableStreamController", - new ReadableByteStreamController(stream, underlyingSource, strategy.highWaterMark, $isReadableStream), - ); - } else if (typeString === "direct") { - var highWaterMark = strategy?.highWaterMark; - $initializeArrayBufferStream.$call(stream, underlyingSource, highWaterMark); - } else if (type === undefined) { - if (strategy.highWaterMark === undefined) strategy.highWaterMark = 1; - - $setupReadableStreamDefaultController( - stream, - underlyingSource, - strategy.size, - strategy.highWaterMark, - underlyingSource.start, - underlyingSource.pull, - underlyingSource.cancel, - ); - } else throw new RangeError("Invalid type for underlying source"); -} - -export function readableStreamDefaultControllerStart(controller) { - if ($getByIdDirectPrivate(controller, "started") !== -1) return; - - const underlyingSource = $getByIdDirectPrivate(controller, "underlyingSource"); - const startMethod = underlyingSource.start; - $putByIdDirectPrivate(controller, "started", 0); - - $promiseInvokeOrNoopMethodNoCatch(underlyingSource, startMethod, [controller]).$then( - () => { - $putByIdDirectPrivate(controller, "started", 1); - $assert(!$getByIdDirectPrivate(controller, "pulling")); - $assert(!$getByIdDirectPrivate(controller, "pullAgain")); - $readableStreamDefaultControllerCallPullIfNeeded(controller); - }, - error => { - $readableStreamDefaultControllerError(controller, error); - }, - ); -} - -// FIXME: Replace readableStreamPipeTo by below function. -// This method implements the latest https://streams.spec.whatwg.org/#readable-stream-pipe-to. -export function readableStreamPipeToWritableStream( - source, - destination, - preventClose, - preventAbort, - preventCancel, - signal, -) { - // const isDirectStream = !!$getByIdDirectPrivate(source, "start"); - - $assert($isReadableStream(source)); - $assert($isWritableStream(destination)); - $assert(!$isReadableStreamLocked(source)); - $assert(!$isWritableStreamLocked(destination)); - $assert(signal === undefined || $isAbortSignal(signal)); - - if ($getByIdDirectPrivate(source, "underlyingByteSource") !== undefined) - return Promise.$reject("Piping to a readable bytestream is not supported"); - - let pipeState: any = { - source: source, - destination: destination, - preventAbort: preventAbort, - preventCancel: preventCancel, - preventClose: preventClose, - signal: signal, - }; - - pipeState.reader = $acquireReadableStreamDefaultReader(source); - pipeState.writer = $acquireWritableStreamDefaultWriter(destination); - - source.$disturbed = true; - - pipeState.shuttingDown = false; - pipeState.promiseCapability = $newPromiseCapability(Promise); - pipeState.pendingReadPromiseCapability = $newPromiseCapability(Promise); - pipeState.pendingReadPromiseCapability.resolve.$call(); - pipeState.pendingWritePromise = Promise.$resolve(); - - if (signal !== undefined) { - const algorithm = reason => { - $pipeToShutdownWithAction( - pipeState, - () => { - const shouldAbortDestination = - !pipeState.preventAbort && $getByIdDirectPrivate(pipeState.destination, "state") === "writable"; - const promiseDestination = shouldAbortDestination - ? $writableStreamAbort(pipeState.destination, reason) - : Promise.$resolve(); - - const shouldAbortSource = - !pipeState.preventCancel && $getByIdDirectPrivate(pipeState.source, "state") === $streamReadable; - const promiseSource = shouldAbortSource - ? $readableStreamCancel(pipeState.source, reason) - : Promise.$resolve(); - - let promiseCapability = $newPromiseCapability(Promise); - let shouldWait = true; - let handleResolvedPromise = () => { - if (shouldWait) { - shouldWait = false; - return; - } - promiseCapability.resolve.$call(); - }; - let handleRejectedPromise = e => { - promiseCapability.reject.$call(undefined, e); - }; - promiseDestination.$then(handleResolvedPromise, handleRejectedPromise); - promiseSource.$then(handleResolvedPromise, handleRejectedPromise); - return promiseCapability.promise; - }, - reason, - ); - }; - const abortAlgorithmIdentifier = (pipeState.abortAlgorithmIdentifier = $addAbortAlgorithmToSignal( - signal, - algorithm, - )); - - if (!abortAlgorithmIdentifier) return pipeState.promiseCapability.promise; - pipeState.signal = signal; - } - - $pipeToErrorsMustBePropagatedForward(pipeState); - $pipeToErrorsMustBePropagatedBackward(pipeState); - $pipeToClosingMustBePropagatedForward(pipeState); - $pipeToClosingMustBePropagatedBackward(pipeState); - - $pipeToLoop(pipeState); - - return pipeState.promiseCapability.promise; -} - -export function pipeToLoop(pipeState) { - if (pipeState.shuttingDown) return; - - $pipeToDoReadWrite(pipeState).$then(result => { - if (result) $pipeToLoop(pipeState); - }); -} - -export function pipeToDoReadWrite(pipeState) { - $assert(!pipeState.shuttingDown); - - pipeState.pendingReadPromiseCapability = $newPromiseCapability(Promise); - $getByIdDirectPrivate(pipeState.writer, "readyPromise").promise.$then( - () => { - if (pipeState.shuttingDown) { - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, false); - return; - } - - $readableStreamDefaultReaderRead(pipeState.reader).$then( - result => { - const canWrite = !result.done && $getByIdDirectPrivate(pipeState.writer, "stream") !== undefined; - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, canWrite); - if (!canWrite) return; - - pipeState.pendingWritePromise = $writableStreamDefaultWriterWrite(pipeState.writer, result.value).$then( - undefined, - () => {}, - ); - }, - e => { - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, false); - }, - ); - }, - e => { - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, false); - }, - ); - return pipeState.pendingReadPromiseCapability.promise; -} - -export function pipeToErrorsMustBePropagatedForward(pipeState) { - const action = () => { - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, false); - const error = $getByIdDirectPrivate(pipeState.source, "storedError"); - if (!pipeState.preventAbort) { - $pipeToShutdownWithAction(pipeState, () => $writableStreamAbort(pipeState.destination, error), error); - return; - } - $pipeToShutdown(pipeState, error); - }; - - if ($getByIdDirectPrivate(pipeState.source, "state") === $streamErrored) { - action(); - return; - } - - $getByIdDirectPrivate(pipeState.reader, "closedPromiseCapability").promise.$then(undefined, action); -} - -export function pipeToErrorsMustBePropagatedBackward(pipeState) { - const action = () => { - const error = $getByIdDirectPrivate(pipeState.destination, "storedError"); - if (!pipeState.preventCancel) { - $pipeToShutdownWithAction(pipeState, () => $readableStreamCancel(pipeState.source, error), error); - return; - } - $pipeToShutdown(pipeState, error); - }; - if ($getByIdDirectPrivate(pipeState.destination, "state") === "errored") { - action(); - return; - } - $getByIdDirectPrivate(pipeState.writer, "closedPromise").promise.$then(undefined, action); -} - -export function pipeToClosingMustBePropagatedForward(pipeState) { - const action = () => { - pipeState.pendingReadPromiseCapability.resolve.$call(undefined, false); - // const error = $getByIdDirectPrivate(pipeState.source, "storedError"); - if (!pipeState.preventClose) { - $pipeToShutdownWithAction(pipeState, () => - $writableStreamDefaultWriterCloseWithErrorPropagation(pipeState.writer), - ); - return; - } - $pipeToShutdown(pipeState); - }; - if ($getByIdDirectPrivate(pipeState.source, "state") === $streamClosed) { - action(); - return; - } - $getByIdDirectPrivate(pipeState.reader, "closedPromiseCapability").promise.$then(action, () => {}); -} - -export function pipeToClosingMustBePropagatedBackward(pipeState) { - if ( - !$writableStreamCloseQueuedOrInFlight(pipeState.destination) && - $getByIdDirectPrivate(pipeState.destination, "state") !== "closed" - ) - return; - - // $assert no chunks have been read/written - - const error = new TypeError("closing is propagated backward"); - if (!pipeState.preventCancel) { - $pipeToShutdownWithAction(pipeState, () => $readableStreamCancel(pipeState.source, error), error); - return; - } - $pipeToShutdown(pipeState, error); -} - -export function pipeToShutdownWithAction(pipeState, action) { - if (pipeState.shuttingDown) return; - - pipeState.shuttingDown = true; - - const hasError = arguments.length > 2; - const error = arguments[2]; - const finalize = () => { - const promise = action(); - promise.$then( - () => { - if (hasError) $pipeToFinalize(pipeState, error); - else $pipeToFinalize(pipeState); - }, - e => { - $pipeToFinalize(pipeState, e); - }, - ); - }; - - if ( - $getByIdDirectPrivate(pipeState.destination, "state") === "writable" && - !$writableStreamCloseQueuedOrInFlight(pipeState.destination) - ) { - pipeState.pendingReadPromiseCapability.promise.$then( - () => { - pipeState.pendingWritePromise.$then(finalize, finalize); - }, - e => $pipeToFinalize(pipeState, e), - ); - return; - } - - finalize(); -} - -export function pipeToShutdown(pipeState) { - if (pipeState.shuttingDown) return; - - pipeState.shuttingDown = true; - - const hasError = arguments.length > 1; - const error = arguments[1]; - const finalize = () => { - if (hasError) $pipeToFinalize(pipeState, error); - else $pipeToFinalize(pipeState); - }; - - if ( - $getByIdDirectPrivate(pipeState.destination, "state") === "writable" && - !$writableStreamCloseQueuedOrInFlight(pipeState.destination) - ) { - pipeState.pendingReadPromiseCapability.promise.$then( - () => { - pipeState.pendingWritePromise.$then(finalize, finalize); - }, - e => $pipeToFinalize(pipeState, e), - ); - return; - } - finalize(); -} - -export function pipeToFinalize(pipeState) { - $writableStreamDefaultWriterRelease(pipeState.writer); - $readableStreamReaderGenericRelease(pipeState.reader); - - const signal = pipeState.signal; - if (signal) $removeAbortAlgorithmFromSignal(signal, pipeState.abortAlgorithmIdentifier); - - if (arguments.length > 1) pipeState.promiseCapability.reject.$call(undefined, arguments[1]); - else pipeState.promiseCapability.resolve.$call(); -} - -const enum TeeStateFlags { - canceled1 = 1 << 0, - canceled2 = 1 << 1, - reading = 1 << 2, - closedOrErrored = 1 << 3, - readAgain = 1 << 4, -} - -export function readableStreamTee(stream, shouldClone) { - $assert($isReadableStream(stream)); - $assert(typeof shouldClone === "boolean"); - - var start_ = $getByIdDirectPrivate(stream, "start"); - if (start_) { - $putByIdDirectPrivate(stream, "start", undefined); - start_(); - } - - const reader = new $ReadableStreamDefaultReader(stream); - - const teeState = { - stream, - flags: 0, - reason1: undefined, - reason2: undefined, - branch1Source: undefined, - branch2Source: undefined, - branch1: undefined, - branch2: undefined, - cancelPromiseCapability: $newPromiseCapability(Promise), - }; - - const pullFunction = $readableStreamTeePullFunction(teeState, reader, shouldClone); - - const branch1Source = { - $pull: pullFunction, - $cancel: $readableStreamTeeBranch1CancelFunction(teeState, stream), - }; - - const branch2Source = { - $pull: pullFunction, - $cancel: $readableStreamTeeBranch2CancelFunction(teeState, stream), - }; - - const branch1 = new $ReadableStream(branch1Source); - const branch2 = new $ReadableStream(branch2Source); - - $getByIdDirectPrivate(reader, "closedPromiseCapability").promise.$then(undefined, function (e) { - const flags = teeState.flags; - if (flags & TeeStateFlags.closedOrErrored) return; - $readableStreamDefaultControllerError(branch1.$readableStreamController, e); - $readableStreamDefaultControllerError(branch2.$readableStreamController, e); - teeState.flags |= TeeStateFlags.closedOrErrored; - - if (teeState.fllags & (TeeStateFlags.canceled1 | TeeStateFlags.canceled2)) - teeState.cancelPromiseCapability.resolve.$call(); - }); - - // Additional fields compared to the spec, as they are needed within pull/cancel functions. - teeState.branch1 = branch1; - teeState.branch2 = branch2; - - return [branch1, branch2]; -} - -export function readableStreamTeePullFunction(teeState, reader, shouldClone) { - "use strict"; - - const pullAlgorithm = function () { - if (teeState.flags & TeeStateFlags.reading) { - teeState.flags |= TeeStateFlags.readAgain; - return $Promise.$resolve(); - } - teeState.flags |= TeeStateFlags.reading; - $Promise.prototype.$then.$call( - $readableStreamDefaultReaderRead(reader), - function (result) { - $assert($isObject(result)); - $assert(typeof result.done === "boolean"); - const { done, value } = result; - if (done) { - // close steps. - teeState.flags &= ~TeeStateFlags.reading; - if (!(teeState.flags & TeeStateFlags.canceled1)) - $readableStreamDefaultControllerClose(teeState.branch1.$readableStreamController); - if (!(teeState.flags & TeeStateFlags.canceled2)) - $readableStreamDefaultControllerClose(teeState.branch2.$readableStreamController); - if (!(teeState.flags & TeeStateFlags.canceled1) || !(teeState.flags & TeeStateFlags.canceled2)) - teeState.cancelPromiseCapability.resolve.$call(); - return; - } - // chunk steps. - teeState.flags &= ~TeeStateFlags.readAgain; - let chunk1 = value; - let chunk2 = value; - if (!(teeState.flags & TeeStateFlags.canceled2) && shouldClone) { - try { - chunk2 = $structuredCloneForStream(value); - } catch (e) { - $readableStreamDefaultControllerError(teeState.branch1.$readableStreamController, e); - $readableStreamDefaultControllerError(teeState.branch2.$readableStreamController, e); - $readableStreamCancel(teeState.stream, e).$then( - teeState.cancelPromiseCapability.resolve, - teeState.cancelPromiseCapability.reject, - ); - return; - } - } - if (!(teeState.flags & TeeStateFlags.canceled1)) - $readableStreamDefaultControllerEnqueue(teeState.branch1.$readableStreamController, chunk1); - if (!(teeState.flags & TeeStateFlags.canceled2)) - $readableStreamDefaultControllerEnqueue(teeState.branch2.$readableStreamController, chunk2); - teeState.flags &= ~TeeStateFlags.reading; - - $Promise.$resolve().$then(() => { - if (teeState.flags & TeeStateFlags.readAgain) pullAlgorithm(); - }); - }, - () => { - // error steps. - teeState.flags &= ~TeeStateFlags.reading; - }, - ); - return $Promise.$resolve(); - }; - return pullAlgorithm; -} - -export function readableStreamTeeBranch1CancelFunction(teeState, stream) { - return function (r) { - teeState.flags |= TeeStateFlags.canceled1; - teeState.reason1 = r; - if (teeState.flags & TeeStateFlags.canceled2) { - $readableStreamCancel(stream, [teeState.reason1, teeState.reason2]).$then( - teeState.cancelPromiseCapability.resolve, - teeState.cancelPromiseCapability.reject, - ); - } - return teeState.cancelPromiseCapability.promise; - }; -} - -export function readableStreamTeeBranch2CancelFunction(teeState, stream) { - return function (r) { - teeState.flags |= TeeStateFlags.canceled2; - teeState.reason2 = r; - if (teeState.flags & TeeStateFlags.canceled1) { - $readableStreamCancel(stream, [teeState.reason1, teeState.reason2]).$then( - teeState.cancelPromiseCapability.resolve, - teeState.cancelPromiseCapability.reject, - ); - } - return teeState.cancelPromiseCapability.promise; - }; -} - -$alwaysInline = true; -export function isReadableStream(stream) { - // Spec tells to return true only if stream has a readableStreamController internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Therefore, readableStreamController is initialized with null value. - return $isObject(stream) && $getByIdDirectPrivate(stream, "readableStreamController") !== undefined; -} - -$alwaysInline = true; -export function isReadableStreamDefaultReader(reader) { - // Spec tells to return true only if reader has a readRequests internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Since readRequests is initialized with an empty array, the following test is ok. - return $isObject(reader) && !!$getByIdDirectPrivate(reader, "readRequests"); -} - -$alwaysInline = true; -export function isReadableStreamDefaultController(controller) { - // Spec tells to return true only if controller has an underlyingSource internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // underlyingSource is obtained in ReadableStream constructor: if undefined, it is set - // to an empty object. Therefore, following test is ok. - return $isObject(controller) && !!$getByIdDirectPrivate(controller, "underlyingSource"); -} - -export function readDirectStream(stream, sink, underlyingSource) { - $putByIdDirectPrivate(stream, "underlyingSource", undefined); - $putByIdDirectPrivate(stream, "start", undefined); - function close(stream, reason) { - const cancelFn = underlyingSource?.cancel; - if (cancelFn) { - try { - var prom = cancelFn.$call(underlyingSource, reason); - if ($isPromise(prom)) { - $markPromiseAsHandled(prom); - } - } catch (e) {} - - underlyingSource = undefined; - } - - if (stream) { - $putByIdDirectPrivate(stream, "readableStreamController", undefined); - $putByIdDirectPrivate(stream, "reader", undefined); - if (reason) { - $putByIdDirectPrivate(stream, "state", $streamErrored); - $putByIdDirectPrivate(stream, "storedError", reason); - } else { - $putByIdDirectPrivate(stream, "state", $streamClosed); - } - stream = undefined; - } - } - - if (!underlyingSource.pull) { - close(); - return; - } - - if (!$isCallable(underlyingSource.pull)) { - close(); - $throwTypeError("pull is not a function"); - return; - } - $putByIdDirectPrivate(stream, "readableStreamController", sink); - const highWaterMark = $getByIdDirectPrivate(stream, "highWaterMark"); - sink.start({ - highWaterMark: !highWaterMark || highWaterMark < 64 ? 64 : highWaterMark, - }); - - $startDirectStream.$call(sink, stream, underlyingSource.pull, close, stream.$asyncContext); - - $putByIdDirectPrivate(stream, "reader", {}); - - var maybePromise = underlyingSource.pull(sink); - sink = undefined; - if (maybePromise && $isPromise(maybePromise)) { - if (maybePromise.$then) { - return maybePromise.$then(() => {}); - } - - return maybePromise.then(() => {}); - } -} - -$linkTimeConstant; -export function assignToStream(stream, sink) { - // The stream is either a direct stream or a "default" JS stream - var underlyingSource = $getByIdDirectPrivate(stream, "underlyingSource"); - - // we know it's a direct stream when $underlyingSource is set - if (underlyingSource) { - try { - return $readDirectStream(stream, sink, underlyingSource); - } catch (e) { - throw e; - } finally { - underlyingSource = undefined; - stream = undefined; - sink = undefined; - } - } - - return $readStreamIntoSink(stream, sink, true); -} - -export async function readStreamIntoSink(stream, sink, isNative) { - var didClose = false; - var didThrow = false; - var started = false; - const highWaterMark = $getByIdDirectPrivate(stream, "highWaterMark") || 0; - - try { - var reader = stream.getReader(); - var many = reader.readMany(); - function onSinkClose(stream, reason) { - if (!didThrow && !didClose && stream && stream.$state !== $streamClosed) { - $readableStreamCancel(stream, reason); - } - } - - if (many && $isPromise(many)) { - // Some time may pass before this Promise is fulfilled. The sink may - // abort, for example. So we have to start it, if only so that we can - // receive a notification when it closes or cancels. - // https://github.com/oven-sh/bun/issues/6758 - if (isNative) $startDirectStream.$call(sink, stream, undefined, onSinkClose, stream.$asyncContext); - sink.start({ highWaterMark }); - started = true; - - many = await many; - } - if (many.done) { - didClose = true; - return sink.end(); - } - var wroteCount = many.value.length; - - if (!started) { - if (isNative) $startDirectStream.$call(sink, stream, undefined, onSinkClose, stream.$asyncContext); - sink.start({ highWaterMark }); - } - - for (var i = 0, values = many.value, length = many.value.length; i < length; i++) { - sink.write(values[i]); - } - - var streamState = $getByIdDirectPrivate(stream, "state"); - if (streamState === $streamClosed) { - didClose = true; - return sink.end(); - } - - while (true) { - var { value, done } = await reader.read(); - if (done) { - didClose = true; - return sink.end(); - } - - sink.write(value); - } - } catch (e) { - didThrow = true; - - try { - reader = undefined; - const prom = stream.cancel(e); - if ($isPromise(prom)) { - $markPromiseAsHandled(prom); - } - } catch (j) {} - - if (sink && !didClose) { - didClose = true; - try { - sink.close(e); - } catch (j) { - throw new globalThis.AggregateError([e, j]); - } - } - - throw e; - } finally { - if (reader) { - try { - reader.releaseLock(); - } catch (e) {} - reader = undefined; - } - sink = undefined; - var streamState = $getByIdDirectPrivate(stream, "state"); - if (stream) { - // make it easy for this to be GC'd - // but don't do property transitions - var readableStreamController = $getByIdDirectPrivate(stream, "readableStreamController"); - if (readableStreamController) { - if ($getByIdDirectPrivate(readableStreamController, "underlyingSource")) - $putByIdDirectPrivate(readableStreamController, "underlyingSource", undefined); - if ($getByIdDirectPrivate(readableStreamController, "controlledReadableStream")) - $putByIdDirectPrivate(readableStreamController, "controlledReadableStream", undefined); - - $putByIdDirectPrivate(stream, "readableStreamController", null); - if ($getByIdDirectPrivate(stream, "underlyingSource")) - $putByIdDirectPrivate(stream, "underlyingSource", undefined); - readableStreamController = undefined; - } - - if (!didThrow && streamState !== $streamClosed && streamState !== $streamErrored) { - $readableStreamCloseIfPossible(stream); - } - stream = undefined; - } - } -} - -export function handleDirectStreamError(e) { - var controller = this; - var sink = controller.$sink; - if (sink) { - $putByIdDirectPrivate(controller, "sink", undefined); - try { - sink.close(e); - } catch (f) {} - } - - this.error = this.flush = this.write = this.close = this.end = $onReadableStreamDirectControllerClosed; - - if (typeof this.$underlyingSource.close === "function") { - try { - this.$underlyingSource.close.$call(this.$underlyingSource, e); - } catch (e) {} - } - - try { - var pend = controller._pendingRead; - if (pend) { - controller._pendingRead = undefined; - $rejectPromise(pend, e); - } - } catch (f) {} - var stream = controller.$controlledReadableStream; - if (stream) $readableStreamError(stream, e); -} - -export function handleDirectStreamErrorReject(e) { - $handleDirectStreamError.$call(this, e); - return Promise.$reject(e); -} - -export function onPullDirectStream(controller) { - var stream = controller.$controlledReadableStream; - if (!stream || $getByIdDirectPrivate(stream, "state") !== $streamReadable) return; - - // pull is in progress - // this is a recursive call - // ignore it - if (controller._deferClose === -1) { - return; - } - - controller._deferClose = -1; - controller._deferFlush = -1; - var deferClose; - var deferFlush; - - var asyncContext = stream.$asyncContext; - if (asyncContext) { - var prev = $getInternalField($asyncContext, 0); - $putInternalField($asyncContext, 0, asyncContext); - } - - // Direct streams allow $pull to be called multiple times, unlike the spec. - // Backpressure is handled by the destination, not by the underlying source. - // In this case, we rely on the heuristic that repeatedly draining in the same tick - // is bad for performance - // this code is only run when consuming a direct stream from JS - // without the HTTP server or anything else - try { - var result = controller.$underlyingSource.pull(controller); - - if (result && $isPromise(result)) { - if (controller._handleError === undefined) { - controller._handleError = $handleDirectStreamErrorReject.bind(controller); - } - - Promise.prototype.catch.$call(result, controller._handleError); - } - } catch (e) { - return $handleDirectStreamErrorReject.$call(controller, e); - } finally { - deferClose = controller._deferClose; - deferFlush = controller._deferFlush; - controller._deferFlush = controller._deferClose = 0; - - if (asyncContext) { - $putInternalField($asyncContext, 0, prev); - } - } - - var promiseToReturn; - - if (controller._pendingRead === undefined) { - controller._pendingRead = promiseToReturn = $newPromise(); - } else { - promiseToReturn = $readableStreamAddReadRequest(stream); - } - - // they called close during $pull() - // we delay that - if (deferClose === 1) { - var reason = controller._deferCloseReason; - controller._deferCloseReason = undefined; - $onCloseDirectStream.$call(controller, reason); - return promiseToReturn; - } - - // not done, but they called flush() - if (deferFlush === 1) { - $onFlushDirectStream.$call(controller); - } - - return promiseToReturn; -} - -export function noopDoneFunction() { - return Promise.$resolve({ value: undefined, done: true }); -} - -export function onReadableStreamDirectControllerClosed(reason) { - $throwTypeError("ReadableStreamDirectController is now closed"); -} - -export function tryUseReadableStreamBufferedFastPath(stream, method) { - // -- Fast path for Blob.prototype.stream(), fetch body streams, and incoming Request body streams -- - const ptr = stream.$bunNativePtr; - if ( - // only available on native streams - ptr && - // don't even attempt it if the stream was used in some way - !$isReadableStreamDisturbed(stream) && - // feature-detect if supported - $isCallable(ptr[method]) - ) { - const promise = ptr[method](); - // if it throws, let it throw without setting $disturbed - stream.$disturbed = true; - - // Clear the lazy load function. - $putByIdDirectPrivate(stream, "start", undefined); - $putByIdDirectPrivate(stream, "reader", {}); - - if (Bun.peek.status(promise) === "fulfilled") { - stream.$reader = undefined; - $readableStreamCloseIfPossible(stream); - return promise; - } - - return promise - .catch(e => { - stream.$reader = undefined; - $readableStreamCancel(stream, e); - return Promise.$reject(e); - }) - .finally(() => { - stream.$reader = undefined; - $readableStreamCloseIfPossible(stream); - }); - } -} - -export function onCloseDirectStream(reason) { - var stream = this.$controlledReadableStream; - if (!stream || $getByIdDirectPrivate(stream, "state") !== $streamReadable) return; - - if (this._deferClose !== 0) { - this._deferClose = 1; - this._deferCloseReason = reason; - return; - } - - $putByIdDirectPrivate(stream, "state", $streamClosing); - if (typeof this.$underlyingSource.close === "function") { - try { - this.$underlyingSource.close.$call(this.$underlyingSource, reason); - } catch (e) {} - } - - var flushed; - try { - flushed = this.$sink.end(); - $putByIdDirectPrivate(this, "sink", undefined); - } catch (e) { - if (this._pendingRead) { - var read = this._pendingRead; - this._pendingRead = undefined; - $rejectPromise(read, e); - } else { - throw e; - } - - return; - } - - this.error = this.flush = this.write = this.close = this.end = $onReadableStreamDirectControllerClosed; - - var reader = $getByIdDirectPrivate(stream, "reader"); - - if (reader && $isReadableStreamDefaultReader(reader)) { - var _pendingRead = this._pendingRead; - if (_pendingRead && $isPromise(_pendingRead) && flushed?.byteLength) { - this._pendingRead = undefined; - $fulfillPromise(_pendingRead, { value: flushed, done: false }); - $readableStreamCloseIfPossible(stream); - return; - } - } - - if (flushed?.byteLength) { - var requests = $getByIdDirectPrivate(reader, "readRequests"); - if (requests?.isNotEmpty()) { - $readableStreamFulfillReadRequest(stream, flushed, false); - $readableStreamCloseIfPossible(stream); - return; - } - - $putByIdDirectPrivate(stream, "state", $streamReadable); - this.$pull = () => { - var thisResult = $createFulfilledPromise({ - value: flushed, - done: false, - }); - flushed = undefined; - $readableStreamCloseIfPossible(stream); - stream = undefined; - return thisResult; - }; - } else if (this._pendingRead) { - var read = this._pendingRead; - this._pendingRead = undefined; - $putByIdDirectPrivate(this, "pull", $noopDoneFunction); - $fulfillPromise(read, { value: undefined, done: true }); - } - - $readableStreamCloseIfPossible(stream); -} - -export function onFlushDirectStream() { - var stream = this.$controlledReadableStream; - var reader = $getByIdDirectPrivate(stream, "reader"); - if (!reader || !$isReadableStreamDefaultReader(reader)) { - return; - } - - var _pendingRead = this._pendingRead; - this._pendingRead = undefined; - if (_pendingRead && $isPromise(_pendingRead)) { - var flushed = this.$sink.flush(); - if (flushed?.byteLength) { - this._pendingRead = $getByIdDirectPrivate(stream, "readRequests")?.shift(); - $fulfillPromise(_pendingRead, { value: flushed, done: false }); - } else { - this._pendingRead = _pendingRead; - } - } else if ($getByIdDirectPrivate(stream, "readRequests")?.isNotEmpty()) { - var flushed = this.$sink.flush(); - if (flushed?.byteLength) { - $readableStreamFulfillReadRequest(stream, flushed, false); - } - } else if (this._deferFlush === -1) { - this._deferFlush = 1; - } -} - -export function createTextStream(highWaterMark) { - var sink; - var array = []; - var hasString = false; - var hasBuffer = false; - var rope = ""; - var estimatedLength = $toLength(0); - var capability = $newPromiseCapability(Promise); - var calledDone = false; - - sink = { - start() {}, - write(chunk) { - if (typeof chunk === "string") { - var chunkLength = $toLength(chunk.length); - if (chunkLength > 0) { - rope += chunk; - hasString = true; - // TODO: utf16 byte length - estimatedLength += chunkLength; - } - - return chunkLength; - } - - if (!chunk || !($ArrayBuffer.$isView(chunk) || chunk instanceof $ArrayBuffer)) { - $throwTypeError("Expected text, ArrayBuffer or ArrayBufferView"); - } - - const byteLength = $toLength(chunk.byteLength); - if (byteLength > 0) { - hasBuffer = true; - if (rope.length > 0) { - $arrayPush(array, rope); - $arrayPush(array, chunk); - rope = ""; - } else { - $arrayPush(array, chunk); - } - } - estimatedLength += byteLength; - return byteLength; - }, - - flush() { - return 0; - }, - - end() { - if (calledDone) { - return ""; - } - return sink.fulfill(); - }, - - fulfill() { - calledDone = true; - const result = sink.finishInternal(); - - $fulfillPromise(capability.promise, result); - return result; - }, - - finishInternal() { - if (!hasString && !hasBuffer) { - return ""; - } - - if (hasString && !hasBuffer) { - if (rope.charCodeAt(0) === 0xfeff) { - rope = rope.slice(1); - } - - return rope; - } - - if (hasBuffer && !hasString) { - return new globalThis.TextDecoder("utf-8", { ignoreBOM: true }).decode(Bun.concatArrayBuffers(array)); - } - - // worst case: mixed content - - var arrayBufferSink = new Bun.ArrayBufferSink(); - arrayBufferSink.start({ - highWaterMark: estimatedLength, - asUint8Array: true, - }); - for (let item of array) { - arrayBufferSink.write(item); - } - array.length = 0; - if (rope.length > 0) { - if (rope.charCodeAt(0) === 0xfeff) { - rope = rope.slice(1); - } - - arrayBufferSink.write(rope); - rope = ""; - } - - // TODO: use builtin - return new globalThis.TextDecoder("utf-8", { ignoreBOM: true }).decode(arrayBufferSink.end()); - }, - - close() { - try { - if (!calledDone) { - calledDone = true; - sink.fulfill(); - } - } catch (e) {} - }, - }; - - return [sink, capability]; -} - -export function initializeTextStream(underlyingSource, highWaterMark) { - var [sink, closingPromise] = $createTextStream(highWaterMark); - - var controller = { - $underlyingSource: underlyingSource, - $pull: $onPullDirectStream, - $controlledReadableStream: this, - $sink: sink, - close: $onCloseDirectStream, - write: sink.write, - error: $handleDirectStreamError, - end: $onCloseDirectStream, - $close: $onCloseDirectStream, - flush: $onFlushDirectStream, - _pendingRead: undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: undefined, - _handleError: undefined, - }; - - $putByIdDirectPrivate(this, "readableStreamController", controller); - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $putByIdDirectPrivate(this, "start", undefined); - return closingPromise; -} - -export function initializeArrayStream(underlyingSource, highWaterMark) { - var array = []; - var closingPromise = $newPromiseCapability(Promise); - var calledDone = false; - - function fulfill() { - calledDone = true; - closingPromise.resolve.$call(undefined, array); - return array; - } - - var sink = { - start() {}, - write(chunk) { - $arrayPush(array, chunk); - return chunk.byteLength || chunk.length; - }, - - flush() { - return 0; - }, - - end() { - if (calledDone) { - return []; - } - return fulfill(); - }, - - close() { - if (!calledDone) { - fulfill(); - } - }, - }; - - var controller = { - $underlyingSource: underlyingSource, - $pull: $onPullDirectStream, - $controlledReadableStream: this, - $sink: sink, - close: $onCloseDirectStream, - write: sink.write, - error: $handleDirectStreamError, - end: $onCloseDirectStream, - $close: $onCloseDirectStream, - flush: $onFlushDirectStream, - _pendingRead: undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: undefined, - _handleError: undefined, - }; - - $putByIdDirectPrivate(this, "readableStreamController", controller); - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $putByIdDirectPrivate(this, "start", undefined); - return closingPromise; -} - -export function initializeArrayBufferStream(underlyingSource, highWaterMark) { - // This is the fallback implementation for direct streams - // When we don't know what the destination type is - // We assume it is a Uint8Array. - - var opts = - highWaterMark && typeof highWaterMark === "number" - ? { highWaterMark, stream: true, asUint8Array: true } - : { stream: true, asUint8Array: true }; - var sink = new Bun.ArrayBufferSink(); - sink.start(opts); - - var controller = { - $underlyingSource: underlyingSource, - $pull: $onPullDirectStream, - $controlledReadableStream: this, - $sink: sink, - close: $onCloseDirectStream, - write: sink.write.bind(sink), - error: $handleDirectStreamError, - end: $onCloseDirectStream, - $close: $onCloseDirectStream, - flush: $onFlushDirectStream, - _pendingRead: undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: undefined, - _handleError: undefined, - }; - - $putByIdDirectPrivate(this, "readableStreamController", controller); - $putByIdDirectPrivate(this, "underlyingSource", undefined); - $putByIdDirectPrivate(this, "start", undefined); -} - -export function readableStreamError(stream, error) { - $assert($isReadableStream(stream)); - $putByIdDirectPrivate(stream, "state", $streamErrored); - $putByIdDirectPrivate(stream, "storedError", error); - const reader = $getByIdDirectPrivate(stream, "reader"); - - if (!reader) return; - - $getByIdDirectPrivate(reader, "closedPromiseCapability").reject.$call(undefined, error); - const promise = $getByIdDirectPrivate(reader, "closedPromiseCapability").promise; - $markPromiseAsHandled(promise); - - if ($isReadableStreamDefaultReader(reader)) { - $readableStreamDefaultReaderErrorReadRequests(reader, error); - } else { - $assert($isReadableStreamBYOBReader(reader)); - const requests = $getByIdDirectPrivate(reader, "readIntoRequests"); - $putByIdDirectPrivate(reader, "readIntoRequests", $createFIFO()); - for (var request = requests.shift(); request; request = requests.shift()) $rejectPromise(request, error); - } -} - -export function readableStreamDefaultControllerShouldCallPull(controller) { - if (!$readableStreamDefaultControllerCanCloseOrEnqueue(controller)) return false; - if (!($getByIdDirectPrivate(controller, "started") === 1)) return false; - - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - - if ( - (!$isReadableStreamLocked(stream) || - !$getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) && - $readableStreamDefaultControllerGetDesiredSize(controller) <= 0 - ) - return false; - const desiredSize = $readableStreamDefaultControllerGetDesiredSize(controller); - $assert(desiredSize !== null); - return desiredSize > 0; -} - -export function readableStreamDefaultControllerCallPullIfNeeded(controller) { - // FIXME: use $readableStreamDefaultControllerShouldCallPull - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (!$readableStreamDefaultControllerCanCloseOrEnqueue(controller)) return; - if (!($getByIdDirectPrivate(controller, "started") === 1)) return; - if ( - (!$isReadableStreamLocked(stream) || - !$getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) && - $readableStreamDefaultControllerGetDesiredSize(controller) <= 0 - ) - return; - - if ($getByIdDirectPrivate(controller, "pulling")) { - $putByIdDirectPrivate(controller, "pullAgain", true); - return; - } - - $assert(!$getByIdDirectPrivate(controller, "pullAgain")); - $putByIdDirectPrivate(controller, "pulling", true); - $getByIdDirectPrivate(controller, "pullAlgorithm") - .$call(undefined) - .$then( - function () { - $putByIdDirectPrivate(controller, "pulling", false); - if ($getByIdDirectPrivate(controller, "pullAgain")) { - $putByIdDirectPrivate(controller, "pullAgain", false); - - $readableStreamDefaultControllerCallPullIfNeeded(controller); - } - }, - function (error) { - $readableStreamDefaultControllerError(controller, error); - }, - ); -} - -$alwaysInline = true; -export function isReadableStreamLocked(stream) { - $assert($isReadableStream(stream)); - return ( - // Case 1. Is there a reader actively using it? - !!$getByIdDirectPrivate(stream, "reader") || - // Case 2. Has the native reader been released? - // Case 3. Has it been converted into a Node.js NativeReadable? - stream.$bunNativePtr === -1 - ); -} - -export function readableStreamDefaultControllerGetDesiredSize(controller) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - const state = $getByIdDirectPrivate(stream, "state"); - - if (state === $streamErrored) return null; - if (state === $streamClosed) return 0; - - return $getByIdDirectPrivate(controller, "strategy").highWaterMark - $getByIdDirectPrivate(controller, "queue").size; -} - -$alwaysInline = true; -export function readableStreamReaderGenericCancel(reader, reason) { - const stream = $getByIdDirectPrivate(reader, "ownerReadableStream"); - $assert(!!stream); - return $readableStreamCancel(stream, reason); -} - -export function readableStreamCancel(stream, reason) { - stream.$disturbed = true; - const state = $getByIdDirectPrivate(stream, "state"); - if (state === $streamClosed) return Promise.$resolve(); - if (state === $streamErrored) return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - $readableStreamClose(stream); - - const controller = $getByIdDirectPrivate(stream, "readableStreamController"); - if (controller === null) return Promise.$resolve(); - - const cancel = controller.$cancel; - if (cancel) return cancel(controller, reason).$then(function () {}); - - const close = controller.close; - if (close) return Promise.$resolve(controller.close(reason)); - - $throwTypeError("ReadableStreamController has no cancel or close method"); -} - -$alwaysInline = true; -export function readableStreamDefaultControllerCancel(controller, reason) { - $putByIdDirectPrivate(controller, "queue", $newQueue()); - return $getByIdDirectPrivate(controller, "cancelAlgorithm").$call(undefined, reason); -} - -export function readableStreamDefaultControllerPull(controller) { - var queue = $getByIdDirectPrivate(controller, "queue"); - if (queue.content.isNotEmpty()) { - const chunk = $dequeueValue(queue); - if ($getByIdDirectPrivate(controller, "closeRequested") && queue.content.isEmpty()) { - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); - } else $readableStreamDefaultControllerCallPullIfNeeded(controller); - - return $createFulfilledPromise({ value: chunk, done: false }); - } - const pendingPromise = $readableStreamAddReadRequest($getByIdDirectPrivate(controller, "controlledReadableStream")); - $readableStreamDefaultControllerCallPullIfNeeded(controller); - return pendingPromise; -} - -export function readableStreamDefaultControllerClose(controller) { - $assert($readableStreamDefaultControllerCanCloseOrEnqueue(controller)); - $putByIdDirectPrivate(controller, "closeRequested", true); - if ($getByIdDirectPrivate(controller, "queue")?.content?.isEmpty()) { - $readableStreamCloseIfPossible($getByIdDirectPrivate(controller, "controlledReadableStream")); - } -} - -export function readableStreamCloseIfPossible(stream) { - switch ($getByIdDirectPrivate(stream, "state")) { - case $streamReadable: - case $streamClosing: { - $readableStreamClose(stream); - break; - } - } -} - -export function readableStreamClose(stream) { - $assert( - $getByIdDirectPrivate(stream, "state") === $streamReadable || - $getByIdDirectPrivate(stream, "state") === $streamClosing, - ); - $putByIdDirectPrivate(stream, "state", $streamClosed); - const reader = $getByIdDirectPrivate(stream, "reader"); - if (!reader) return; - - if ($isReadableStreamDefaultReader(reader)) { - const requests = $getByIdDirectPrivate(reader, "readRequests"); - if (requests.isNotEmpty()) { - $putByIdDirectPrivate(reader, "readRequests", $createFIFO()); - - for (var request = requests.shift(); request; request = requests.shift()) - $fulfillPromise(request, { value: undefined, done: true }); - } - } - - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "closedPromiseCapability").resolve.$call(); -} - -export function readableStreamFulfillReadRequest(stream, chunk, done) { - const readRequest = $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests").shift(); - $fulfillPromise(readRequest, { value: chunk, done: done }); -} - -export function readableStreamDefaultControllerEnqueue(controller, chunk) { - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - // this is checked by callers - $assert($readableStreamDefaultControllerCanCloseOrEnqueue(controller)); - - if ( - $isReadableStreamLocked(stream) && - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty() - ) { - $readableStreamFulfillReadRequest(stream, chunk, false); - $readableStreamDefaultControllerCallPullIfNeeded(controller); - return; - } - - try { - let chunkSize = 1; - if ($getByIdDirectPrivate(controller, "strategy").size !== undefined) - chunkSize = $getByIdDirectPrivate(controller, "strategy").size(chunk); - $enqueueValueWithSize($getByIdDirectPrivate(controller, "queue"), chunk, chunkSize); - } catch (error) { - $readableStreamDefaultControllerError(controller, error); - throw error; - } - $readableStreamDefaultControllerCallPullIfNeeded(controller); -} - -export function readableStreamDefaultReaderRead(reader) { - const stream = $getByIdDirectPrivate(reader, "ownerReadableStream"); - $assert(!!stream); - const state = $getByIdDirectPrivate(stream, "state"); - - stream.$disturbed = true; - if (state === $streamClosed) return $createFulfilledPromise({ value: undefined, done: true }); - if (state === $streamErrored) return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - $assert(state === $streamReadable); - - return $getByIdDirectPrivate(stream, "readableStreamController").$pull( - $getByIdDirectPrivate(stream, "readableStreamController"), - ); -} - -export function readableStreamAddReadRequest(stream) { - $assert($isReadableStreamDefaultReader($getByIdDirectPrivate(stream, "reader"))); - $assert($getByIdDirectPrivate(stream, "state") == $streamReadable); - - const readRequest = $newPromise(); - - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "reader"), "readRequests").push(readRequest); - - return readRequest; -} - -export function isReadableStreamDisturbed(stream) { - $assert($isReadableStream(stream)); - return stream.$disturbed; -} - -$visibility = "Private"; -export function readableStreamDefaultReaderRelease(reader) { - $readableStreamReaderGenericRelease(reader); - $readableStreamDefaultReaderErrorReadRequests( - reader, - $ERR_STREAM_RELEASE_LOCK("Stream reader cancelled via releaseLock()"), - ); -} - -$visibility = "Private"; -export function readableStreamReaderGenericRelease(reader) { - $assert(!!$getByIdDirectPrivate(reader, "ownerReadableStream")); - $assert($getByIdDirectPrivate($getByIdDirectPrivate(reader, "ownerReadableStream"), "reader") === reader); - - if ($getByIdDirectPrivate($getByIdDirectPrivate(reader, "ownerReadableStream"), "state") === $streamReadable) - $getByIdDirectPrivate(reader, "closedPromiseCapability").reject.$call( - undefined, - $ERR_STREAM_RELEASE_LOCK("Stream reader cancelled via releaseLock()"), - ); - else - $putByIdDirectPrivate(reader, "closedPromiseCapability", { - promise: $newHandledRejectedPromise($ERR_STREAM_RELEASE_LOCK("Stream reader cancelled via releaseLock()")), - }); - - const promise = $getByIdDirectPrivate(reader, "closedPromiseCapability").promise; - $markPromiseAsHandled(promise); - - var stream = $getByIdDirectPrivate(reader, "ownerReadableStream"); - if (stream.$bunNativePtr) { - $getByIdDirectPrivate($getByIdDirectPrivate(stream, "readableStreamController"), "underlyingByteSource").$resume( - false, - ); - } - $putByIdDirectPrivate(stream, "reader", undefined); - $putByIdDirectPrivate(reader, "ownerReadableStream", undefined); -} - -export function readableStreamDefaultReaderErrorReadRequests(reader, error) { - const requests = $getByIdDirectPrivate(reader, "readRequests"); - $putByIdDirectPrivate(reader, "readRequests", $createFIFO()); - for (var request = requests.shift(); request; request = requests.shift()) $rejectPromise(request, error); -} - -export function readableStreamDefaultControllerCanCloseOrEnqueue(controller) { - if ($getByIdDirectPrivate(controller, "closeRequested")) { - return false; - } - - const controlledReadableStream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (!$isObject(controlledReadableStream)) { - return false; - } - - return $getByIdDirectPrivate(controlledReadableStream, "state") === $streamReadable; -} - -export function readableStreamFromAsyncIterator(target, fn) { - var cancelled = false, - iter: AsyncIterator; - - // We must eagerly start the async generator to ensure that it works if objects are reused later. - // This impacts Astro, amongst others. - iter = fn.$call(target); - fn = target = undefined; - - if (!$isAsyncGenerator(iter) && typeof iter.next !== "function") { - throw new TypeError("Expected an async generator"); - } - - return new ReadableStream({ - type: "direct", - - cancel(reason) { - $debug("readableStreamFromAsyncIterator.cancel", reason); - cancelled = true; - - if (iter) { - const thisIter = iter; - iter = undefined; - if (reason) { - // We return the value so that the caller can await it. - return thisIter.throw?.(reason); - } else { - // undefined === Abort. - // - // We don't want to throw here because it will almost - // inevitably become an uncatchable exception. So instead, we call the - // synthetic return method if it exists to signal that the stream is - // done. - return thisIter?.return?.(); - } - } - }, - - close() { - cancelled = true; - }, - - async pull(controller) { - var closingError, value, done, immediateTask; - - try { - while (!cancelled && !done) { - const promise = iter.next(controller); - - if (cancelled) { - return; - } - - if ($isPromise(promise) && $isPromiseResolved(promise)) { - clearImmediate(immediateTask); - ({ value, done } = $getPromiseInternalField(promise, $promiseFieldReactionsOrResult)); - $assert(!$isPromise(value), "Expected a value, not a promise"); - } else { - immediateTask = setImmediate(() => immediateTask && controller?.flush?.(true)); - ({ value, done } = await promise); - - if (cancelled) { - return; - } - } - - if (!$isUndefinedOrNull(value)) { - controller.write(value); - } - } - } catch (e) { - closingError = e; - } finally { - clearImmediate(immediateTask); - immediateTask = undefined; - // "iter" will be undefined if the stream was closed above. - - // Stream was closed before we tried writing to it. - if (closingError?.code === "ERR_INVALID_THIS") { - await iter?.return?.(); - return; - } - - if (closingError) { - try { - await iter.throw?.(closingError); - } finally { - iter = undefined; - throw closingError; - } - } else { - await controller.end(); - if (iter) { - await iter.return?.(); - } - } - iter = undefined; - } - }, - }); -} - -export function lazyLoadStream(stream, autoAllocateChunkSize) { - $debug("lazyLoadStream", stream, autoAllocateChunkSize); - var handle = stream.$bunNativePtr; - if (handle === -1) return; - var Prototype = $lazyStreamPrototypeMap.$get($getPrototypeOf(handle)); - if (Prototype === undefined) { - var closer = [false]; - var handleResult; - function handleNativeReadableStreamPromiseResult(val) { - var { c, v } = this; - this.c = undefined; - this.v = undefined; - handleResult(val, c, v); - } - - function callClose(controller) { - try { - var underlyingByteSource = controller.$underlyingByteSource; - const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - if (!stream) { - return; - } - - if ($getByIdDirectPrivate(stream, "state") !== $streamReadable) return; - controller.close(); - } catch (e) { - globalThis.reportError(e); - } finally { - if (underlyingByteSource?.$stream) { - underlyingByteSource.$stream = undefined; - } - } - } - - handleResult = function handleResult(result, controller, view) { - $assert(controller, "controller is missing"); - - if (result && $isPromise(result)) { - return result.$then( - handleNativeReadableStreamPromiseResult.bind({ - c: controller, - v: view, - }), - err => controller.error(err), - ); - } else if (typeof result === "number") { - if (view && view.byteLength === result && view.buffer === controller?.byobRequest?.view?.buffer) { - controller.byobRequest.respondWithNewView(view); - } else { - controller.byobRequest.respond(result); - } - } else if ($isTypedArrayView(result)) { - controller.enqueue(result); - } - - if (closer[0] || result === false) { - $enqueueJob(callClose, controller); - closer[0] = false; - } - }; - - function createResult(handle, controller, view, closer) { - closer[0] = false; - - var result; - try { - result = handle.pull(view, closer); - } catch (err) { - return controller.error(err); - } - - return handleResult(result, controller, view); - } - - Prototype = class NativeReadableStreamSource { - constructor(handle, autoAllocateChunkSize, drainValue) { - $putByIdDirectPrivate(this, "stream", handle); - this.pull = this.#pull.bind(this); - this.cancel = this.#cancel.bind(this); - this.autoAllocateChunkSize = autoAllocateChunkSize; - - if (drainValue !== undefined) { - this.start = controller => { - this.#controller = new WeakRef(controller); - controller.enqueue(drainValue); - }; - } - - handle.onClose = this.#onClose.bind(this); - handle.onDrain = this.#onDrain.bind(this); - } - - #onDrain(chunk) { - var controller = this.#controller?.deref?.(); - if (controller) { - controller.enqueue(chunk); - } - } - - #controller: WeakRef; - - pull; - cancel; - start; - - type = "bytes"; - autoAllocateChunkSize = 0; - #closed = false; - - #onClose() { - this.#closed = true; - this.#controller = undefined; - - var controller = this.#controller?.deref?.(); - - $putByIdDirectPrivate(this, "stream", undefined); - if (controller) { - $enqueueJob(callClose, controller); - } - } - - #pull(controller) { - var handle = $getByIdDirectPrivate(this, "stream"); - - if (!handle || this.#closed) { - this.#controller = undefined; - $putByIdDirectPrivate(this, "stream", undefined); - $enqueueJob(callClose, controller); - return; - } - - if (!this.#controller) { - this.#controller = new WeakRef(controller); - } - - createResult(handle, controller, controller.byobRequest.view, closer); - } - - #cancel(reason) { - var handle = $getByIdDirectPrivate(this, "stream"); - if (handle) { - handle.updateRef(false); - handle.cancel(reason); - $putByIdDirectPrivate(this, "stream", undefined); - } - } - }; - // this is reuse of an existing private symbol - Prototype.prototype.$resume = function (has_ref) { - var handle = $getByIdDirectPrivate(this, "stream"); - if (handle) handle.updateRef(has_ref); - }; - $lazyStreamPrototypeMap.$set($getPrototypeOf(handle), Prototype); - } - - stream.$disturbed = true; - const chunkSizeOrCompleteBuffer = handle.start(autoAllocateChunkSize); - let chunkSize, drainValue; - if ($isTypedArrayView(chunkSizeOrCompleteBuffer)) { - chunkSize = 0; - drainValue = chunkSizeOrCompleteBuffer; - } else { - chunkSize = chunkSizeOrCompleteBuffer; - drainValue = handle.drain(); - } - - // empty file, no need for native back-and-forth on this - if (chunkSize === 0) { - if ((drainValue?.byteLength ?? 0) > 0) { - return { - start(controller) { - controller.enqueue(drainValue); - controller.close(); - }, - pull(controller) { - controller.close(); - }, - type: "bytes", - }; - } - - return { - start(controller) { - controller.close(); - }, - pull(controller) { - controller.close(); - }, - type: "bytes", - }; - } - - return new Prototype(handle, chunkSize, drainValue); -} - -export function readableStreamIntoArray(stream) { - var reader = stream.getReader(); - var manyResult = reader.readMany(); - - async function processManyResult(result) { - let { done, value } = result; - var chunks = value || []; - - while (!done) { - var thisResult = reader.readMany(); - if ($isPromise(thisResult)) { - thisResult = await thisResult; - } - - ({ done, value = [] } = thisResult); - const length = value.length || 0; - if (length > 1) { - chunks = chunks.concat(value); - } else if (length === 1) { - chunks.push(value[0]); - } - } - - return chunks; - } - - if (manyResult && $isPromise(manyResult)) { - return manyResult.$then(processManyResult); - } - - return processManyResult(manyResult); -} - -export function withoutUTF8BOM(result) { - if (result.charCodeAt(0) === 0xfeff) { - return result.slice(1); - } - - return result; -} - -export function readableStreamIntoText(stream) { - const [textStream, closer] = $createTextStream($getByIdDirectPrivate(stream, "highWaterMark")); - const prom = $readStreamIntoSink(stream, textStream, false); - - if (prom && $isPromise(prom)) { - return Promise.$resolve(prom).$then(closer.promise).$then($withoutUTF8BOM); - } - - return closer.promise.$then($withoutUTF8BOM); -} - -export function readableStreamToArrayBufferDirect(stream, underlyingSource, asUint8Array) { - var sink = new Bun.ArrayBufferSink(); - $putByIdDirectPrivate(stream, "underlyingSource", undefined); - var highWaterMark = $getByIdDirectPrivate(stream, "highWaterMark"); - sink.start({ highWaterMark, asUint8Array }); - var capability = $newPromiseCapability(Promise); - var ended = false; - var pull = underlyingSource.pull; - var close = underlyingSource.close; - - var controller = { - start() {}, - close(reason) { - if (!ended) { - ended = true; - if (close) { - close(); - } - - $fulfillPromise(capability.promise, sink.end()); - } - }, - end() { - if (!ended) { - ended = true; - if (close) { - close(); - } - $fulfillPromise(capability.promise, sink.end()); - } - }, - flush() { - return 0; - }, - write: sink.write.bind(sink), - }; - - var didError = false; - try { - var firstPull = pull(controller); - } catch (e) { - didError = true; - $readableStreamError(stream, e); - return Promise.$reject(e); - } finally { - if (!$isPromise(firstPull)) { - if (!didError && stream) $readableStreamCloseIfPossible(stream); - controller = close = sink = pull = stream = undefined; - return capability.promise; - } - } - - $assert($isPromise(firstPull)); - return firstPull.then( - () => { - if (!didError && stream) $readableStreamCloseIfPossible(stream); - controller = close = sink = pull = stream = undefined; - return capability.promise; - }, - e => { - didError = true; - if ($getByIdDirectPrivate(stream, "state") === $streamReadable) $readableStreamError(stream, e); - return Promise.$reject(e); - }, - ); -} - -export async function readableStreamToTextDirect(stream, underlyingSource) { - const capability = $initializeTextStream.$call(stream, underlyingSource, undefined); - var reader = stream.getReader(); - - while ($getByIdDirectPrivate(stream, "state") === $streamReadable) { - var thisResult = await reader.read(); - if (thisResult.done) { - break; - } - } - - try { - reader.releaseLock(); - } catch (e) {} - reader = undefined; - stream = undefined; - - return capability.promise; -} - -export async function readableStreamToArrayDirect(stream, underlyingSource) { - const capability = $initializeArrayStream.$call(stream, underlyingSource, undefined); - underlyingSource = undefined; - var reader = stream.getReader(); - try { - while ($getByIdDirectPrivate(stream, "state") === $streamReadable) { - var thisResult = await reader.read(); - if (thisResult.done) { - break; - } - } - - try { - reader.releaseLock(); - } catch (e) {} - reader = undefined; - - return Promise.$resolve(capability.promise); - } catch (e) { - throw e; - } finally { - stream = undefined; - reader = undefined; - } -} - -export function readableStreamDefineLazyIterators(prototype) { - var asyncIterator = globalThis.Symbol.asyncIterator; - - var ReadableStreamAsyncIterator = async function* ReadableStreamAsyncIterator(stream, preventCancel) { - var reader = stream.getReader(); - var deferredError; - try { - while (true) { - var done, value; - const firstResult = reader.readMany(); - if ($isPromise(firstResult)) { - ({ done, value } = await firstResult); - } else { - ({ done, value } = firstResult); - } - - if (done) { - return; - } - yield* value; - } - } catch (e) { - deferredError = e; - } finally { - reader.releaseLock(); - - if (!preventCancel && !$isReadableStreamLocked(stream)) { - const promise = stream.cancel(deferredError); - if (Bun.peek.status(promise) === "rejected") { - $markPromiseAsHandled(promise); - } - } - - if (deferredError) { - throw deferredError; - } - } - }; - var createAsyncIterator = function asyncIterator() { - return ReadableStreamAsyncIterator(this, false); - }; - var createValues = function values({ preventCancel = false } = { preventCancel: false }) { - return ReadableStreamAsyncIterator(this, preventCancel); - }; - $Object.$defineProperty(prototype, asyncIterator, { value: createAsyncIterator }); - $Object.$defineProperty(prototype, "values", { value: createValues }); - return prototype; -} diff --git a/src/js/builtins/TransformStream.ts b/src/js/builtins/TransformStream.ts deleted file mode 100644 index f9d80b7cbddd92..00000000000000 --- a/src/js/builtins/TransformStream.ts +++ /dev/null @@ -1,107 +0,0 @@ -// @ts-nocheck -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeTransformStream(this) { - let transformer = arguments[0]; - - // This is the path for CreateTransformStream. - if ($isObject(transformer) && $getByIdDirectPrivate(transformer, "TransformStream")) return this; - - let writableStrategy = arguments[1]; - let readableStrategy = arguments[2]; - - if (transformer === undefined) transformer = null; - - if (readableStrategy === undefined) readableStrategy = {}; - - if (writableStrategy === undefined) writableStrategy = {}; - - let transformerDict = {}; - if (transformer !== null) { - if ("start" in transformer) { - transformerDict["start"] = transformer["start"]; - if (typeof transformerDict["start"] !== "function") $throwTypeError("transformer.start should be a function"); - } - if ("transform" in transformer) { - transformerDict["transform"] = transformer["transform"]; - if (typeof transformerDict["transform"] !== "function") - $throwTypeError("transformer.transform should be a function"); - } - if ("flush" in transformer) { - transformerDict["flush"] = transformer["flush"]; - if (typeof transformerDict["flush"] !== "function") $throwTypeError("transformer.flush should be a function"); - } - - if ("readableType" in transformer) throw new RangeError("TransformStream transformer has a readableType"); - if ("writableType" in transformer) throw new RangeError("TransformStream transformer has a writableType"); - } - - const readableHighWaterMark = $extractHighWaterMark(readableStrategy, 0); - const readableSizeAlgorithm = $extractSizeAlgorithm(readableStrategy); - - const writableHighWaterMark = $extractHighWaterMark(writableStrategy, 1); - const writableSizeAlgorithm = $extractSizeAlgorithm(writableStrategy); - - const startPromiseCapability = $newPromiseCapability(Promise); - $initializeTransformStream( - this, - startPromiseCapability.promise, - writableHighWaterMark, - writableSizeAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, - ); - $setUpTransformStreamDefaultControllerFromTransformer(this, transformer, transformerDict); - - if ("start" in transformerDict) { - const controller = $getByIdDirectPrivate(this, "controller"); - const startAlgorithm = () => $promiseInvokeOrNoopMethodNoCatch(transformer, transformerDict["start"], [controller]); - startAlgorithm().$then( - () => { - // FIXME: We probably need to resolve start promise with the result of the start algorithm. - startPromiseCapability.resolve.$call(); - }, - error => { - startPromiseCapability.reject.$call(undefined, error); - }, - ); - } else startPromiseCapability.resolve.$call(); - - return this; -} - -$getter; -export function readable() { - if (!$isTransformStream(this)) throw $makeThisTypeError("TransformStream", "readable"); - - return $getByIdDirectPrivate(this, "readable"); -} - -export function writable() { - if (!$isTransformStream(this)) throw $makeThisTypeError("TransformStream", "writable"); - - return $getByIdDirectPrivate(this, "writable"); -} diff --git a/src/js/builtins/TransformStreamDefaultController.ts b/src/js/builtins/TransformStreamDefaultController.ts deleted file mode 100644 index 1045498b8df6a4..00000000000000 --- a/src/js/builtins/TransformStreamDefaultController.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeTransformStreamDefaultController(this) { - return this; -} - -$getter; -export function desiredSize(this) { - if (!$isTransformStreamDefaultController(this)) - throw $makeThisTypeError("TransformStreamDefaultController", "enqueue"); - - const stream = $getByIdDirectPrivate(this, "stream"); - const readable = $getByIdDirectPrivate(stream, "readable"); - const readableController = $getByIdDirectPrivate(readable, "readableStreamController"); - - return $readableStreamDefaultControllerGetDesiredSize(readableController); -} - -export function enqueue(this, chunk) { - if (!$isTransformStreamDefaultController(this)) - throw $makeThisTypeError("TransformStreamDefaultController", "enqueue"); - - $transformStreamDefaultControllerEnqueue(this, chunk); -} - -export function error(this, e) { - if (!$isTransformStreamDefaultController(this)) throw $makeThisTypeError("TransformStreamDefaultController", "error"); - - $transformStreamDefaultControllerError(this, e); -} - -export function terminate(this) { - if (!$isTransformStreamDefaultController(this)) - throw $makeThisTypeError("TransformStreamDefaultController", "terminate"); - - $transformStreamDefaultControllerTerminate(this); -} diff --git a/src/js/builtins/TransformStreamInternals.ts b/src/js/builtins/TransformStreamInternals.ts deleted file mode 100644 index 833fafdc6b3eb1..00000000000000 --- a/src/js/builtins/TransformStreamInternals.ts +++ /dev/null @@ -1,349 +0,0 @@ -// @ts-nocheck -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -export function isTransformStream(stream) { - return $isObject(stream) && !!$getByIdDirectPrivate(stream, "readable"); -} - -export function isTransformStreamDefaultController(controller) { - return $isObject(controller) && !!$getByIdDirectPrivate(controller, "transformAlgorithm"); -} - -export function createTransformStream( - startAlgorithm, - transformAlgorithm, - flushAlgorithm, - writableHighWaterMark, - writableSizeAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, -) { - if (writableHighWaterMark === undefined) writableHighWaterMark = 1; - if (writableSizeAlgorithm === undefined) writableSizeAlgorithm = () => 1; - if (readableHighWaterMark === undefined) readableHighWaterMark = 0; - if (readableSizeAlgorithm === undefined) readableSizeAlgorithm = () => 1; - $assert(writableHighWaterMark >= 0); - $assert(readableHighWaterMark >= 0); - - const transform = {}; - $putByIdDirectPrivate(transform, "TransformStream", true); - - const stream = new TransformStream(transform); - const startPromiseCapability = $newPromiseCapability(Promise); - $initializeTransformStream( - stream, - startPromiseCapability.promise, - writableHighWaterMark, - writableSizeAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, - ); - - const controller = new TransformStreamDefaultController(); - $setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); - - startAlgorithm().$then( - () => { - startPromiseCapability.resolve.$call(); - }, - error => { - startPromiseCapability.reject.$call(undefined, error); - }, - ); - - return stream; -} - -export function initializeTransformStream( - stream, - startPromise, - writableHighWaterMark, - writableSizeAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, -) { - const startAlgorithm = () => { - return startPromise; - }; - const writeAlgorithm = chunk => { - return $transformStreamDefaultSinkWriteAlgorithm(stream, chunk); - }; - const abortAlgorithm = reason => { - return $transformStreamDefaultSinkAbortAlgorithm(stream, reason); - }; - const closeAlgorithm = () => { - return $transformStreamDefaultSinkCloseAlgorithm(stream); - }; - const writable = $createWritableStream( - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - writableHighWaterMark, - writableSizeAlgorithm, - ); - - const pullAlgorithm = () => { - return $transformStreamDefaultSourcePullAlgorithm(stream); - }; - const cancelAlgorithm = reason => { - $transformStreamErrorWritableAndUnblockWrite(stream, reason); - return Promise.$resolve(); - }; - const underlyingSource = {}; - $putByIdDirectPrivate(underlyingSource, "start", startAlgorithm); - $putByIdDirectPrivate(underlyingSource, "pull", pullAlgorithm); - $putByIdDirectPrivate(underlyingSource, "cancel", cancelAlgorithm); - const options = {}; - $putByIdDirectPrivate(options, "size", readableSizeAlgorithm); - $putByIdDirectPrivate(options, "highWaterMark", readableHighWaterMark); - const readable = new ReadableStream(underlyingSource, options); - - // The writable to expose to JS through writable getter. - $putByIdDirectPrivate(stream, "writable", writable); - // The writable to use for the actual transform algorithms. - $putByIdDirectPrivate(stream, "internalWritable", $getInternalWritableStream(writable)); - - $putByIdDirectPrivate(stream, "readable", readable); - $putByIdDirectPrivate(stream, "backpressure", undefined); - $putByIdDirectPrivate(stream, "backpressureChangePromise", undefined); - - $transformStreamSetBackpressure(stream, true); - $putByIdDirectPrivate(stream, "controller", undefined); -} - -export function transformStreamError(stream, e) { - const readable = $getByIdDirectPrivate(stream, "readable"); - const readableController = $getByIdDirectPrivate(readable, "readableStreamController"); - $readableStreamDefaultControllerError(readableController, e); - - $transformStreamErrorWritableAndUnblockWrite(stream, e); -} - -export function transformStreamErrorWritableAndUnblockWrite(stream, e) { - $transformStreamDefaultControllerClearAlgorithms($getByIdDirectPrivate(stream, "controller")); - - const writable = $getByIdDirectPrivate(stream, "internalWritable"); - $writableStreamDefaultControllerErrorIfNeeded($getByIdDirectPrivate(writable, "controller"), e); - - if ($getByIdDirectPrivate(stream, "backpressure")) $transformStreamSetBackpressure(stream, false); -} - -export function transformStreamSetBackpressure(stream, backpressure) { - $assert($getByIdDirectPrivate(stream, "backpressure") !== backpressure); - - const backpressureChangePromise = $getByIdDirectPrivate(stream, "backpressureChangePromise"); - if (backpressureChangePromise !== undefined) backpressureChangePromise.resolve.$call(); - - $putByIdDirectPrivate(stream, "backpressureChangePromise", $newPromiseCapability(Promise)); - $putByIdDirectPrivate(stream, "backpressure", backpressure); -} - -export function setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm) { - $assert($isTransformStream(stream)); - $assert($getByIdDirectPrivate(stream, "controller") === undefined); - - $putByIdDirectPrivate(controller, "stream", stream); - $putByIdDirectPrivate(stream, "controller", controller); - $putByIdDirectPrivate(controller, "transformAlgorithm", transformAlgorithm); - $putByIdDirectPrivate(controller, "flushAlgorithm", flushAlgorithm); -} - -export function setUpTransformStreamDefaultControllerFromTransformer(stream, transformer, transformerDict) { - const controller = new TransformStreamDefaultController(); - let transformAlgorithm = chunk => { - try { - $transformStreamDefaultControllerEnqueue(controller, chunk); - } catch (e) { - return Promise.$reject(e); - } - return Promise.$resolve(); - }; - let flushAlgorithm = () => { - return Promise.$resolve(); - }; - - if ("transform" in transformerDict) - transformAlgorithm = chunk => { - return $promiseInvokeOrNoopMethod(transformer, transformerDict["transform"], [chunk, controller]); - }; - - if ("flush" in transformerDict) { - flushAlgorithm = () => { - return $promiseInvokeOrNoopMethod(transformer, transformerDict["flush"], [controller]); - }; - } - - $setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); -} - -export function transformStreamDefaultControllerClearAlgorithms(controller) { - // We set transformAlgorithm to true to allow GC but keep the isTransformStreamDefaultController check. - $putByIdDirectPrivate(controller, "transformAlgorithm", true); - $putByIdDirectPrivate(controller, "flushAlgorithm", undefined); -} - -export function transformStreamDefaultControllerEnqueue(controller, chunk) { - const stream = $getByIdDirectPrivate(controller, "stream"); - const readable = $getByIdDirectPrivate(stream, "readable"); - const readableController = $getByIdDirectPrivate(readable, "readableStreamController"); - - $assert(readableController !== undefined); - if (!$readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - $throwTypeError("TransformStream.readable cannot close or enqueue"); - - try { - $readableStreamDefaultControllerEnqueue(readableController, chunk); - } catch (e) { - $transformStreamErrorWritableAndUnblockWrite(stream, e); - throw $getByIdDirectPrivate(readable, "storedError"); - } - - const backpressure = !$readableStreamDefaultControllerShouldCallPull(readableController); - if (backpressure !== $getByIdDirectPrivate(stream, "backpressure")) { - $assert(backpressure); - $transformStreamSetBackpressure(stream, true); - } -} - -export function transformStreamDefaultControllerError(controller, e) { - $transformStreamError($getByIdDirectPrivate(controller, "stream"), e); -} - -export function transformStreamDefaultControllerPerformTransform(controller, chunk) { - const promiseCapability = $newPromiseCapability(Promise); - - const transformPromise = $getByIdDirectPrivate(controller, "transformAlgorithm").$call(undefined, chunk); - transformPromise.$then( - () => { - promiseCapability.resolve(); - }, - r => { - $transformStreamError($getByIdDirectPrivate(controller, "stream"), r); - promiseCapability.reject.$call(undefined, r); - }, - ); - return promiseCapability.promise; -} - -export function transformStreamDefaultControllerTerminate(controller) { - const stream = $getByIdDirectPrivate(controller, "stream"); - const readable = $getByIdDirectPrivate(stream, "readable"); - const readableController = $getByIdDirectPrivate(readable, "readableStreamController"); - - // FIXME: Update readableStreamDefaultControllerClose to make this check. - if ($readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - $readableStreamDefaultControllerClose(readableController); - const error = $makeTypeError("the stream has been terminated"); - $transformStreamErrorWritableAndUnblockWrite(stream, error); -} - -export function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) { - const writable = $getByIdDirectPrivate(stream, "internalWritable"); - - $assert($getByIdDirectPrivate(writable, "state") === "writable"); - - const controller = $getByIdDirectPrivate(stream, "controller"); - - if ($getByIdDirectPrivate(stream, "backpressure")) { - const promiseCapability = $newPromiseCapability(Promise); - - const backpressureChangePromise = $getByIdDirectPrivate(stream, "backpressureChangePromise"); - $assert(backpressureChangePromise !== undefined); - backpressureChangePromise.promise.$then( - () => { - const state = $getByIdDirectPrivate(writable, "state"); - if (state === "erroring") { - promiseCapability.reject.$call(undefined, $getByIdDirectPrivate(writable, "storedError")); - return; - } - - $assert(state === "writable"); - $transformStreamDefaultControllerPerformTransform(controller, chunk).$then( - () => { - promiseCapability.resolve(); - }, - e => { - promiseCapability.reject.$call(undefined, e); - }, - ); - }, - e => { - promiseCapability.reject.$call(undefined, e); - }, - ); - - return promiseCapability.promise; - } - return $transformStreamDefaultControllerPerformTransform(controller, chunk); -} - -export function transformStreamDefaultSinkAbortAlgorithm(stream, reason) { - $transformStreamError(stream, reason); - return Promise.$resolve(); -} - -export function transformStreamDefaultSinkCloseAlgorithm(stream) { - const readable = $getByIdDirectPrivate(stream, "readable"); - const controller = $getByIdDirectPrivate(stream, "controller"); - const readableController = $getByIdDirectPrivate(readable, "readableStreamController"); - - const flushAlgorithm = $getByIdDirectPrivate(controller, "flushAlgorithm"); - $assert(flushAlgorithm !== undefined); - const flushPromise = $getByIdDirectPrivate(controller, "flushAlgorithm").$call(); - $transformStreamDefaultControllerClearAlgorithms(controller); - - const promiseCapability = $newPromiseCapability(Promise); - flushPromise.$then( - () => { - if ($getByIdDirectPrivate(readable, "state") === $streamErrored) { - promiseCapability.reject.$call(undefined, $getByIdDirectPrivate(readable, "storedError")); - return; - } - - // FIXME: Update readableStreamDefaultControllerClose to make this check. - if ($readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - $readableStreamDefaultControllerClose(readableController); - promiseCapability.resolve(); - }, - r => { - $transformStreamError($getByIdDirectPrivate(controller, "stream"), r); - promiseCapability.reject.$call(undefined, $getByIdDirectPrivate(readable, "storedError")); - }, - ); - return promiseCapability.promise; -} - -export function transformStreamDefaultSourcePullAlgorithm(stream) { - $assert($getByIdDirectPrivate(stream, "backpressure")); - $assert($getByIdDirectPrivate(stream, "backpressureChangePromise") !== undefined); - - $transformStreamSetBackpressure(stream, false); - - return $getByIdDirectPrivate(stream, "backpressureChangePromise").promise; -} diff --git a/src/js/builtins/WritableStreamDefaultController.ts b/src/js/builtins/WritableStreamDefaultController.ts deleted file mode 100644 index 1a3ddc29046c3f..00000000000000 --- a/src/js/builtins/WritableStreamDefaultController.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeWritableStreamDefaultController(this) { - $putByIdDirectPrivate(this, "queue", $newQueue()); - $putByIdDirectPrivate(this, "abortSteps", reason => { - const result = $getByIdDirectPrivate(this, "abortAlgorithm").$call(undefined, reason); - $writableStreamDefaultControllerClearAlgorithms(this); - return result; - }); - - $putByIdDirectPrivate(this, "errorSteps", () => { - $resetQueue($getByIdDirectPrivate(this, "queue")); - }); - - return this; -} - -export function error(this, e) { - if ($getByIdDirectPrivate(this, "abortSteps") === undefined) - throw $makeThisTypeError("WritableStreamDefaultController", "error"); - - const stream = $getByIdDirectPrivate(this, "stream"); - if ($getByIdDirectPrivate(stream, "state") !== "writable") return; - $writableStreamDefaultControllerError(this, e); -} diff --git a/src/js/builtins/WritableStreamDefaultWriter.ts b/src/js/builtins/WritableStreamDefaultWriter.ts deleted file mode 100644 index ff3f38f0066f75..00000000000000 --- a/src/js/builtins/WritableStreamDefaultWriter.ts +++ /dev/null @@ -1,105 +0,0 @@ -// @ts-nocheck -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -export function initializeWritableStreamDefaultWriter(stream) { - // stream can be a WritableStream if WritableStreamDefaultWriter constructor is called directly from JS - // or an InternalWritableStream in other code paths. - const internalStream = $getInternalWritableStream(stream); - if (internalStream) stream = internalStream; - - if (!$isWritableStream(stream)) $throwTypeError("WritableStreamDefaultWriter constructor takes a WritableStream"); - - $setUpWritableStreamDefaultWriter(this, stream); - return this; -} - -$getter; -export function closed() { - if (!$isWritableStreamDefaultWriter(this)) - return Promise.$reject($makeGetterTypeError("WritableStreamDefaultWriter", "closed")); - - return $getByIdDirectPrivate(this, "closedPromise").promise; -} - -$getter; -export function desiredSize() { - if (!$isWritableStreamDefaultWriter(this)) throw $makeThisTypeError("WritableStreamDefaultWriter", "desiredSize"); - - if ($getByIdDirectPrivate(this, "stream") === undefined) $throwTypeError("WritableStreamDefaultWriter has no stream"); - - return $writableStreamDefaultWriterGetDesiredSize(this); -} - -$getter; -export function ready() { - if (!$isWritableStreamDefaultWriter(this)) - return Promise.$reject($makeThisTypeError("WritableStreamDefaultWriter", "ready")); - - return $getByIdDirectPrivate(this, "readyPromise").promise; -} - -export function abort(reason) { - if (!$isWritableStreamDefaultWriter(this)) - return Promise.$reject($makeThisTypeError("WritableStreamDefaultWriter", "abort")); - - if ($getByIdDirectPrivate(this, "stream") === undefined) - return Promise.$reject($makeTypeError("WritableStreamDefaultWriter has no stream")); - - return $writableStreamDefaultWriterAbort(this, reason); -} - -export function close() { - if (!$isWritableStreamDefaultWriter(this)) - return Promise.$reject($makeThisTypeError("WritableStreamDefaultWriter", "close")); - - const stream = $getByIdDirectPrivate(this, "stream"); - if (stream === undefined) return Promise.$reject($makeTypeError("WritableStreamDefaultWriter has no stream")); - - if ($writableStreamCloseQueuedOrInFlight(stream)) - return Promise.$reject($makeTypeError("WritableStreamDefaultWriter is being closed")); - - return $writableStreamDefaultWriterClose(this); -} - -export function releaseLock() { - if (!$isWritableStreamDefaultWriter(this)) throw $makeThisTypeError("WritableStreamDefaultWriter", "releaseLock"); - - const stream = $getByIdDirectPrivate(this, "stream"); - if (stream === undefined) return; - - $assert($getByIdDirectPrivate(stream, "writer") !== undefined); - $writableStreamDefaultWriterRelease(this); -} - -export function write(chunk) { - if (!$isWritableStreamDefaultWriter(this)) - return Promise.$reject($makeThisTypeError("WritableStreamDefaultWriter", "write")); - - if ($getByIdDirectPrivate(this, "stream") === undefined) - return Promise.$reject($makeTypeError("WritableStreamDefaultWriter has no stream")); - - return $writableStreamDefaultWriterWrite(this, chunk); -} diff --git a/src/js/builtins/WritableStreamInternals.ts b/src/js/builtins/WritableStreamInternals.ts deleted file mode 100644 index e14c5dee3590fe..00000000000000 --- a/src/js/builtins/WritableStreamInternals.ts +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -export function isWritableStream(stream) { - return $isObject(stream) && !!$getByIdDirectPrivate(stream, "underlyingSink"); -} - -export function isWritableStreamDefaultWriter(writer) { - return $isObject(writer) && !!$getByIdDirectPrivate(writer, "closedPromise"); -} - -export function acquireWritableStreamDefaultWriter(stream) { - return new WritableStreamDefaultWriter(stream); -} - -// https://streams.spec.whatwg.org/#create-writable-stream -export function createWritableStream( - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, -) { - $assert(typeof highWaterMark === "number" && highWaterMark === highWaterMark && highWaterMark >= 0); - - const internalStream = {}; - $initializeWritableStreamSlots(internalStream, {}); - const controller = new WritableStreamDefaultController(); - - $setUpWritableStreamDefaultController( - internalStream, - controller, - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, - ); - - return $createWritableStreamFromInternal(internalStream); -} - -export function createInternalWritableStreamFromUnderlyingSink(underlyingSink, strategy) { - const stream = {}; - - if (underlyingSink === undefined) underlyingSink = {}; - - if (strategy === undefined) strategy = {}; - - if (!$isObject(underlyingSink)) $throwTypeError("WritableStream constructor takes an object as first argument"); - - if ("type" in underlyingSink) $throwRangeError("Invalid type is specified"); - - const sizeAlgorithm = $extractSizeAlgorithm(strategy); - const highWaterMark = $extractHighWaterMark(strategy, 1); - - const underlyingSinkDict = {}; - if ("start" in underlyingSink) { - underlyingSinkDict["start"] = underlyingSink["start"]; - if (typeof underlyingSinkDict["start"] !== "function") $throwTypeError("underlyingSink.start should be a function"); - } - if ("write" in underlyingSink) { - underlyingSinkDict["write"] = underlyingSink["write"]; - if (typeof underlyingSinkDict["write"] !== "function") $throwTypeError("underlyingSink.write should be a function"); - } - if ("close" in underlyingSink) { - underlyingSinkDict["close"] = underlyingSink["close"]; - if (typeof underlyingSinkDict["close"] !== "function") $throwTypeError("underlyingSink.close should be a function"); - } - if ("abort" in underlyingSink) { - underlyingSinkDict["abort"] = underlyingSink["abort"]; - if (typeof underlyingSinkDict["abort"] !== "function") $throwTypeError("underlyingSink.abort should be a function"); - } - - $initializeWritableStreamSlots(stream, underlyingSink); - $setUpWritableStreamDefaultControllerFromUnderlyingSink( - stream, - underlyingSink, - underlyingSinkDict, - highWaterMark, - sizeAlgorithm, - ); - - return stream; -} - -export function initializeWritableStreamSlots(stream, underlyingSink) { - $putByIdDirectPrivate(stream, "state", "writable"); - $putByIdDirectPrivate(stream, "storedError", undefined); - $putByIdDirectPrivate(stream, "writer", undefined); - $putByIdDirectPrivate(stream, "controller", undefined); - $putByIdDirectPrivate(stream, "inFlightWriteRequest", undefined); - $putByIdDirectPrivate(stream, "closeRequest", undefined); - $putByIdDirectPrivate(stream, "inFlightCloseRequest", undefined); - $putByIdDirectPrivate(stream, "pendingAbortRequest", undefined); - $putByIdDirectPrivate(stream, "writeRequests", $createFIFO()); - $putByIdDirectPrivate(stream, "backpressure", false); - $putByIdDirectPrivate(stream, "underlyingSink", underlyingSink); -} - -export function writableStreamCloseForBindings(stream) { - if ($isWritableStreamLocked(stream)) - return Promise.$reject($makeTypeError("WritableStream.close method can only be used on non locked WritableStream")); - - if ($writableStreamCloseQueuedOrInFlight(stream)) - return Promise.$reject( - $makeTypeError("WritableStream.close method can only be used on a being close WritableStream"), - ); - - return $writableStreamClose(stream); -} - -export function writableStreamAbortForBindings(stream, reason) { - if ($isWritableStreamLocked(stream)) - return Promise.$reject($makeTypeError("WritableStream.abort method can only be used on non locked WritableStream")); - - return $writableStreamAbort(stream, reason); -} - -export function isWritableStreamLocked(stream) { - return $getByIdDirectPrivate(stream, "writer") !== undefined; -} - -export function setUpWritableStreamDefaultWriter(writer, stream) { - if ($isWritableStreamLocked(stream)) $throwTypeError("WritableStream is locked"); - - $putByIdDirectPrivate(writer, "stream", stream); - $putByIdDirectPrivate(stream, "writer", writer); - - const readyPromiseCapability = $newPromiseCapability(Promise); - const closedPromiseCapability = $newPromiseCapability(Promise); - $putByIdDirectPrivate(writer, "readyPromise", readyPromiseCapability); - $putByIdDirectPrivate(writer, "closedPromise", closedPromiseCapability); - - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "writable") { - if ($writableStreamCloseQueuedOrInFlight(stream) || !$getByIdDirectPrivate(stream, "backpressure")) - readyPromiseCapability.resolve.$call(); - } else if (state === "erroring") { - readyPromiseCapability.reject.$call(undefined, $getByIdDirectPrivate(stream, "storedError")); - $markPromiseAsHandled(readyPromiseCapability.promise); - } else if (state === "closed") { - readyPromiseCapability.resolve.$call(); - closedPromiseCapability.resolve.$call(); - } else { - $assert(state === "errored"); - const storedError = $getByIdDirectPrivate(stream, "storedError"); - readyPromiseCapability.reject.$call(undefined, storedError); - $markPromiseAsHandled(readyPromiseCapability.promise); - closedPromiseCapability.reject.$call(undefined, storedError); - $markPromiseAsHandled(closedPromiseCapability.promise); - } -} - -export function writableStreamAbort(stream, reason) { - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "closed" || state === "errored") return Promise.$resolve(); - - const pendingAbortRequest = $getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (pendingAbortRequest !== undefined) return pendingAbortRequest.promise.promise; - - $assert(state === "writable" || state === "erroring"); - let wasAlreadyErroring = false; - if (state === "erroring") { - wasAlreadyErroring = true; - reason = undefined; - } - - const abortPromiseCapability = $newPromiseCapability(Promise); - $putByIdDirectPrivate(stream, "pendingAbortRequest", { - promise: abortPromiseCapability, - reason: reason, - wasAlreadyErroring: wasAlreadyErroring, - }); - - if (!wasAlreadyErroring) $writableStreamStartErroring(stream, reason); - return abortPromiseCapability.promise; -} - -export function writableStreamClose(stream) { - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "closed" || state === "errored") - return Promise.$reject($makeTypeError("Cannot close a writable stream that is closed or errored")); - - $assert(state === "writable" || state === "erroring"); - $assert(!$writableStreamCloseQueuedOrInFlight(stream)); - - const closePromiseCapability = $newPromiseCapability(Promise); - $putByIdDirectPrivate(stream, "closeRequest", closePromiseCapability); - - const writer = $getByIdDirectPrivate(stream, "writer"); - if (writer !== undefined && $getByIdDirectPrivate(stream, "backpressure") && state === "writable") - $getByIdDirectPrivate(writer, "readyPromise").resolve.$call(); - - $writableStreamDefaultControllerClose($getByIdDirectPrivate(stream, "controller")); - - return closePromiseCapability.promise; -} - -export function writableStreamAddWriteRequest(stream) { - $assert($isWritableStreamLocked(stream)); - $assert($getByIdDirectPrivate(stream, "state") === "writable"); - - const writePromiseCapability = $newPromiseCapability(Promise); - const writeRequests = $getByIdDirectPrivate(stream, "writeRequests"); - writeRequests.push(writePromiseCapability); - return writePromiseCapability.promise; -} - -export function writableStreamCloseQueuedOrInFlight(stream) { - return ( - $getByIdDirectPrivate(stream, "closeRequest") !== undefined || - $getByIdDirectPrivate(stream, "inFlightCloseRequest") !== undefined - ); -} - -export function writableStreamDealWithRejection(stream, error) { - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "writable") { - $writableStreamStartErroring(stream, error); - return; - } - - $assert(state === "erroring"); - $writableStreamFinishErroring(stream); -} - -export function writableStreamFinishErroring(stream) { - $assert($getByIdDirectPrivate(stream, "state") === "erroring"); - $assert(!$writableStreamHasOperationMarkedInFlight(stream)); - - $putByIdDirectPrivate(stream, "state", "errored"); - - const controller = $getByIdDirectPrivate(stream, "controller"); - $getByIdDirectPrivate(controller, "errorSteps").$call(); - - const storedError = $getByIdDirectPrivate(stream, "storedError"); - const requests = $getByIdDirectPrivate(stream, "writeRequests"); - for (var request = requests.shift(); request; request = requests.shift()) - request.reject.$call(undefined, storedError); - - // TODO: is this still necessary? - $putByIdDirectPrivate(stream, "writeRequests", $createFIFO()); - - const abortRequest = $getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest === undefined) { - $writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - - $putByIdDirectPrivate(stream, "pendingAbortRequest", undefined); - if (abortRequest.wasAlreadyErroring) { - abortRequest.promise.reject.$call(undefined, storedError); - $writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - - $getByIdDirectPrivate(controller, "abortSteps") - .$call(undefined, abortRequest.reason) - .$then( - () => { - abortRequest.promise.resolve.$call(); - $writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, - reason => { - abortRequest.promise.reject.$call(undefined, reason); - $writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, - ); -} - -export function writableStreamFinishInFlightClose(stream) { - const inFlightCloseRequest = $getByIdDirectPrivate(stream, "inFlightCloseRequest"); - inFlightCloseRequest.resolve.$call(); - - $putByIdDirectPrivate(stream, "inFlightCloseRequest", undefined); - - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - - if (state === "erroring") { - $putByIdDirectPrivate(stream, "storedError", undefined); - const abortRequest = $getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest !== undefined) { - abortRequest.promise.resolve.$call(); - $putByIdDirectPrivate(stream, "pendingAbortRequest", undefined); - } - } - - $putByIdDirectPrivate(stream, "state", "closed"); - - const writer = $getByIdDirectPrivate(stream, "writer"); - if (writer !== undefined) $getByIdDirectPrivate(writer, "closedPromise").resolve.$call(); - - $assert($getByIdDirectPrivate(stream, "pendingAbortRequest") === undefined); - $assert($getByIdDirectPrivate(stream, "storedError") === undefined); -} - -export function writableStreamFinishInFlightCloseWithError(stream, error) { - const inFlightCloseRequest = $getByIdDirectPrivate(stream, "inFlightCloseRequest"); - $assert(inFlightCloseRequest !== undefined); - inFlightCloseRequest.reject.$call(undefined, error); - - $putByIdDirectPrivate(stream, "inFlightCloseRequest", undefined); - - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - - const abortRequest = $getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest !== undefined) { - abortRequest.promise.reject.$call(undefined, error); - $putByIdDirectPrivate(stream, "pendingAbortRequest", undefined); - } - - $writableStreamDealWithRejection(stream, error); -} - -export function writableStreamFinishInFlightWrite(stream) { - const inFlightWriteRequest = $getByIdDirectPrivate(stream, "inFlightWriteRequest"); - $assert(inFlightWriteRequest !== undefined); - inFlightWriteRequest.resolve.$call(); - - $putByIdDirectPrivate(stream, "inFlightWriteRequest", undefined); -} - -export function writableStreamFinishInFlightWriteWithError(stream, error) { - const inFlightWriteRequest = $getByIdDirectPrivate(stream, "inFlightWriteRequest"); - $assert(inFlightWriteRequest !== undefined); - inFlightWriteRequest.reject.$call(undefined, error); - - $putByIdDirectPrivate(stream, "inFlightWriteRequest", undefined); - - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - - $writableStreamDealWithRejection(stream, error); -} - -export function writableStreamHasOperationMarkedInFlight(stream) { - return ( - $getByIdDirectPrivate(stream, "inFlightWriteRequest") !== undefined || - $getByIdDirectPrivate(stream, "inFlightCloseRequest") !== undefined - ); -} - -export function writableStreamMarkCloseRequestInFlight(stream) { - const closeRequest = $getByIdDirectPrivate(stream, "closeRequest"); - $assert($getByIdDirectPrivate(stream, "inFlightCloseRequest") === undefined); - $assert(closeRequest !== undefined); - - $putByIdDirectPrivate(stream, "inFlightCloseRequest", closeRequest); - $putByIdDirectPrivate(stream, "closeRequest", undefined); -} - -export function writableStreamMarkFirstWriteRequestInFlight(stream) { - const writeRequests = $getByIdDirectPrivate(stream, "writeRequests"); - $assert($getByIdDirectPrivate(stream, "inFlightWriteRequest") === undefined); - $assert(writeRequests.isNotEmpty()); - - const writeRequest = writeRequests.shift(); - $putByIdDirectPrivate(stream, "inFlightWriteRequest", writeRequest); -} - -export function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { - $assert($getByIdDirectPrivate(stream, "state") === "errored"); - - const storedError = $getByIdDirectPrivate(stream, "storedError"); - - const closeRequest = $getByIdDirectPrivate(stream, "closeRequest"); - if (closeRequest !== undefined) { - $assert($getByIdDirectPrivate(stream, "inFlightCloseRequest") === undefined); - closeRequest.reject.$call(undefined, storedError); - $putByIdDirectPrivate(stream, "closeRequest", undefined); - } - - const writer = $getByIdDirectPrivate(stream, "writer"); - if (writer !== undefined) { - const closedPromise = $getByIdDirectPrivate(writer, "closedPromise"); - closedPromise.reject.$call(undefined, storedError); - $markPromiseAsHandled(closedPromise.promise); - } -} - -export function writableStreamStartErroring(stream, reason) { - $assert($getByIdDirectPrivate(stream, "storedError") === undefined); - $assert($getByIdDirectPrivate(stream, "state") === "writable"); - - const controller = $getByIdDirectPrivate(stream, "controller"); - $assert(controller !== undefined); - - $putByIdDirectPrivate(stream, "state", "erroring"); - $putByIdDirectPrivate(stream, "storedError", reason); - - const writer = $getByIdDirectPrivate(stream, "writer"); - if (writer !== undefined) $writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); - - if (!$writableStreamHasOperationMarkedInFlight(stream) && $getByIdDirectPrivate(controller, "started") === 1) - $writableStreamFinishErroring(stream); -} - -export function writableStreamUpdateBackpressure(stream, backpressure) { - $assert($getByIdDirectPrivate(stream, "state") === "writable"); - $assert(!$writableStreamCloseQueuedOrInFlight(stream)); - - const writer = $getByIdDirectPrivate(stream, "writer"); - if (writer !== undefined && backpressure !== $getByIdDirectPrivate(stream, "backpressure")) { - if (backpressure) $putByIdDirectPrivate(writer, "readyPromise", $newPromiseCapability(Promise)); - else $getByIdDirectPrivate(writer, "readyPromise").resolve.$call(); - } - $putByIdDirectPrivate(stream, "backpressure", backpressure); -} - -export function writableStreamDefaultWriterAbort(writer, reason) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - return $writableStreamAbort(stream, reason); -} - -export function writableStreamDefaultWriterClose(writer) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - return $writableStreamClose(stream); -} - -export function writableStreamDefaultWriterCloseWithErrorPropagation(writer) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - - const state = $getByIdDirectPrivate(stream, "state"); - - if ($writableStreamCloseQueuedOrInFlight(stream) || state === "closed") return Promise.$resolve(); - - if (state === "errored") return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - - $assert(state === "writable" || state === "erroring"); - return $writableStreamDefaultWriterClose(writer); -} - -export function writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { - let closedPromiseCapability = $getByIdDirectPrivate(writer, "closedPromise"); - let closedPromise = closedPromiseCapability.promise; - - if (($getPromiseInternalField(closedPromise, $promiseFieldFlags) & $promiseStateMask) !== $promiseStatePending) { - closedPromiseCapability = $newPromiseCapability(Promise); - closedPromise = closedPromiseCapability.promise; - $putByIdDirectPrivate(writer, "closedPromise", closedPromiseCapability); - } - - closedPromiseCapability.reject.$call(undefined, error); - $markPromiseAsHandled(closedPromise); -} - -export function writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { - let readyPromiseCapability = $getByIdDirectPrivate(writer, "readyPromise"); - let readyPromise = readyPromiseCapability.promise; - - if (($getPromiseInternalField(readyPromise, $promiseFieldFlags) & $promiseStateMask) !== $promiseStatePending) { - readyPromiseCapability = $newPromiseCapability(Promise); - readyPromise = readyPromiseCapability.promise; - $putByIdDirectPrivate(writer, "readyPromise", readyPromiseCapability); - } - - readyPromiseCapability.reject.$call(undefined, error); - $markPromiseAsHandled(readyPromise); -} - -export function writableStreamDefaultWriterGetDesiredSize(writer) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - - const state = $getByIdDirectPrivate(stream, "state"); - - if (state === "errored" || state === "erroring") return null; - - if (state === "closed") return 0; - - return $writableStreamDefaultControllerGetDesiredSize($getByIdDirectPrivate(stream, "controller")); -} - -export function writableStreamDefaultWriterRelease(writer) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - $assert($getByIdDirectPrivate(stream, "writer") === writer); - - const releasedError = $makeTypeError("writableStreamDefaultWriterRelease"); - - $writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); - $writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); - - $putByIdDirectPrivate(stream, "writer", undefined); - $putByIdDirectPrivate(writer, "stream", undefined); -} - -export function writableStreamDefaultWriterWrite(writer, chunk) { - const stream = $getByIdDirectPrivate(writer, "stream"); - $assert(stream !== undefined); - - const controller = $getByIdDirectPrivate(stream, "controller"); - $assert(controller !== undefined); - const chunkSize = $writableStreamDefaultControllerGetChunkSize(controller, chunk); - - if (stream !== $getByIdDirectPrivate(writer, "stream")) - return Promise.$reject($makeTypeError("writer is not stream's writer")); - - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "errored") return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - - if ($writableStreamCloseQueuedOrInFlight(stream) || state === "closed") - return Promise.$reject($makeTypeError("stream is closing or closed")); - - if ($writableStreamCloseQueuedOrInFlight(stream) || state === "closed") - return Promise.$reject($makeTypeError("stream is closing or closed")); - - if (state === "erroring") return Promise.$reject($getByIdDirectPrivate(stream, "storedError")); - - $assert(state === "writable"); - - const promise = $writableStreamAddWriteRequest(stream); - $writableStreamDefaultControllerWrite(controller, chunk, chunkSize); - return promise; -} - -export function setUpWritableStreamDefaultController( - stream, - controller, - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, -) { - $assert($isWritableStream(stream)); - $assert($getByIdDirectPrivate(stream, "controller") === undefined); - - $putByIdDirectPrivate(controller, "stream", stream); - $putByIdDirectPrivate(stream, "controller", controller); - - $resetQueue($getByIdDirectPrivate(controller, "queue")); - - $putByIdDirectPrivate(controller, "started", -1); - $putByIdDirectPrivate(controller, "startAlgorithm", startAlgorithm); - $putByIdDirectPrivate(controller, "strategySizeAlgorithm", sizeAlgorithm); - $putByIdDirectPrivate(controller, "strategyHWM", highWaterMark); - $putByIdDirectPrivate(controller, "writeAlgorithm", writeAlgorithm); - $putByIdDirectPrivate(controller, "closeAlgorithm", closeAlgorithm); - $putByIdDirectPrivate(controller, "abortAlgorithm", abortAlgorithm); - - const backpressure = $writableStreamDefaultControllerGetBackpressure(controller); - $writableStreamUpdateBackpressure(stream, backpressure); - - $writableStreamDefaultControllerStart(controller); -} - -export function writableStreamDefaultControllerStart(controller) { - if ($getByIdDirectPrivate(controller, "started") !== -1) return; - - $putByIdDirectPrivate(controller, "started", 0); - - const startAlgorithm = $getByIdDirectPrivate(controller, "startAlgorithm"); - $putByIdDirectPrivate(controller, "startAlgorithm", undefined); - const stream = $getByIdDirectPrivate(controller, "stream"); - return Promise.$resolve(startAlgorithm.$call()).$then( - () => { - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - $putByIdDirectPrivate(controller, "started", 1); - $writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, - error => { - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - $putByIdDirectPrivate(controller, "started", 1); - $writableStreamDealWithRejection(stream, error); - }, - ); -} - -export function setUpWritableStreamDefaultControllerFromUnderlyingSink( - stream, - underlyingSink, - underlyingSinkDict, - highWaterMark, - sizeAlgorithm, -) { - // @ts-ignore - const controller = new $WritableStreamDefaultController(); - - let startAlgorithm: (...args: any[]) => any = () => {}; - let writeAlgorithm: (...args: any[]) => any = () => { - return Promise.$resolve(); - }; - let closeAlgorithm: (...args: any[]) => any = () => { - return Promise.$resolve(); - }; - let abortAlgorithm: (...args: any[]) => any = () => { - return Promise.$resolve(); - }; - - if ("start" in underlyingSinkDict) { - const startMethod = underlyingSinkDict["start"]; - startAlgorithm = () => $promiseInvokeOrNoopMethodNoCatch(underlyingSink, startMethod, [controller]); - } - if ("write" in underlyingSinkDict) { - const writeMethod = underlyingSinkDict["write"]; - writeAlgorithm = chunk => $promiseInvokeOrNoopMethod(underlyingSink, writeMethod, [chunk, controller]); - } - if ("close" in underlyingSinkDict) { - const closeMethod = underlyingSinkDict["close"]; - closeAlgorithm = () => $promiseInvokeOrNoopMethod(underlyingSink, closeMethod, []); - } - if ("abort" in underlyingSinkDict) { - const abortMethod = underlyingSinkDict["abort"]; - abortAlgorithm = reason => $promiseInvokeOrNoopMethod(underlyingSink, abortMethod, [reason]); - } - - $setUpWritableStreamDefaultController( - stream, - controller, - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, - ); -} - -export function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { - const stream = $getByIdDirectPrivate(controller, "stream"); - - if ($getByIdDirectPrivate(controller, "started") !== 1) return; - - $assert(stream !== undefined); - if ($getByIdDirectPrivate(stream, "inFlightWriteRequest") !== undefined) return; - - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state !== "closed" || state !== "errored"); - if (state === "erroring") { - $writableStreamFinishErroring(stream); - return; - } - - const queue = $getByIdDirectPrivate(controller, "queue"); - - if (queue.content?.isEmpty() ?? false) return; - - const value = $peekQueueValue(queue); - if (value === $isCloseSentinel) $writableStreamDefaultControllerProcessClose(controller); - else $writableStreamDefaultControllerProcessWrite(controller, value); -} - -export function isCloseSentinel() {} - -export function writableStreamDefaultControllerClearAlgorithms(controller) { - $putByIdDirectPrivate(controller, "writeAlgorithm", undefined); - $putByIdDirectPrivate(controller, "closeAlgorithm", undefined); - $putByIdDirectPrivate(controller, "abortAlgorithm", undefined); - $putByIdDirectPrivate(controller, "strategySizeAlgorithm", undefined); -} - -export function writableStreamDefaultControllerClose(controller) { - $enqueueValueWithSize($getByIdDirectPrivate(controller, "queue"), $isCloseSentinel, 0); - $writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); -} - -export function writableStreamDefaultControllerError(controller, error) { - const stream = $getByIdDirectPrivate(controller, "stream"); - $assert(stream !== undefined); - $assert($getByIdDirectPrivate(stream, "state") === "writable"); - - $writableStreamDefaultControllerClearAlgorithms(controller); - $writableStreamStartErroring(stream, error); -} - -export function writableStreamDefaultControllerErrorIfNeeded(controller, error) { - const stream = $getByIdDirectPrivate(controller, "stream"); - if ($getByIdDirectPrivate(stream, "state") === "writable") $writableStreamDefaultControllerError(controller, error); -} - -export function writableStreamDefaultControllerGetBackpressure(controller) { - const desiredSize = $writableStreamDefaultControllerGetDesiredSize(controller); - return desiredSize <= 0; -} - -export function writableStreamDefaultControllerGetChunkSize(controller, chunk) { - try { - return $getByIdDirectPrivate(controller, "strategySizeAlgorithm").$call(undefined, chunk); - } catch (e) { - $writableStreamDefaultControllerErrorIfNeeded(controller, e); - return 1; - } -} - -export function writableStreamDefaultControllerGetDesiredSize(controller) { - return $getByIdDirectPrivate(controller, "strategyHWM") - $getByIdDirectPrivate(controller, "queue").size; -} - -export function writableStreamDefaultControllerProcessClose(controller) { - const stream = $getByIdDirectPrivate(controller, "stream"); - - $writableStreamMarkCloseRequestInFlight(stream); - $dequeueValue($getByIdDirectPrivate(controller, "queue")); - - $assert($getByIdDirectPrivate(controller, "queue").content?.isEmpty()); - - const sinkClosePromise = $getByIdDirectPrivate(controller, "closeAlgorithm").$call(); - $writableStreamDefaultControllerClearAlgorithms(controller); - - sinkClosePromise.$then( - () => { - $writableStreamFinishInFlightClose(stream); - }, - reason => { - $writableStreamFinishInFlightCloseWithError(stream, reason); - }, - ); -} - -export function writableStreamDefaultControllerProcessWrite(controller, chunk) { - const stream = $getByIdDirectPrivate(controller, "stream"); - - $writableStreamMarkFirstWriteRequestInFlight(stream); - - const sinkWritePromise = $getByIdDirectPrivate(controller, "writeAlgorithm").$call(undefined, chunk); - - sinkWritePromise.$then( - () => { - $writableStreamFinishInFlightWrite(stream); - const state = $getByIdDirectPrivate(stream, "state"); - $assert(state === "writable" || state === "erroring"); - - $dequeueValue($getByIdDirectPrivate(controller, "queue")); - if (!$writableStreamCloseQueuedOrInFlight(stream) && state === "writable") { - const backpressure = $writableStreamDefaultControllerGetBackpressure(controller); - $writableStreamUpdateBackpressure(stream, backpressure); - } - $writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, - reason => { - const state = $getByIdDirectPrivate(stream, "state"); - if (state === "writable") $writableStreamDefaultControllerClearAlgorithms(controller); - - $writableStreamFinishInFlightWriteWithError(stream, reason); - }, - ); -} - -export function writableStreamDefaultControllerWrite(controller, chunk, chunkSize) { - try { - $enqueueValueWithSize($getByIdDirectPrivate(controller, "queue"), chunk, chunkSize); - - const stream = $getByIdDirectPrivate(controller, "stream"); - - const state = $getByIdDirectPrivate(stream, "state"); - if (!$writableStreamCloseQueuedOrInFlight(stream) && state === "writable") { - const backpressure = $writableStreamDefaultControllerGetBackpressure(controller); - $writableStreamUpdateBackpressure(stream, backpressure); - } - $writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - } catch (e) { - $writableStreamDefaultControllerErrorIfNeeded(controller, e); - } -} diff --git a/src/js/node/stream.ts b/src/js/node/stream.ts index 26ba3188a60bb4..80ec044e1c6162 100644 --- a/src/js/node/stream.ts +++ b/src/js/node/stream.ts @@ -27,7 +27,7 @@ const kPaused = Symbol("kPaused"); // END moved from require_readable const StringDecoder = require("node:string_decoder").StringDecoder; -const transferToNativeReadable = $newCppFunction("ReadableStream.cpp", "jsFunctionTransferToNativeReadableStream", 1); +// const transferToNativeReadable = $newCppFunction("ReadableStream.cpp", "jsFunctionTransferToNativeReadableStream", 1); const { kAutoDestroyed } = require("internal/shared"); const { validateBoolean, @@ -5640,7 +5640,8 @@ function getNativeReadableStream(Readable, stream, options) { // There may be a ReadableStream.Strong handle to the ReadableStream. // We can't update those handles to point to the NativeReadable from JS // So we instead mark it as no longer usable, and create a new NativeReadable - transferToNativeReadable(stream); + // transferToNativeReadable(stream); + throw new Error("TODO: transferToNativeReadable"); return new NativeReadable(ptr, options); }