Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3402ff3
Re-implement readablestream: basics and default reader and controller
wusyong Aug 20, 2024
8f38d29
Improve read_a_chunk and stop_reading implemntation (#34077)
Taym95 Oct 31, 2024
d028cef
Implement ReadableStreamDefaultReader::Constructor (#34056)
Taym95 Oct 31, 2024
4175237
Readablestream fix CanGc (#34080)
Taym95 Oct 31, 2024
9907512
correct ReadableStream::error_native implementation and fix clippy wa…
Taym95 Nov 1, 2024
7a75ee1
turn assertion of stream present on controller on a early return with…
gterzian Nov 1, 2024
783ffeb
Fix already mutably borrowed crash (#34105)
Taym95 Nov 1, 2024
43a12cc
Refactor `get_in_memory_bytes` to return `Option<Vec<u8>> and avoid `…
Taym95 Nov 4, 2024
6d238bd
Set ReadableStream ReadableStreamDefaultReader in start_reading (#34125)
Taym95 Nov 7, 2024
e5ca543
Fix Unhandled rejection with value: object `TypeError: stream is not…
Taym95 Nov 11, 2024
dc24f47
Fix assert!(self.is_readable()) crash in ReadableStream::close (#34207)
Taym95 Nov 12, 2024
8cca089
fix call to to_js_object in underlying source algos (#34098)
gterzian Nov 12, 2024
2d1e2b0
do not assume presence of a stream when performing pull steps (#34244)
gterzian Nov 14, 2024
862ec82
gracefully handle failure of underlying source algorithms (#34243)
gterzian Nov 14, 2024
066b818
ensure result of calling start algo is an object (#34245)
gterzian Nov 14, 2024
79b16b4
return js failed error if underlying source constructor threw (#34246)
gterzian Nov 15, 2024
d758255
Use JSVal for ValueWithSize::value (#34259)
Taym95 Nov 15, 2024
28e7d77
fix release reader lock, (#34255)
gterzian Nov 16, 2024
a49c0de
in stream cancel, reject promist if locked (#34271)
gterzian Nov 18, 2024
0453167
Fix UnderlyingSourceContainer::call_start_algorithm (#34277)
Taym95 Nov 18, 2024
fab8e67
implement controller cancel steps, fix stream cancel method (#34301)
gterzian Nov 21, 2024
9209f75
fix conditional in perform pull steps (#34324)
gterzian Nov 21, 2024
0a47353
set reader closed promise to one resolved with undefined if stream cl…
gterzian Nov 21, 2024
8d4612e
fix init of stream and controller (#34323)
gterzian Nov 22, 2024
837d3fa
Stream: Fix reborrow in controller enqueue, and fix error and excepti…
gterzian Nov 25, 2024
4c31ae3
Stream: Fix incorrect "this" object in underlying source callbacks (#…
gterzian Nov 25, 2024
0cabcf3
fix conditional logic in enqueue to ensure pull is called into (#34375)
gterzian Nov 26, 2024
254e30b
Stream: Fix bytelength queueing strategy (#34376)
gterzian Nov 26, 2024
dc445ba
set correct default count queuing size strategy (#34389)
gterzian Nov 26, 2024
a228e59
use proto in stream constructor (#34441)
gterzian Dec 2, 2024
7ec2a08
fix edge cases in get_desired_size (#34440)
gterzian Dec 2, 2024
17b3443
Stream: fix algo and strategy calls error handling. (#34424)
gterzian Dec 3, 2024
967596f
fix native use of streams (#34468)
gterzian Dec 5, 2024
1bc6482
Implement readablestreamdefaulttee (#34405)
Taym95 Dec 9, 2024
42edcf0
Align ReadableStreamDefaultReader with spec and fix additional tests …
Taym95 Dec 9, 2024
f54b1f6
Streams: fetch stream chunks should be uint8 arrays (#34553)
gterzian Dec 10, 2024
5323e7c
Update wpt test for ReadableStream reimplementation (#34579)
Taym95 Dec 11, 2024
beed082
Fix ignore_malloc_size_of in readablestream tee (#34578)
Taym95 Dec 11, 2024
fc5c9ae
Remove incorrect use of handle array, fail test safely by giving only…
gterzian Dec 12, 2024
2715e24
Update more wpt test for ReadableStream reimplementation (#34598)
Taym95 Dec 13, 2024
448f076
Fix doc and rename Tee to DefaultTee (#34612)
Taym95 Dec 14, 2024
edf293a
fix: Address review comments
Taym95 Dec 14, 2024
c30bb4e
Update response-stream-with-broken-then.any.js.ini test expectation
Taym95 Dec 15, 2024
45b532e
fix reflect_dom_object can_gc
Taym95 Dec 15, 2024
3b51a89
Fix compositeReason for DefaultTeeUnderlyingSource (#34627)
Taym95 Dec 15, 2024
c14a36f
Last fixes stream (#34636)
gterzian Dec 16, 2024
11d511d
fix crown rooting related errors (#34662)
gterzian Dec 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/script/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ image = { workspace = true }
indexmap = { workspace = true }
ipc-channel = { workspace = true }
itertools = { workspace = true }
js = { package = "mozjs", git = "https://github.com/servo/mozjs", features = ["streams", "crown"] }
js = { package = "mozjs", git = "https://github.com/servo/mozjs", features = ["crown"] }
jstraceable_derive = { path = "../jstraceable_derive" }
keyboard-types = { workspace = true }
libc = { workspace = true }
Expand Down
11 changes: 6 additions & 5 deletions components/script/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ impl TransmitBodyConnectHandler {
// TODO: Step 2, If body is null.

// Step 3, get a reader for stream.
rooted_stream.start_reading().expect("Couldn't acquire a reader for the body stream.");
rooted_stream.acquire_default_reader(CanGc::note())
.expect("Couldn't acquire a reader for the body stream.");

// Note: this algorithm continues when the first chunk is requested by `net`.
}),
Expand Down Expand Up @@ -242,7 +243,7 @@ impl TransmitBodyConnectHandler {
let global = rooted_stream.global();

// Step 4, the result of reading a chunk from body’s stream with reader.
let promise = rooted_stream.read_a_chunk();
let promise = rooted_stream.read_a_chunk(CanGc::note());

// Step 5, the parallel steps waiting for and handling the result of the read promise,
// are a combination of the promise native handler here,
Expand Down Expand Up @@ -692,7 +693,7 @@ impl Callback for ConsumeBodyPromiseHandler {
let global = stream.global();

// Run the above step again.
let read_promise = stream.read_a_chunk();
let read_promise = stream.read_a_chunk(can_gc);

let promise_handler = Box::new(ConsumeBodyPromiseHandler {
result_promise: self.result_promise.clone(),
Expand Down Expand Up @@ -763,7 +764,7 @@ fn consume_body_with_promise<T: BodyMixin + DomObject>(
};

// Step 3.
if stream.start_reading().is_err() {
if stream.acquire_default_reader(can_gc).is_err() {
return promise.reject_error(Error::Type(
"The response's stream is disturbed or locked".to_string(),
));
Expand All @@ -774,7 +775,7 @@ fn consume_body_with_promise<T: BodyMixin + DomObject>(

// Step 1 of
// https://fetch.spec.whatwg.org/#concept-read-all-bytes-from-readablestream
let read_promise = stream.read_a_chunk();
let read_promise = stream.read_a_chunk(can_gc);

let promise_handler = Box::new(ConsumeBodyPromiseHandler {
result_promise: promise.clone(),
Expand Down
26 changes: 23 additions & 3 deletions components/script/dom/bindings/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use js::jsapi::{
};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
use js::rust::wrappers::{JS_GetProperty, JS_WrapObject};
use js::rust::{MutableHandleObject, Runtime};
use js::rust::{HandleObject, MutableHandleObject, Runtime};

use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
Expand Down Expand Up @@ -205,9 +205,29 @@ impl CallbackInterface {
}
}

pub trait ThisReflector {
fn jsobject(&self) -> *mut JSObject;
}

impl<T: DomObject> ThisReflector for T {
fn jsobject(&self) -> *mut JSObject {
self.reflector().get_jsobject().get()
}
}

impl<'a> ThisReflector for HandleObject<'a> {
fn jsobject(&self) -> *mut JSObject {
self.get()
}
}

/// Wraps the reflector for `p` into the realm of `cx`.
pub fn wrap_call_this_object<T: DomObject>(cx: JSContext, p: &T, mut rval: MutableHandleObject) {
rval.set(p.reflector().get_jsobject().get());
pub fn wrap_call_this_object<T: ThisReflector>(
cx: JSContext,
p: &T,
mut rval: MutableHandleObject,
) {
rval.set(p.jsobject());
assert!(!rval.get().is_null());

unsafe {
Expand Down
16 changes: 16 additions & 0 deletions components/script/dom/bindings/codegen/Bindings.conf
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,22 @@ DOMInterfaces = {
'canGc': ['SimulateDeviceConnection', 'DisconnectAllDevices'],
},

'ReadableStream': {
'canGc': ['GetReader', 'Cancel', 'Tee'],
},

"ReadableStreamDefaultController": {
"canGc": ["Enqueue"]
},

"ReadableStreamBYOBReader": {
"canGc": ["Read", "Closed", "Cancel"]
},

"ReadableStreamDefaultReader": {
"canGc": ["Read", "Cancel"]
},

}

Dictionaries = {
Expand Down
5 changes: 3 additions & 2 deletions components/script/dom/bindings/codegen/CodegenRust.py
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
"""
{
use crate::realms::{AlreadyInRealm, InRealm};
use crate::dom::readablestream::ReadableStream;
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
match ReadableStream::from_js(cx, $${val}.get().to_object(), InRealm::Already(&in_realm_proof)) {
Ok(val) => val,
Expand All @@ -949,7 +950,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
templateBody = wrapObjectTemplate(templateBody, "None",
isDefinitelyObject, type, failureCode)

declType = CGGeneric("DomRoot<ReadableStream>")
declType = CGGeneric("DomRoot<dom::readablestream::ReadableStream>")

return handleOptional(templateBody, declType,
handleDefault("None"))
Expand Down Expand Up @@ -7718,7 +7719,7 @@ def getMethodImpls(self, method):
f"unsafe {{ self.{method.name}({', '.join(argnamesWithoutThis)}) }}")
return [ClassMethod(f'{method.name}_', method.returnType, args,
bodyInHeader=True,
templateArgs=["T: DomObject"],
templateArgs=["T: ThisReflector"],
body=bodyWithThis,
visibility='pub'),
ClassMethod(f'{method.name}__', method.returnType, argsWithoutThis,
Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/bindings/codegen/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def main():
from Configuration import Configuration
from CodegenRust import CGBindingRoot

parser = WebIDL.Parser(make_dir(os.path.join(out_dir, "cache")))
parser = WebIDL.Parser(make_dir(os.path.join(out_dir, "cache")), use_builtin_readable_stream=False)
webidls = [name for name in os.listdir(webidls_dir) if name.endswith(".webidl")]
for webidl in webidls:
filename = os.path.join(webidls_dir, webidl)
Expand Down
50 changes: 50 additions & 0 deletions components/script/dom/bindings/function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// Defines a macro `native_fn!` to create a JavaScript function from a Rust function pointer.
/// # Example
/// ```
/// let js_function: Rc<Function> = native_fn!(my_rust_function, c"myFunction", 2, 0);
/// ```
#[macro_export]
macro_rules! native_fn {
($call:expr, $name:expr, $nargs:expr, $flags:expr) => {{
let cx = $crate::dom::types::GlobalScope::get_cx();
let fun_obj = $crate::native_raw_obj_fn!(cx, $call, $name, $nargs, $flags);
#[allow(unsafe_code)]
unsafe {
Function::new(cx, fun_obj)
}
}};
}

/// Defines a macro `native_raw_obj_fn!` to create a raw JavaScript function object.
/// # Example
/// ```
/// let raw_function_obj: *mut JSObject = native_raw_obj_fn!(cx, my_rust_function, c"myFunction", 2, 0);
/// ```
#[macro_export]
macro_rules! native_raw_obj_fn {
($cx:expr, $call:expr, $name:expr, $nargs:expr, $flags:expr) => {{
#[allow(unsafe_code)]
#[allow(clippy::macro_metavars_in_unsafe)]
unsafe extern "C" fn wrapper(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
$call(cx, argc, vp)
}
#[allow(unsafe_code)]
#[allow(clippy::macro_metavars_in_unsafe)]
unsafe {
let name: &std::ffi::CStr = $name;
let raw_fun = $crate::dom::bindings::import::module::jsapi::JS_NewFunction(
*$cx,
Some(wrapper),
$nargs,
$flags,
name.as_ptr() as *const std::ffi::c_char,
);
assert!(!raw_fun.is_null());
$crate::dom::bindings::import::module::jsapi::JS_GetFunctionObject(raw_fun)
}
}};
}
2 changes: 1 addition & 1 deletion components/script/dom/bindings/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod base {

pub use crate::dom::bindings::callback::{
wrap_call_this_object, CallSetup, CallbackContainer, CallbackFunction, CallbackInterface,
CallbackObject, ExceptionHandling,
CallbackObject, ExceptionHandling, ThisReflector,
};
pub use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
ChannelCountMode, ChannelCountModeValues, ChannelInterpretation,
Expand Down
1 change: 0 additions & 1 deletion components/script/dom/bindings/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ pub unsafe fn create_global_object(
let mut options = RealmOptions::default();
options.creationOptions_.traceGlobal_ = Some(trace);
options.creationOptions_.sharedMemoryAndAtomics_ = false;
options.creationOptions_.streams_ = true;
select_compartment(cx, &mut options);

let principal = ServoJSPrincipals::new(origin);
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub mod conversions;
pub mod error;
pub mod finalize;
pub mod frozenarray;
pub mod function;
pub mod guard;
pub mod import;
pub mod inheritance;
Expand Down
113 changes: 113 additions & 0 deletions components/script/dom/bytelengthqueuingstrategy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::rc::Rc;

use dom_struct::dom_struct;
use js::gc::{HandleValue, MutableHandleValue};
use js::jsapi::{CallArgs, JSContext};
use js::jsval::JSVal;
use js::rust::HandleObject;

use super::bindings::codegen::Bindings::FunctionBinding::Function;
use super::bindings::codegen::Bindings::QueuingStrategyBinding::{
ByteLengthQueuingStrategyMethods, QueuingStrategyInit,
};
use super::bindings::import::module::{DomObject, DomRoot, Fallible, Reflector};
use super::bindings::reflector::reflect_dom_object_with_proto;
use super::types::GlobalScope;
use crate::dom::bindings::import::module::get_dictionary_property;
use crate::native_fn;
use crate::script_runtime::CanGc;

#[dom_struct]
pub struct ByteLengthQueuingStrategy {
reflector_: Reflector,
high_water_mark: f64,
}

impl ByteLengthQueuingStrategy {
pub fn new_inherited(init: f64) -> Self {
Self {
reflector_: Reflector::new(),
high_water_mark: init,
}
}

pub fn new(
global: &GlobalScope,
proto: Option<HandleObject>,
init: f64,
can_gc: CanGc,
) -> DomRoot<Self> {
reflect_dom_object_with_proto(Box::new(Self::new_inherited(init)), global, proto, can_gc)
}
}

impl ByteLengthQueuingStrategyMethods<crate::DomTypeHolder> for ByteLengthQueuingStrategy {
/// <https://streams.spec.whatwg.org/#blqs-constructor>
fn Constructor(
global: &GlobalScope,
proto: Option<HandleObject>,
can_gc: CanGc,
init: &QueuingStrategyInit,
) -> DomRoot<Self> {
Self::new(global, proto, init.highWaterMark, can_gc)
}
/// <https://streams.spec.whatwg.org/#blqs-high-water-mark>
fn HighWaterMark(&self) -> f64 {
self.high_water_mark
}

/// <https://streams.spec.whatwg.org/#blqs-size>
fn GetSize(&self) -> Fallible<Rc<Function>> {
let global = self.reflector_.global();
// Return this's relevant global object's byte length queuing strategy
// size function.
if let Some(fun) = global.get_byte_length_queuing_strategy_size() {
return Ok(fun);
}

// Step 1. Let steps be the following steps, given chunk
// Note: See ByteLengthQueuingStrategySize instead.

// Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « »,
// globalObject’s relevant Realm).
let fun = native_fn!(byte_length_queuing_strategy_size, c"size", 1, 0);
// Step 3. Set globalObject’s byte length queuing strategy size function to
// a Function that represents a reference to F,
// with callback context equal to globalObject’s relevant settings object.
global.set_byte_length_queuing_strategy_size(fun.clone());
Ok(fun)
}
}

/// <https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function>
#[allow(unsafe_code)]
pub unsafe fn byte_length_queuing_strategy_size(
cx: *mut JSContext,
argc: u32,
vp: *mut JSVal,
) -> bool {
let args = CallArgs::from_vp(vp, argc);

// Step 1.1: Return ? GetV(chunk, "byteLength").
let val = HandleValue::from_raw(args.get(0));

// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-getv
// Let O be ? ToObject(V).
if !val.is_object() {
return false;
}
rooted!(in(cx) let object = val.to_object());

// Return ? O.[[Get]](P, V).
get_dictionary_property(
cx,
object.handle(),
"byteLength",
MutableHandleValue::from_raw(args.rval()),
)
.unwrap_or(false)
}
Loading