@@ -318,16 +318,22 @@ class ReadableStreamController {
318
318
// passing along the closed promise that will be used to communicate state to the
319
319
// user code.
320
320
//
321
- // The Reader will hold a reference to the controller that will be cleared when the reader
322
- // is released or destroyed. The controller is guaranteed to either outlive or detach the
323
- // reader so the ReadableStreamController& reference should remain valid .
321
+ // The Reader holds a strong reference to the controller. The Controller will hold a weak
322
+ // reference to the reader. It is ok for the reader itself to be freed/garbage collected
323
+ // while still being attached to the controller, but not the other way around .
324
324
virtual void attach (
325
325
ReadableStreamController& controller,
326
326
jsg::Promise<void > closedPromise) = 0;
327
327
328
328
// When a Reader lock is released, the controller will signal to the reader that it has been
329
329
// detached.
330
330
virtual void detach () = 0;
331
+
332
+ virtual kj::Own<WeakRef<Reader>> addWeakRef () = 0;
333
+
334
+ private:
335
+ static kj::Badge<Reader> getBadge () { return kj::Badge<Reader>(); }
336
+ friend class ReaderImpl ;
331
337
};
332
338
333
339
struct ByobOptions {
@@ -479,12 +485,12 @@ class ReadableStreamController {
479
485
480
486
// Locks this controller to the given reader, returning true if the lock was successful, or false
481
487
// if the controller was already locked.
482
- virtual bool lockReader (jsg::Lock& js, Reader& reader) = 0;
488
+ virtual bool lockReader (jsg::Lock& js, kj::Own<WeakRef< Reader>> reader) = 0;
483
489
484
490
// Removes the lock and releases the reader from this controller.
485
491
// maybeJs will be nullptr when the isolate lock is not available.
486
492
// If maybeJs is set, the reader's closed promise will be resolved.
487
- virtual void releaseReader (Reader& reader, kj::Maybe< jsg::Lock&> maybeJs ) = 0;
493
+ virtual void releaseReader (jsg::Lock& js, Reader& reader ) = 0;
488
494
489
495
virtual kj::Maybe<PipeController&> tryPipeLock (jsg::Ref<WritableStream> destination) = 0;
490
496
@@ -574,8 +580,9 @@ class WritableStreamController {
574
580
// passing along the closed and ready promises that will be used to communicate state to the
575
581
// user code.
576
582
//
577
- // The controller is guaranteed to either outlive the Writer or will detach the Writer so the
578
- // WritableStreamController& reference should always remain valid.
583
+ // The Writer holds a strong reference to the controller. The Controller will hold a weak
584
+ // reference to the writer. It is ok for the writer itself to be freed/garbage collected
585
+ // while still being attached to the controller, but not the other way around.
579
586
virtual void attach (
580
587
WritableStreamController& controller,
581
588
jsg::Promise<void > closedPromise,
@@ -588,6 +595,12 @@ class WritableStreamController {
588
595
// The ready promise can be replaced whenever backpressure is signaled by the underlying
589
596
// controller.
590
597
virtual void replaceReadyPromise (jsg::Promise<void > readyPromise) = 0;
598
+
599
+ virtual kj::Own<WeakRef<Writer>> addWeakRef () = 0;
600
+
601
+ private:
602
+ static kj::Badge<Writer> getBadge () { return kj::Badge<Writer>(); }
603
+ friend class WritableStreamDefaultWriter ;
591
604
};
592
605
593
606
struct PendingAbort {
@@ -672,12 +685,10 @@ class WritableStreamController {
672
685
673
686
// Locks this controller to the given writer, returning true if the lock was successful, or false
674
687
// if the controller was already locked.
675
- virtual bool lockWriter (jsg::Lock& js, Writer& writer ) = 0;
688
+ virtual bool lockWriter (jsg::Lock& js, kj::Own<WeakRef< Writer>> ) = 0;
676
689
677
690
// Removes the lock and releases the writer from this controller.
678
- // maybeJs will be nullptr when the isolate lock is not available.
679
- // If maybeJs is set, the writer's closed and ready promises will be resolved.
680
- virtual void releaseWriter (Writer& writer, kj::Maybe<jsg::Lock&> maybeJs) = 0;
691
+ virtual void releaseWriter (jsg::Lock& js, Writer& writer) = 0;
681
692
682
693
virtual kj::Maybe<v8::Local<v8::Value>> isErroring (jsg::Lock& js) = 0;
683
694
@@ -710,28 +721,37 @@ struct Locked {};
710
721
711
722
// When a reader is locked to a ReadableStream, a ReaderLock instance
712
723
// is used internally to represent the locked state in the ReadableStreamController.
724
+ // ReaderLocked maintains a weak referene to the actual Reader instance. It's ok
725
+ // for the Reader to be garbage collected while the ReadableStream is still alive but
726
+ // not vis versa. The Reader holds a strong reference to the ReadableStream only while
727
+ // it is attached.
713
728
class ReaderLocked {
714
729
public:
715
730
ReaderLocked (
716
- ReadableStreamController::Reader& reader,
731
+ kj::Own<WeakRef< ReadableStreamController::Reader>> reader,
717
732
jsg::Promise<void >::Resolver closedFulfiller,
718
733
kj::Maybe<IoOwn<kj::Canceler>> canceler = kj::none)
719
- : reader(reader),
734
+ : reader(kj::mv( reader) ),
720
735
closedFulfiller (kj::mv(closedFulfiller)),
721
736
canceler(kj::mv(canceler)) {}
722
737
723
738
ReaderLocked (ReaderLocked&&) = default;
724
739
~ReaderLocked () noexcept (false ) {
725
- KJ_IF_SOME (r, reader) { r.detach (); }
740
+ if (reader.get () != nullptr ) {
741
+ reader->runIfAlive ([](auto & r) {
742
+ r.detach ();
743
+ });
744
+ }
726
745
}
727
746
KJ_DISALLOW_COPY (ReaderLocked);
728
747
729
748
void visitForGc (jsg::GcVisitor& visitor) {
730
749
visitor.visit (closedFulfiller);
731
750
}
732
751
733
- ReadableStreamController::Reader& getReader () {
734
- return KJ_ASSERT_NONNULL (reader);
752
+ kj::Maybe<ReadableStreamController::Reader&> getReader () {
753
+ if (reader.get () == nullptr ) return kj::none;
754
+ return reader->tryGet ();
735
755
}
736
756
737
757
kj::Maybe<jsg::Promise<void >::Resolver>& getClosedFulfiller () {
@@ -743,34 +763,43 @@ class ReaderLocked {
743
763
}
744
764
745
765
private:
746
- kj::Maybe< ReadableStreamController::Reader& > reader;
766
+ kj::Own<WeakRef< ReadableStreamController::Reader> > reader;
747
767
kj::Maybe<jsg::Promise<void >::Resolver> closedFulfiller;
748
768
kj::Maybe<IoOwn<kj::Canceler>> canceler;
749
769
};
750
770
751
771
// When a writer is locked to a WritableStream, a WriterLock instance
752
772
// is used internally to represent the locked state in the WritableStreamController.
773
+ // WriterLocked maintains a weak reference to the actual Writer instance. It's ok
774
+ // for the Writer to be garbage collected while the WritableStream is still alive but
775
+ // not vis versa. The Writer holds a strong reference to the WritableStream only while
776
+ // it is attached.
753
777
class WriterLocked {
754
778
public:
755
779
WriterLocked (
756
- WritableStreamController::Writer& writer,
780
+ kj::Own<WeakRef< WritableStreamController::Writer>> writer,
757
781
jsg::Promise<void >::Resolver closedFulfiller,
758
782
kj::Maybe<jsg::Promise<void >::Resolver> readyFulfiller = kj::none)
759
- : writer(writer),
783
+ : writer(kj::mv( writer) ),
760
784
closedFulfiller (kj::mv(closedFulfiller)),
761
785
readyFulfiller(kj::mv(readyFulfiller)) {}
762
786
763
787
WriterLocked (WriterLocked&&) = default;
764
788
~WriterLocked () noexcept (false ) {
765
- KJ_IF_SOME (w, writer) { w.detach (); }
789
+ if (writer.get () != nullptr ) {
790
+ writer->runIfAlive ([&](auto & w) {
791
+ w.detach ();
792
+ });
793
+ }
766
794
}
767
795
768
796
void visitForGc (jsg::GcVisitor& visitor) {
769
797
visitor.visit (closedFulfiller, readyFulfiller);
770
798
}
771
799
772
- WritableStreamController::Writer& getWriter () {
773
- return KJ_ASSERT_NONNULL (writer);
800
+ kj::Maybe<WritableStreamController::Writer&> getWriter () {
801
+ if (writer.get () == nullptr ) return kj::none;
802
+ return writer->tryGet ();
774
803
}
775
804
776
805
kj::Maybe<jsg::Promise<void >::Resolver>& getClosedFulfiller () {
@@ -782,14 +811,15 @@ class WriterLocked {
782
811
}
783
812
784
813
void setReadyFulfiller (jsg::PromiseResolverPair<void >& pair) {
785
- KJ_IF_SOME (w, writer) {
814
+ if (writer.get () == nullptr ) return ;
815
+ writer->runIfAlive ([&](auto & w) {
786
816
readyFulfiller = kj::mv (pair.resolver );
787
817
w.replaceReadyPromise (kj::mv (pair.promise ));
788
- }
818
+ });
789
819
}
790
820
791
821
private:
792
- kj::Maybe< WritableStreamController::Writer& > writer;
822
+ kj::Own<WeakRef< WritableStreamController::Writer> > writer;
793
823
kj::Maybe<jsg::Promise<void >::Resolver> closedFulfiller;
794
824
kj::Maybe<jsg::Promise<void >::Resolver> readyFulfiller;
795
825
};
0 commit comments