aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/JSBufferList.cpp56
-rw-r--r--src/bun.js/bindings/JSBufferList.h57
-rw-r--r--src/bun.js/bindings/JSReadableState.cpp293
-rw-r--r--src/bun.js/bindings/JSReadableState.h110
-rw-r--r--src/bun.js/bindings/JSStringDecoder.cpp10
-rw-r--r--src/bun.js/bindings/JSStringDecoder.h9
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp30
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h10
-rw-r--r--src/bun.js/bindings/exports.zig2
-rw-r--r--src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h2
-rw-r--r--src/bun.js/bindings/webcore/DOMIsoSubspaces.h2
-rw-r--r--src/bun.js/streams.exports.js68
12 files changed, 526 insertions, 123 deletions
diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp
index 50e0defe0..948eed296 100644
--- a/src/bun.js/bindings/JSBufferList.cpp
+++ b/src/bun.js/bindings/JSBufferList.cpp
@@ -181,35 +181,6 @@ JSC::GCClient::IsoSubspace* JSBufferList::subspaceForImpl(JSC::VM& vm)
[](auto& spaces, auto&& space) { spaces.m_subspaceForBufferList = WTFMove(space); });
}
-class JSBufferListPrototype : public JSC::JSNonFinalObject {
-public:
- using Base = JSC::JSNonFinalObject;
- static JSBufferListPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
- {
- JSBufferListPrototype* ptr = new (NotNull, JSC::allocateCell<JSBufferListPrototype>(vm)) JSBufferListPrototype(vm, structure);
- ptr->finishCreation(vm, globalObject);
- return ptr;
- }
-
- DECLARE_INFO;
- template<typename CellType, JSC::SubspaceAccess>
- static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
- {
- return &vm.plainObjectSpace();
- }
- static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
- {
- return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
- }
-
-private:
- JSBufferListPrototype(JSC::VM& vm, JSC::Structure* structure)
- : Base(vm, structure)
- {
- }
-
- void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
-};
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBufferListPrototype, JSBufferListPrototype::Base);
static inline JSC::EncodedJSValue jsBufferListPrototypeFunction_pushBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSBufferList>::ClassParameter castedThis)
@@ -375,14 +346,31 @@ void JSBufferListPrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalTh
const ClassInfo JSBufferListPrototype::s_info = { "BufferList"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferListPrototype) };
-EncodedJSValue constructJSBufferList(JSGlobalObject* globalObject, CallFrame* callFrame)
+void JSBufferListConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSBufferListPrototype* prototype)
{
- JSC::VM& vm = globalObject->vm();
- JSBufferListPrototype* prototype = JSBufferListPrototype::create(
- vm, globalObject, JSBufferListPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+ Base::finishCreation(vm, 0, "BufferList"_s, PropertyAdditionMode::WithoutStructureTransition);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSBufferListConstructor* JSBufferListConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSBufferListPrototype* prototype) {
+ JSBufferListConstructor* ptr = new (NotNull, JSC::allocateCell<JSBufferListConstructor>(vm)) JSBufferListConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSBufferListConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ JSC::VM& vm = lexicalGlobalObject->vm();
JSBufferList* bufferList = JSBufferList::create(
- vm, globalObject, JSBufferList::createStructure(vm, globalObject, prototype));
+ vm, lexicalGlobalObject, reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferListStructure());
return JSC::JSValue::encode(bufferList);
}
+void JSBufferListConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSBufferListPrototype* prototype)
+{
+}
+
+const ClassInfo JSBufferListConstructor::s_info = { "BufferList"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferListConstructor) };
+
} // namespace Zig \ No newline at end of file
diff --git a/src/bun.js/bindings/JSBufferList.h b/src/bun.js/bindings/JSBufferList.h
index 67d8d21f3..3c0b8d12c 100644
--- a/src/bun.js/bindings/JSBufferList.h
+++ b/src/bun.js/bindings/JSBufferList.h
@@ -85,6 +85,61 @@ private:
Deque<WriteBarrier<Unknown>> m_deque;
};
-EncodedJSValue constructJSBufferList(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame);
+class JSBufferListPrototype : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSBufferListPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSBufferListPrototype* ptr = new (NotNull, JSC::allocateCell<JSBufferListPrototype>(vm)) JSBufferListPrototype(vm, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSBufferListPrototype(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+};
+
+class JSBufferListConstructor final : public JSC::InternalFunction {
+public:
+ using Base = JSC::InternalFunction;
+ static JSBufferListConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSBufferListPrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSBufferListPrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+private:
+ JSBufferListConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSBufferListPrototype* prototype);
+};
}
diff --git a/src/bun.js/bindings/JSReadableState.cpp b/src/bun.js/bindings/JSReadableState.cpp
new file mode 100644
index 000000000..fe19449ff
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableState.cpp
@@ -0,0 +1,293 @@
+#include "JSReadableState.h"
+#include "JSBufferList.h"
+#include "JSBuffer.h"
+#include "JavaScriptCore/Lookup.h"
+#include "JavaScriptCore/ObjectConstructor.h"
+#include "ZigGlobalObject.h"
+#include "JSDOMOperation.h"
+#include "JSDOMAttribute.h"
+#include "headers.h"
+#include "JSDOMConvertEnumeration.h"
+
+namespace WebCore {
+
+using namespace JSC;
+
+static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_pipesCount);
+static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_paused);
+static JSC_DECLARE_CUSTOM_GETTER(setJSReadableState_paused);
+
+int64_t getHighWaterMark(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
+{
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSC::JSValue highWaterMarkVal = options->getDirect(vm, JSC::Identifier::fromString(vm, "highWaterMark"_s));
+ if (isDuplex && (highWaterMarkVal.isUndefined() || highWaterMarkVal.isNull())) {
+ highWaterMarkVal = options->getDirect(vm, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
+ }
+ if (!highWaterMarkVal.isNull() && !highWaterMarkVal.isUndefined()) {
+ double customHightWaterMark = highWaterMarkVal.toNumber(globalObject);
+ RETURN_IF_EXCEPTION(throwScope, -1);
+ if (customHightWaterMark < 0)
+ return -1;
+ return floor(customHightWaterMark);
+ }
+
+ return -1;
+}
+
+void JSReadableState::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
+{
+ Base::finishCreation(vm);
+
+ bool objectMode = false;
+ auto objectModeIdent = JSC::Identifier::fromString(vm, "objectMode"_s);
+ if (options != nullptr) {
+ JSC::JSValue objectModeVal = options->getDirect(vm, objectModeIdent);
+ if (isDuplex && !objectModeVal) {
+ objectModeVal = options->getDirect(vm, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
+ }
+ if (objectModeVal)
+ objectMode = objectModeVal.toBoolean(globalObject);
+ }
+ putDirect(vm, WTFMove(objectModeIdent), JSC::jsBoolean(objectMode));
+
+ int64_t highWaterMark = objectMode ? 16 : 16 * 1024; // default value
+ if (options != nullptr) {
+ int64_t customHightWaterMark = getHighWaterMark(vm, globalObject, isDuplex, options);
+ if (customHightWaterMark >= 0)
+ highWaterMark = customHightWaterMark;
+ }
+ putDirect(vm, JSC::Identifier::fromString(vm, "highWaterMark"_s), JSC::jsNumber(highWaterMark));
+
+ putDirect(vm, JSC::Identifier::fromString(vm, "buffer"_s), JSBufferList::create(
+ vm, globalObject, reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferListStructure()));
+ putDirect(vm, JSC::Identifier::fromString(vm, "length"_s), JSC::jsNumber(0));
+ putDirect(vm, JSC::Identifier::fromString(vm, "pipes"_s), JSC::constructEmptyArray(globalObject, nullptr, 0));
+ putDirect(vm, JSC::Identifier::fromString(vm, "flowing"_s), JSC::jsNull());
+ putDirect(vm, JSC::Identifier::fromString(vm, "ended"_s), JSC::jsBoolean(false));
+ putDirect(vm, JSC::Identifier::fromString(vm, "endEmitted"_s), JSC::jsBoolean(false));
+ // Stream is still being constructed and cannot be
+ // destroyed until construction finished or failed.
+ // Async construction is opt in, therefore we start as
+ // constructed.
+ putDirect(vm, JSC::Identifier::fromString(vm, "reading"_s), JSC::jsBoolean(false));
+
+ // A flag to be able to tell if the event 'readable'/'data' is emitted
+ // immediately, or on a later tick. We set this to true at first, because
+ // any actions that shouldn't happen until "later" should generally also
+ // not happen before the first read call.
+ putDirect(vm, JSC::Identifier::fromString(vm, "constructed"_s), JSC::jsBoolean(true));
+
+ // Whenever we return null, then we set a flag to say
+ // that we're awaiting a 'readable' event emission.
+ putDirect(vm, JSC::Identifier::fromString(vm, "sync"_s), JSC::jsBoolean(true));
+
+ putDirect(vm, JSC::Identifier::fromString(vm, "needReadable"_s), JSC::jsBoolean(false));
+ putDirect(vm, JSC::Identifier::fromString(vm, "emittedReadable"_s), JSC::jsBoolean(false));
+ putDirect(vm, JSC::Identifier::fromString(vm, "readableListening"_s), JSC::jsBoolean(false));
+ putDirect(vm, JSC::Identifier::fromString(vm, "resumeScheduled"_s), JSC::jsBoolean(false));
+
+ // Should close be emitted on destroy. Defaults to true.
+ putDirect(vm, JSC::Identifier::fromString(vm, "errorEmitted"_s), JSC::jsBoolean(false));
+
+ if (options == nullptr) {
+ // Should .destroy() be called after 'end' (and potentially 'finish').
+ putDirect(vm, JSC::Identifier::fromString(vm, "emitClose"_s), JSC::jsBoolean(false));
+ // Has it been destroyed.
+ putDirect(vm, JSC::Identifier::fromString(vm, "autoDestroy"_s), JSC::jsBoolean(false));
+ } else {
+ // Should .destroy() be called after 'end' (and potentially 'finish').
+ auto emitCloseIdent = JSC::Identifier::fromString(vm, "emitClose"_s);
+ JSC::JSValue emitCloseVal = options->getDirect(vm, emitCloseIdent);
+ putDirect(vm, WTFMove(emitCloseIdent), JSC::jsBoolean(!emitCloseVal.isBoolean() || emitCloseVal.toBoolean(globalObject)));
+ // Has it been destroyed.
+ auto autoDestroyIdent = JSC::Identifier::fromString(vm, "autoDestroy"_s);
+ JSC::JSValue autoDestroyVal = options->getDirect(vm, autoDestroyIdent);
+ putDirect(vm, WTFMove(autoDestroyIdent), JSC::jsBoolean(!autoDestroyVal.isBoolean() || autoDestroyVal.toBoolean(globalObject)));
+ }
+
+ // Indicates whether the stream has errored. When true no further
+ // _read calls, 'data' or 'readable' events should occur. This is needed
+ // since when autoDestroy is disabled we need a way to tell whether the
+ // stream has failed.
+ putDirect(vm, JSC::Identifier::fromString(vm, "destroyed"_s), JSC::jsBoolean(false));
+
+ // Indicates whether the stream has finished destroying.
+ putDirect(vm, JSC::Identifier::fromString(vm, "errored"_s), JSC::jsNull());
+
+ // True if close has been emitted or would have been emitted
+ // depending on emitClose.
+ putDirect(vm, JSC::Identifier::fromString(vm, "closed"_s), JSC::jsBoolean(false));
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ putDirect(vm, JSC::Identifier::fromString(vm, "closeEmitted"_s), JSC::jsBoolean(false));
+
+ // Ref the piped dest which we need a drain event on it
+ // type: null | Writable | Set<Writable>.
+ auto defaultEncodingIdent = JSC::Identifier::fromString(vm, "defaultEncoding"_s);
+ if (options == nullptr) {
+ putDirect(vm, WTFMove(defaultEncodingIdent), JSC::jsString(vm, WTF::String("utf8"_s)));
+ } else {
+ JSC::JSValue defaultEncodingVal = getDirect(vm, defaultEncodingIdent);
+ if (defaultEncodingVal) {
+ putDirect(vm, WTFMove(defaultEncodingIdent), defaultEncodingVal);
+ } else {
+ putDirect(vm, WTFMove(defaultEncodingIdent), JSC::jsString(vm, WTF::String("utf8"_s)));
+ }
+ }
+
+ putDirect(vm, JSC::Identifier::fromString(vm, "awaitDrainWriters"_s), JSC::jsNull());
+ // If true, a maybeReadMore has been scheduled.
+ putDirect(vm, JSC::Identifier::fromString(vm, "multiAwaitDrain"_s), JSC::jsBoolean(false));
+
+ putDirect(vm, JSC::Identifier::fromString(vm, "readingMore"_s), JSC::jsBoolean(false));
+ putDirect(vm, JSC::Identifier::fromString(vm, "dataEmitted"_s), JSC::jsBoolean(false));
+
+ auto decoderIdent = JSC::Identifier::fromString(vm, "decoder"_s);
+ auto encodingIdent = JSC::Identifier::fromString(vm, "encoding"_s);
+ if (options == nullptr) {
+ putDirect(vm, WTFMove(decoderIdent), JSC::jsNull());
+ putDirect(vm, WTFMove(encodingIdent), JSC::jsNull());
+ } else {
+ JSC::JSValue encodingVal = options->getDirect(vm, encodingIdent);
+ if (encodingVal) {
+ auto constructor = reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSStringDecoder();
+ auto constructData = JSC::getConstructData(constructor);
+ MarkedArgumentBuffer args;
+ args.append(encodingVal);
+ JSObject* decoder = JSC::construct(globalObject, constructor, constructData, args);
+ putDirect(vm, WTFMove(decoderIdent), decoder);
+ putDirect(vm, WTFMove(encodingIdent), encodingVal);
+ } else {
+ putDirect(vm, WTFMove(decoderIdent), JSC::jsNull());
+ putDirect(vm, WTFMove(encodingIdent), JSC::jsNull());
+ }
+ }
+}
+
+const JSC::ClassInfo JSReadableState::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableState) };
+
+JSC::GCClient::IsoSubspace* JSReadableState::subspaceForImpl(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<JSReadableState, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForReadableState.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableState = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForReadableState.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableState = WTFMove(space); });
+}
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStatePrototype, JSReadableStatePrototype::Base);
+
+JSC_DEFINE_CUSTOM_GETTER(jsReadableState_pipesCount, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSObject* thisObject = JSC::jsDynamicCast<JSObject*>(JSValue::decode(thisValue));
+ if (!thisObject) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ JSC::JSValue pipesVal = thisObject->getDirect(vm, JSC::Identifier::fromString(vm, "pipes"_s));
+ if (!pipesVal) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ JSArray* pipes = JSC::jsDynamicCast<JSArray*>(pipesVal);
+ if (!pipes) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(pipes->length())));
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsReadableState_paused, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue));
+ if (!state) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ if (state->m_paused == 0)
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNull()));
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->m_paused > 0)));
+}
+
+JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_paused, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue));
+ if (!state) {
+ RETURN_IF_EXCEPTION(throwScope, false);
+ }
+ state->m_paused = JSC::JSValue::decode(encodedValue).toBoolean(lexicalGlobalObject) ? 1 : -1;
+ RELEASE_AND_RETURN(throwScope, true);
+}
+
+/* Hash table for prototype */
+static const HashTableValue JSReadableStatePrototypeTableValues[]
+ = {
+ { "pipesCount"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_pipesCount, 0 } },
+ { "paused"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_paused, setJSReadableState_paused } },
+ };
+
+void JSReadableStatePrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSReadableState::info(), JSReadableStatePrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+const ClassInfo JSReadableStatePrototype::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStatePrototype) };
+
+void JSReadableStateConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "ReadableState"_s, PropertyAdditionMode::WithoutStructureTransition);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSReadableStateConstructor* JSReadableStateConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* prototype) {
+ JSReadableStateConstructor* ptr = new (NotNull, JSC::allocateCell<JSReadableStateConstructor>(vm)) JSReadableStateConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSReadableStateConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ JSC::VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ if (callFrame->argumentCount() < 3) {
+ throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ return JSValue::encode(jsUndefined());
+ }
+ JSValue optionsVal = callFrame->uncheckedArgument(0);
+ JSValue streamVal = callFrame->uncheckedArgument(1);
+ JSValue isDuplexVal = callFrame->uncheckedArgument(2);
+
+ bool isDuplex;
+ if (!isDuplexVal.isBoolean()) {
+ // change this to `stream instanceof Duplex` after native Duplex is implemented.
+ JSC::throwTypeError(lexicalGlobalObject, throwScope, "isDuplex should be boolean"_s);
+ return JSValue::encode(jsUndefined());
+ }
+ isDuplex = isDuplexVal.toBoolean(lexicalGlobalObject);
+ JSObject* options = nullptr;
+ if (optionsVal.toBoolean(lexicalGlobalObject) && optionsVal.isObject()) {
+ options = optionsVal.toObject(lexicalGlobalObject);
+ }
+
+ JSReadableState* stringDecoder = JSReadableState::create(
+ vm, lexicalGlobalObject, reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSReadableStateStructure(), isDuplex, options);
+ return JSC::JSValue::encode(stringDecoder);
+}
+
+void JSReadableStateConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
+{
+}
+
+const ClassInfo JSReadableStateConstructor::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStateConstructor) };
+
+} // namespace Zig
diff --git a/src/bun.js/bindings/JSReadableState.h b/src/bun.js/bindings/JSReadableState.h
new file mode 100644
index 000000000..fd78f0411
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableState.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "root.h"
+#include "BufferEncodingType.h"
+
+namespace WebCore {
+using namespace JSC;
+
+class JSReadableState : public JSC::JSDestructibleObject {
+ using Base = JSC::JSDestructibleObject;
+
+public:
+ JSReadableState(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure), m_paused(0)
+ {
+ }
+
+ DECLARE_INFO;
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+
+ template<typename, JSC::SubspaceAccess mode> 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)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype,
+ JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ static JSReadableState* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, bool isDuplex, JSObject* options)
+ {
+ JSReadableState* accessor = new (NotNull, JSC::allocateCell<JSReadableState>(vm)) JSReadableState(vm, structure);
+ accessor->finishCreation(vm, globalObject, isDuplex, options);
+ return accessor;
+ }
+
+ void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options);
+ static void destroy(JSCell*) {}
+
+ // 0 for null, 1 for true, -1 for false
+ int8_t m_paused;
+};
+
+class JSReadableStatePrototype : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSReadableStatePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSReadableStatePrototype* ptr = new (NotNull, JSC::allocateCell<JSReadableStatePrototype>(vm)) JSReadableStatePrototype(vm, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSReadableStatePrototype(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+};
+
+class JSReadableStateConstructor final : public JSC::InternalFunction {
+public:
+ using Base = JSC::InternalFunction;
+ static JSReadableStateConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+
+private:
+ JSReadableStateConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
+};
+
+}
diff --git a/src/bun.js/bindings/JSStringDecoder.cpp b/src/bun.js/bindings/JSStringDecoder.cpp
index d9af6e49e..c4daad1dd 100644
--- a/src/bun.js/bindings/JSStringDecoder.cpp
+++ b/src/bun.js/bindings/JSStringDecoder.cpp
@@ -411,16 +411,6 @@ void JSStringDecoderConstructor::initializeProperties(VM& vm, JSC::JSGlobalObjec
{
}
-JSC::GCClient::IsoSubspace* JSStringDecoderConstructor::subspaceForImpl(JSC::VM& vm)
-{
- return WebCore::subspaceForImpl<JSStringDecoderConstructor, UseCustomHeapCellType::No>(
- vm,
- [](auto& spaces) { return spaces.m_clientSubspaceForStringDecoderConstructor.get(); },
- [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForStringDecoderConstructor = WTFMove(space); },
- [](auto& spaces) { return spaces.m_subspaceForStringDecoderConstructor.get(); },
- [](auto& spaces, auto&& space) { spaces.m_subspaceForStringDecoderConstructor = WTFMove(space); });
-}
-
const ClassInfo JSStringDecoderConstructor::s_info = { "StringDecoder"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSStringDecoderConstructor) };
} // namespace Zig
diff --git a/src/bun.js/bindings/JSStringDecoder.h b/src/bun.js/bindings/JSStringDecoder.h
index de2c54209..299c2fb96 100644
--- a/src/bun.js/bindings/JSStringDecoder.h
+++ b/src/bun.js/bindings/JSStringDecoder.h
@@ -103,15 +103,6 @@ public:
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
}
- template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
- {
- if constexpr (mode == JSC::SubspaceAccess::Concurrently)
- return nullptr;
- return subspaceForImpl(vm);
- }
-
- static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
-
void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSStringDecoderPrototype* prototype);
// Must be defined for each specialization class.
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 2753707e8..34c12161e 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -88,6 +88,7 @@
#include "JSCloseEvent.h"
#include "JSFetchHeaders.h"
#include "JSStringDecoder.h"
+#include "JSReadableState.h"
#include "Process.h"
@@ -1070,9 +1071,8 @@ JSC:
if (string == bunStreamString) {
auto* obj = constructEmptyObject(globalObject);
- auto* bufferList = JSC::JSFunction::create(
- vm, globalObject, 0, "BufferList"_s, WebCore::constructJSBufferList, ImplementationVisibility::Public, NoIntrinsic, WebCore::constructJSBufferList);
- obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "BufferList"_s)), bufferList, 0);
+ obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "BufferList"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferList(), 0);
+ obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "ReadableState"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSReadableState(), 0);
return JSValue::encode(obj);
}
@@ -1995,6 +1995,18 @@ void GlobalObject::finishCreation(VM& vm)
init.setConstructor(constructor);
});
+ m_JSBufferListClassStructure.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ auto* prototype = JSBufferListPrototype::create(
+ init.vm, init.global, JSBufferListPrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
+ auto* structure = JSBufferList::createStructure(init.vm, init.global, prototype);
+ auto* constructor = JSBufferListConstructor::create(
+ init.vm, init.global, JSBufferListConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
+ init.setPrototype(prototype);
+ init.setStructure(structure);
+ init.setConstructor(constructor);
+ });
+
m_JSStringDecoderClassStructure.initLater(
[](LazyClassStructure::Initializer& init) {
auto* prototype = JSStringDecoderPrototype::create(
@@ -2007,6 +2019,18 @@ void GlobalObject::finishCreation(VM& vm)
init.setConstructor(constructor);
});
+ m_JSReadableStateClassStructure.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ auto* prototype = JSReadableStatePrototype::create(
+ init.vm, init.global, JSReadableStatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
+ auto* structure = JSReadableState::createStructure(init.vm, init.global, prototype);
+ auto* constructor = JSReadableStateConstructor::create(
+ init.vm, init.global, JSReadableStateConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
+ init.setPrototype(prototype);
+ init.setStructure(structure);
+ init.setConstructor(constructor);
+ });
+
m_JSFFIFunctionStructure.initLater(
[](LazyClassStructure::Initializer& init) {
init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->functionPrototype()));
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index 160aef714..300d5d60d 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -192,10 +192,18 @@ public:
JSC::JSValue HTTPSResponseSinkPrototype() { return m_JSHTTPSResponseSinkClassStructure.prototypeInitializedOnMainThread(this); }
JSC::JSValue JSReadableHTTPSResponseSinkControllerPrototype() { return m_JSHTTPSResponseControllerPrototype.getInitializedOnMainThread(this); }
+ JSC::Structure* JSBufferListStructure() { return m_JSBufferListClassStructure.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSBufferList() { return m_JSBufferListClassStructure.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSBufferListPrototype() { return m_JSBufferListClassStructure.prototypeInitializedOnMainThread(this); }
+
JSC::Structure* JSStringDecoderStructure() { return m_JSStringDecoderClassStructure.getInitializedOnMainThread(this); }
JSC::JSObject* JSStringDecoder() { return m_JSStringDecoderClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue JSStringDecoderPrototype() { return m_JSStringDecoderClassStructure.prototypeInitializedOnMainThread(this); }
+ JSC::Structure* JSReadableStateStructure() { return m_JSReadableStateClassStructure.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSReadableState() { return m_JSReadableStateClassStructure.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSReadableStatePrototype() { return m_JSReadableStateClassStructure.prototypeInitializedOnMainThread(this); }
+
JSC::JSMap* readableStreamNativeMap() { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); }
JSC::JSMap* requireMap() { return m_requireMap.getInitializedOnMainThread(this); }
JSC::JSObject* encodeIntoObjectPrototype() { return m_encodeIntoObjectPrototype.getInitializedOnMainThread(this); }
@@ -348,7 +356,9 @@ private:
LazyClassStructure m_JSArrayBufferSinkClassStructure;
LazyClassStructure m_JSHTTPResponseSinkClassStructure;
LazyClassStructure m_JSHTTPSResponseSinkClassStructure;
+ LazyClassStructure m_JSBufferListClassStructure;
LazyClassStructure m_JSStringDecoderClassStructure;
+ LazyClassStructure m_JSReadableStateClassStructure;
LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype;
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index 2186177ab..16a7c0468 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -2234,7 +2234,7 @@ pub const ZigConsoleClient = struct {
while (props_iter.next()) |key| {
var property_value = props_iter.value;
- const tag = Tag.get(JSValue.fromRef(property_value.asObjectRef()), this.globalThis);
+ const tag = Tag.get(property_value, this.globalThis);
if (tag.cell.isHidden()) continue;
diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
index 456ef6aa4..8f976919c 100644
--- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
@@ -27,7 +27,7 @@ public:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSinkController;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSink;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForStringDecoder;
- std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForStringDecoderConstructor;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForReadableState;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForPendingVirtualModuleResult;
#include "ZigGeneratedClasses+DOMClientIsoSubspaces.h"
/* --- bun --- */
diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
index c5e01c902..98d7de159 100644
--- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
@@ -27,7 +27,7 @@ public:
std::unique_ptr<IsoSubspace> m_subspaceForJSSinkController;
std::unique_ptr<IsoSubspace> m_subspaceForJSSink;
std::unique_ptr<IsoSubspace> m_subspaceForStringDecoder;
- std::unique_ptr<IsoSubspace> m_subspaceForStringDecoderConstructor;
+ std::unique_ptr<IsoSubspace> m_subspaceForReadableState;
std::unique_ptr<IsoSubspace> m_subspaceForPendingVirtualModuleResult;
#include "ZigGeneratedClasses+DOMIsoSubspaces.h"
/*-- BUN --*/
diff --git a/src/bun.js/streams.exports.js b/src/bun.js/streams.exports.js
index 21521bc61..99e63adba 100644
--- a/src/bun.js/streams.exports.js
+++ b/src/bun.js/streams.exports.js
@@ -2489,6 +2489,7 @@ var require_readable = __commonJS({
Symbol: Symbol2,
} = require_primordials();
module.exports = Readable;
+ var ReadableState = globalThis[Symbol.for("Bun.lazy")]("bun:stream").ReadableState;
Readable.ReadableState = ReadableState;
var { EventEmitter: EE } = __require("events");
var { Stream, prependListener } = require_legacy();
@@ -2511,56 +2512,12 @@ var require_readable = __commonJS({
},
} = require_errors();
var { validateObject } = require_validators();
- var kPaused = Symbol2("kPaused");
var { StringDecoder } = __require("string_decoder");
var from = require_from();
ObjectSetPrototypeOf(Readable.prototype, Stream.prototype);
ObjectSetPrototypeOf(Readable, Stream);
var nop = () => {};
var { errorOrDestroy } = destroyImpl;
- function ReadableState(options, stream, isDuplex) {
- if (typeof isDuplex !== "boolean")
- isDuplex = stream instanceof require_duplex();
- this.objectMode = !!(options && options.objectMode);
- if (isDuplex)
- this.objectMode =
- this.objectMode || !!(options && options.readableObjectMode);
- this.highWaterMark = options
- ? getHighWaterMark(this, options, "readableHighWaterMark", isDuplex)
- : getDefaultHighWaterMark(false);
- this.buffer = new BufferList();
- this.length = 0;
- this.pipes = [];
- this.flowing = null;
- this.ended = false;
- this.endEmitted = false;
- this.reading = false;
- this.constructed = true;
- this.sync = true;
- this.needReadable = false;
- this.emittedReadable = false;
- this.readableListening = false;
- this.resumeScheduled = false;
- this[kPaused] = null;
- this.errorEmitted = false;
- this.emitClose = !options || options.emitClose !== false;
- this.autoDestroy = !options || options.autoDestroy !== false;
- this.destroyed = false;
- this.errored = null;
- this.closed = false;
- this.closeEmitted = false;
- this.defaultEncoding = (options && options.defaultEncoding) || "utf8";
- this.awaitDrainWriters = null;
- this.multiAwaitDrain = false;
- this.readingMore = false;
- this.dataEmitted = false;
- this.decoder = null;
- this.encoding = null;
- if (options && options.encoding) {
- this.decoder = new StringDecoder(options.encoding);
- this.encoding = options.encoding;
- }
- }
function Readable(options) {
if (!(this instanceof Readable)) return new Readable(options);
const isDuplex = this instanceof require_duplex();
@@ -2681,7 +2638,7 @@ var require_readable = __commonJS({
}
Readable.prototype.isPaused = function () {
const state = this._readableState;
- return state[kPaused] === true || state.flowing === false;
+ return state.paused === true || state.flowing === false;
};
Readable.prototype.setEncoding = function (enc) {
const decoder = new StringDecoder(enc);
@@ -3074,7 +3031,7 @@ var require_readable = __commonJS({
function updateReadableListening(self) {
const state = self._readableState;
state.readableListening = self.listenerCount("readable") > 0;
- if (state.resumeScheduled && state[kPaused] === false) {
+ if (state.resumeScheduled && state.paused === false) {
state.flowing = true;
} else if (self.listenerCount("data") > 0) {
self.resume();
@@ -3093,7 +3050,7 @@ var require_readable = __commonJS({
state.flowing = !state.readableListening;
resume(this, state);
}
- state[kPaused] = false;
+ state.paused = false;
return this;
};
function resume(stream, state) {
@@ -3119,7 +3076,7 @@ var require_readable = __commonJS({
this._readableState.flowing = false;
this.emit("pause");
}
- this._readableState[kPaused] = true;
+ this._readableState.paused = true;
return this;
};
function flow(stream) {
@@ -3340,21 +3297,6 @@ var require_readable = __commonJS({
},
},
});
- ObjectDefineProperties(ReadableState.prototype, {
- pipesCount: {
- get() {
- return this.pipes.length;
- },
- },
- paused: {
- get() {
- return this[kPaused] !== false;
- },
- set(value) {
- this[kPaused] = !!value;
- },
- },
- });
Readable._fromList = fromList;
function fromList(n, state) {
if (state.length === 0) return null;