Skip to content

Commit 1cdf4ec

Browse files
committed
Replace writer ready and closed promises with LazyPromise
1 parent 8041fb8 commit 1cdf4ec

File tree

5 files changed

+68
-38
lines changed

5 files changed

+68
-38
lines changed

src/workerd/api/streams/common.h

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -621,22 +621,23 @@ class WritableStreamController {
621621
public:
622622
// When a Writer is locked to a controller, the controller will attach itself to the writer,
623623
// passing along the closed and ready promises that will be used to communicate state to the
624-
// user code.
624+
// user code. LazyPromise is used to defer the creation of the V8 Promise until the promise
625+
// is actually accessed by JavaScript.
625626
//
626627
// The controller is guaranteed to either outlive the Writer or will detach the Writer so the
627628
// WritableStreamController& reference should always remain valid.
628629
virtual void attach(jsg::Lock& js,
629630
WritableStreamController& controller,
630-
jsg::Promise<void> closedPromise,
631-
jsg::Promise<void> readyPromise) = 0;
631+
jsg::LazyPromise<void> closedPromise,
632+
jsg::LazyPromise<void> readyPromise) = 0;
632633

633634
// When a Writer lock is released, the controller will signal to the writer that is has been
634635
// detached.
635636
virtual void detach() = 0;
636637

637638
// The ready promise can be replaced whenever backpressure is signaled by the underlying
638639
// controller.
639-
virtual void replaceReadyPromise(jsg::Lock& js, jsg::Promise<void> readyPromise) = 0;
640+
virtual void replaceReadyPromise(jsg::Lock& js, jsg::LazyPromise<void> readyPromise) = 0;
640641
};
641642

642643
struct PendingAbort {
@@ -831,8 +832,8 @@ class WriterLocked {
831832
public:
832833
static constexpr kj::StringPtr NAME KJ_UNUSED = "writer-locked"_kj;
833834
WriterLocked(WritableStreamController::Writer& writer,
834-
jsg::Promise<void>::Resolver closedFulfiller,
835-
kj::Maybe<jsg::Promise<void>::Resolver> readyFulfiller = kj::none)
835+
jsg::LazyPromise<void>::Resolver closedFulfiller,
836+
kj::Maybe<jsg::LazyPromise<void>::Resolver> readyFulfiller = kj::none)
836837
: writer(writer),
837838
closedFulfiller(kj::mv(closedFulfiller)),
838839
readyFulfiller(kj::mv(readyFulfiller)) {}
@@ -852,15 +853,15 @@ class WriterLocked {
852853
return KJ_ASSERT_NONNULL(writer);
853854
}
854855

855-
kj::Maybe<jsg::Promise<void>::Resolver>& getClosedFulfiller() {
856+
kj::Maybe<jsg::LazyPromise<void>::Resolver>& getClosedFulfiller() {
856857
return closedFulfiller;
857858
}
858859

859-
kj::Maybe<jsg::Promise<void>::Resolver>& getReadyFulfiller() {
860+
kj::Maybe<jsg::LazyPromise<void>::Resolver>& getReadyFulfiller() {
860861
return readyFulfiller;
861862
}
862863

863-
void setReadyFulfiller(jsg::Lock& js, jsg::PromiseResolverPair<void>& pair) {
864+
void setReadyFulfiller(jsg::Lock& js, jsg::LazyPromiseResolverPair<void>& pair) {
864865
KJ_IF_SOME(w, writer) {
865866
readyFulfiller = kj::mv(pair.resolver);
866867
w.replaceReadyPromise(js, kj::mv(pair.promise));
@@ -880,8 +881,8 @@ class WriterLocked {
880881

881882
private:
882883
kj::Maybe<WritableStreamController::Writer&> writer;
883-
kj::Maybe<jsg::Promise<void>::Resolver> closedFulfiller;
884-
kj::Maybe<jsg::Promise<void>::Resolver> readyFulfiller;
884+
kj::Maybe<jsg::LazyPromise<void>::Resolver> closedFulfiller;
885+
kj::Maybe<jsg::LazyPromise<void>::Resolver> readyFulfiller;
885886
};
886887

887888
template <typename T>
@@ -911,6 +912,34 @@ void maybeRejectPromise(jsg::Lock& js,
911912
}
912913
}
913914

915+
// LazyPromise resolver overloads
916+
template <typename T>
917+
void maybeResolvePromise(
918+
jsg::Lock& js, kj::Maybe<typename jsg::LazyPromise<T>::Resolver>& maybeResolver, T&& t) {
919+
KJ_IF_SOME(resolver, maybeResolver) {
920+
resolver.resolve(js, kj::fwd<T>(t));
921+
maybeResolver = kj::none;
922+
}
923+
}
924+
925+
inline void maybeResolvePromise(
926+
jsg::Lock& js, kj::Maybe<typename jsg::LazyPromise<void>::Resolver>& maybeResolver) {
927+
KJ_IF_SOME(resolver, maybeResolver) {
928+
resolver.resolve(js);
929+
maybeResolver = kj::none;
930+
}
931+
}
932+
933+
template <typename T>
934+
void maybeRejectPromise(jsg::Lock& js,
935+
kj::Maybe<typename jsg::LazyPromise<T>::Resolver>& maybeResolver,
936+
v8::Local<v8::Value> reason) {
937+
KJ_IF_SOME(resolver, maybeResolver) {
938+
resolver.reject(js, jsg::Value(js.v8Isolate, reason));
939+
maybeResolver = kj::none;
940+
}
941+
}
942+
914943
template <typename T>
915944
jsg::Promise<T> rejectedMaybeHandledPromise(
916945
jsg::Lock& js, v8::Local<v8::Value> reason, bool handled) {

src/workerd/api/streams/internal.c++

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ void WritableStreamInternalController::updateBackpressure(jsg::Lock& js, bool ba
10061006
// Per the spec, when backpressure is updated and is true, we replace the existing
10071007
// ready promise on the writer with a new pending promise, regardless of whether
10081008
// the existing one is resolved or not.
1009-
auto prp = js.newPromiseAndResolver<void>();
1009+
jsg::LazyPromiseResolverPair<void> prp;
10101010
prp.promise.markAsHandled(js);
10111011
writerLock.setReadyFulfiller(js, prp);
10121012
return;
@@ -1362,10 +1362,10 @@ bool WritableStreamInternalController::lockWriter(jsg::Lock& js, Writer& writer)
13621362
return false;
13631363
}
13641364

1365-
auto closedPrp = js.newPromiseAndResolver<void>();
1365+
jsg::LazyPromiseResolverPair<void> closedPrp;
13661366
closedPrp.promise.markAsHandled(js);
13671367

1368-
auto readyPrp = js.newPromiseAndResolver<void>();
1368+
jsg::LazyPromiseResolverPair<void> readyPrp;
13691369
readyPrp.promise.markAsHandled(js);
13701370

13711371
auto lock = WriterLocked(writer, kj::mv(closedPrp.resolver), kj::mv(readyPrp.resolver));

src/workerd/api/streams/standard.c++

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ bool WritableLockImpl<Controller>::lockWriter(jsg::Lock& js, Controller& self, W
363363
return false;
364364
}
365365

366-
auto closedPrp = js.newPromiseAndResolver<void>();
366+
jsg::LazyPromiseResolverPair<void> closedPrp;
367367
closedPrp.promise.markAsHandled(js);
368-
auto readyPrp = js.newPromiseAndResolver<void>();
368+
jsg::LazyPromiseResolverPair<void> readyPrp;
369369
readyPrp.promise.markAsHandled(js);
370370

371371
auto lock = WriterLocked(writer, kj::mv(closedPrp.resolver), kj::mv(readyPrp.resolver));
@@ -3532,9 +3532,9 @@ void WritableStreamJsController::maybeRejectReadyPromise(
35323532
if (writerLock.getReadyFulfiller() != kj::none) {
35333533
maybeRejectPromise<void>(js, writerLock.getReadyFulfiller(), reason);
35343534
} else {
3535-
auto prp = js.newPromiseAndResolver<void>();
3535+
jsg::LazyPromiseResolverPair<void> prp;
35363536
prp.promise.markAsHandled(js);
3537-
prp.resolver.reject(js, reason);
3537+
prp.resolver.reject(js, jsg::Value(js.v8Isolate, reason));
35383538
writerLock.setReadyFulfiller(js, prp);
35393539
}
35403540
}
@@ -3748,7 +3748,7 @@ void WritableStreamJsController::updateBackpressure(jsg::Lock& js, bool backpres
37483748
// Per the spec, when backpressure is updated and is true, we replace the existing
37493749
// ready promise on the writer with a new pending promise, regardless of whether
37503750
// the existing one is resolved or not.
3751-
auto prp = js.newPromiseAndResolver<void>();
3751+
jsg::LazyPromiseResolverPair<void> prp;
37523752
prp.promise.markAsHandled(js);
37533753
return writerLock.setReadyFulfiller(js, prp);
37543754
}

src/workerd/api/streams/writable.c++

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ jsg::Promise<void> WritableStreamDefaultWriter::abort(
5454

5555
void WritableStreamDefaultWriter::attach(jsg::Lock& js,
5656
WritableStreamController& controller,
57-
jsg::Promise<void> closedPromise,
58-
jsg::Promise<void> readyPromise) {
57+
jsg::LazyPromise<void> closedPromise,
58+
jsg::LazyPromise<void> readyPromise) {
5959
KJ_ASSERT(state.is<Initial>());
6060
state = controller.addRef();
6161
this->closedPromise = kj::mv(closedPromise);
62-
replaceReadyPromise(js, kj::mv(readyPromise));
62+
this->readyPromise = kj::mv(readyPromise);
6363
}
6464

6565
jsg::Promise<void> WritableStreamDefaultWriter::close(jsg::Lock& js) {
@@ -108,8 +108,9 @@ void WritableStreamDefaultWriter::detach() {
108108
KJ_UNREACHABLE;
109109
}
110110

111-
jsg::MemoizedIdentity<jsg::Promise<void>>& WritableStreamDefaultWriter::getClosed() {
112-
return KJ_ASSERT_NONNULL(closedPromise, "the writer was never attached to a stream");
111+
jsg::MemoizedIdentity<jsg::Promise<void>>& WritableStreamDefaultWriter::getClosed(jsg::Lock& js) {
112+
return KJ_ASSERT_NONNULL(closedPromise, "the writer was never attached to a stream")
113+
.getPromise(js);
113114
}
114115

115116
kj::Maybe<int> WritableStreamDefaultWriter::getDesiredSize() {
@@ -130,12 +131,14 @@ kj::Maybe<int> WritableStreamDefaultWriter::getDesiredSize() {
130131
KJ_UNREACHABLE;
131132
}
132133

133-
jsg::MemoizedIdentity<jsg::Promise<void>>& WritableStreamDefaultWriter::getReady() {
134-
return KJ_ASSERT_NONNULL(readyPromise, "the writer was never attached to a stream");
134+
jsg::MemoizedIdentity<jsg::Promise<void>>& WritableStreamDefaultWriter::getReady(jsg::Lock& js) {
135+
return KJ_ASSERT_NONNULL(readyPromise, "the writer was never attached to a stream")
136+
.getPromise(js);
135137
}
136138

137139
kj::Maybe<jsg::Promise<void>> WritableStreamDefaultWriter::isReady(jsg::Lock& js) {
138-
return readyPromisePending.map([&](jsg::Promise<void>& p) { return p.whenResolved(js); });
140+
return readyPromise.map(
141+
[&](jsg::LazyPromise<void>& p) { return p.getPromise(js).inner().whenResolved(js); });
139142
}
140143

141144
void WritableStreamDefaultWriter::lockToStream(jsg::Lock& js, WritableStream& stream) {
@@ -172,9 +175,8 @@ void WritableStreamDefaultWriter::releaseLock(jsg::Lock& js) {
172175
}
173176

174177
void WritableStreamDefaultWriter::replaceReadyPromise(
175-
jsg::Lock& js, jsg::Promise<void> readyPromise) {
176-
this->readyPromisePending = kj::mv(readyPromise);
177-
this->readyPromise = KJ_ASSERT_NONNULL(this->readyPromisePending).whenResolved(js);
178+
jsg::Lock& js, jsg::LazyPromise<void> readyPromise) {
179+
this->readyPromise = kj::mv(readyPromise);
178180
}
179181

180182
jsg::Promise<void> WritableStreamDefaultWriter::write(

src/workerd/api/streams/writable.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class WritableStreamDefaultWriter: public jsg::Object, public WritableStreamCont
2121
static jsg::Ref<WritableStreamDefaultWriter> constructor(
2222
jsg::Lock& js, jsg::Ref<WritableStream> stream);
2323

24-
jsg::MemoizedIdentity<jsg::Promise<void>>& getClosed();
25-
jsg::MemoizedIdentity<jsg::Promise<void>>& getReady();
24+
jsg::MemoizedIdentity<jsg::Promise<void>>& getClosed(jsg::Lock& js);
25+
jsg::MemoizedIdentity<jsg::Promise<void>>& getReady(jsg::Lock& js);
2626
kj::Maybe<int> getDesiredSize();
2727

2828
jsg::Promise<void> abort(jsg::Lock& js, jsg::Optional<v8::Local<v8::Value>> reason);
@@ -66,14 +66,14 @@ class WritableStreamDefaultWriter: public jsg::Object, public WritableStreamCont
6666

6767
void attach(jsg::Lock& js,
6868
WritableStreamController& controller,
69-
jsg::Promise<void> closedPromise,
70-
jsg::Promise<void> readyPromise) override;
69+
jsg::LazyPromise<void> closedPromise,
70+
jsg::LazyPromise<void> readyPromise) override;
7171

7272
void detach() override;
7373

7474
void lockToStream(jsg::Lock& js, WritableStream& stream);
7575

76-
void replaceReadyPromise(jsg::Lock& js, jsg::Promise<void> readyPromise) override;
76+
void replaceReadyPromise(jsg::Lock& js, jsg::LazyPromise<void> readyPromise) override;
7777

7878
void visitForMemoryInfo(jsg::MemoryTracker& tracker) const;
7979

@@ -94,9 +94,8 @@ class WritableStreamDefaultWriter: public jsg::Object, public WritableStreamCont
9494
kj::Maybe<IoContext&> ioContext;
9595
kj::OneOf<Initial, Attached, Released, StreamStates::Closed> state = Initial();
9696

97-
kj::Maybe<jsg::MemoizedIdentity<jsg::Promise<void>>> closedPromise;
98-
kj::Maybe<jsg::MemoizedIdentity<jsg::Promise<void>>> readyPromise;
99-
kj::Maybe<jsg::Promise<void>> readyPromisePending;
97+
kj::Maybe<jsg::LazyPromise<void>> closedPromise;
98+
kj::Maybe<jsg::LazyPromise<void>> readyPromise;
10099

101100
void visitForGc(jsg::GcVisitor& visitor);
102101
};

0 commit comments

Comments
 (0)