Skip to content

Commit a9cb737

Browse files
authored
Auto merge of #27026 - CYBAI:dynamic-module, r=<try>
Introduce dynamic module --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #25439 - [x] There are tests for these changes
2 parents ccff007 + 419cd53 commit a9cb737

36 files changed

+813
-440
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/script/devtools.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::dom::element::Element;
1616
use crate::dom::globalscope::GlobalScope;
1717
use crate::dom::node::{window_from_node, Node, ShadowIncluding};
1818
use crate::realms::enter_realm;
19+
use crate::script_module::ScriptFetchOptions;
1920
use crate::script_thread::Documents;
2021
use devtools_traits::{AutoMargins, ComputedNodeLayout, TimelineMarkerType};
2122
use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, TimelineMarker};
@@ -34,7 +35,14 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
3435
let cx = global.get_cx();
3536
let _ac = enter_realm(global);
3637
rooted!(in(*cx) let mut rval = UndefinedValue());
37-
global.evaluate_script_on_global_with_result(&eval, "<eval>", rval.handle_mut(), 1);
38+
global.evaluate_script_on_global_with_result(
39+
&eval,
40+
"<eval>",
41+
rval.handle_mut(),
42+
1,
43+
ScriptFetchOptions::default_classic_script(&global),
44+
global.api_base_url(),
45+
);
3846

3947
if rval.is_undefined() {
4048
EvaluateJSReply::VoidValue

components/script/dom/bindings/codegen/Bindings.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ DOMInterfaces = {
4747
'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'],
4848
},
4949

50+
'DynamicModuleOwner': {
51+
'inRealms': ['PromiseAttribute'],
52+
},
53+
5054
'URL': {
5155
'weakReferenceable': True,
5256
},

components/script/dom/bindings/trace.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ use hyper::Method;
7777
use hyper::StatusCode;
7878
use indexmap::IndexMap;
7979
use ipc_channel::ipc::{IpcReceiver, IpcSender};
80-
use js::glue::{CallObjectTracer, CallValueTracer};
81-
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, JobQueue, TraceKind};
80+
use js::glue::{CallObjectTracer, CallStringTracer, CallValueTracer};
81+
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSString, JSTracer, JobQueue, TraceKind};
8282
use js::jsval::JSVal;
8383
use js::rust::{GCMethods, Handle, Runtime};
8484
use js::typedarray::TypedArray;
8585
use js::typedarray::TypedArrayElement;
86+
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
8687
use media::WindowGLContext;
8788
use metrics::{InteractiveMetrics, InteractiveWindow};
8889
use mime::Mime;
@@ -94,7 +95,7 @@ use msg::constellation_msg::{ServiceWorkerId, ServiceWorkerRegistrationId};
9495
use net_traits::filemanager_thread::RelativePos;
9596
use net_traits::image::base::{Image, ImageMetadata};
9697
use net_traits::image_cache::{ImageCache, PendingImageId};
97-
use net_traits::request::{Referrer, Request, RequestBuilder};
98+
use net_traits::request::{CredentialsMode, ParserMetadata, Referrer, Request, RequestBuilder};
9899
use net_traits::response::HttpsState;
99100
use net_traits::response::{Response, ResponseBody};
100101
use net_traits::storage_thread::StorageType;
@@ -134,6 +135,7 @@ use std::borrow::Cow;
134135
use std::cell::{Cell, RefCell, UnsafeCell};
135136
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
136137
use std::hash::{BuildHasher, Hash};
138+
use std::mem;
137139
use std::ops::{Deref, DerefMut, Range};
138140
use std::path::PathBuf;
139141
use std::rc::Rc;
@@ -252,6 +254,18 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS
252254
}
253255
}
254256

257+
/// Trace a `JSString`.
258+
pub fn trace_string(tracer: *mut JSTracer, description: &str, s: &Heap<*mut JSString>) {
259+
unsafe {
260+
trace!("tracing {}", description);
261+
CallStringTracer(
262+
tracer,
263+
s.ptr.get() as *mut _,
264+
GCTraceKindToAscii(TraceKind::String),
265+
);
266+
}
267+
}
268+
255269
unsafe impl<T: JSTraceable> JSTraceable for Rc<T> {
256270
unsafe fn trace(&self, trc: *mut JSTracer) {
257271
(**self).trace(trc)
@@ -323,6 +337,15 @@ unsafe impl JSTraceable for Heap<*mut JSObject> {
323337
}
324338
}
325339

340+
unsafe impl JSTraceable for Heap<*mut JSString> {
341+
unsafe fn trace(&self, trc: *mut JSTracer) {
342+
if self.get().is_null() {
343+
return;
344+
}
345+
trace_string(trc, "heap string", self);
346+
}
347+
}
348+
326349
unsafe impl JSTraceable for Heap<JSVal> {
327350
unsafe fn trace(&self, trc: *mut JSTracer) {
328351
trace_jsval(trc, "heap value", self);
@@ -534,6 +557,8 @@ unsafe_no_jsmanaged_fields!(StyleSharedRwLock);
534557
unsafe_no_jsmanaged_fields!(USVString);
535558
unsafe_no_jsmanaged_fields!(Referrer);
536559
unsafe_no_jsmanaged_fields!(ReferrerPolicy);
560+
unsafe_no_jsmanaged_fields!(CredentialsMode);
561+
unsafe_no_jsmanaged_fields!(ParserMetadata);
537562
unsafe_no_jsmanaged_fields!(Response);
538563
unsafe_no_jsmanaged_fields!(ResponseBody);
539564
unsafe_no_jsmanaged_fields!(ResourceThreads);
@@ -1068,6 +1093,17 @@ where
10681093
}
10691094
}
10701095

1096+
impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
1097+
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1098+
// Briefly resurrect the real Box value so we can rely on the existing calculations.
1099+
// Then immediately forget about it again to avoid dropping the box.
1100+
let inner = unsafe { Box::from_raw(self.ptr) };
1101+
let size = inner.size_of(ops);
1102+
mem::forget(inner);
1103+
size
1104+
}
1105+
}
1106+
10711107
impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
10721108
fn default() -> RootedTraceableBox<T> {
10731109
RootedTraceableBox::new(T::default())
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4+
5+
use crate::dom::bindings::codegen::Bindings::DynamicModuleOwnerBinding::DynamicModuleOwnerMethods;
6+
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
7+
use crate::dom::bindings::root::DomRoot;
8+
use crate::dom::globalscope::GlobalScope;
9+
use crate::dom::promise::Promise;
10+
use dom_struct::dom_struct;
11+
use std::rc::Rc;
12+
use uuid::Uuid;
13+
14+
/// An unique id for dynamic module
15+
#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, PartialEq)]
16+
pub struct DynamicModuleId(pub Uuid);
17+
18+
#[dom_struct]
19+
pub struct DynamicModuleOwner {
20+
reflector_: Reflector,
21+
22+
#[ignore_malloc_size_of = "Rc"]
23+
promise: Rc<Promise>,
24+
25+
/// Unique id for each dynamic module
26+
#[ignore_malloc_size_of = "Defined in uuid"]
27+
id: DynamicModuleId,
28+
}
29+
30+
impl DynamicModuleOwner {
31+
#[allow(unrooted_must_root)]
32+
fn new_inherited(promise: Rc<Promise>, id: DynamicModuleId) -> Self {
33+
DynamicModuleOwner {
34+
reflector_: Reflector::new(),
35+
promise,
36+
id,
37+
}
38+
}
39+
40+
#[allow(unrooted_must_root)]
41+
pub fn new(global: &GlobalScope, promise: Rc<Promise>, id: DynamicModuleId) -> DomRoot<Self> {
42+
reflect_dom_object(
43+
Box::new(DynamicModuleOwner::new_inherited(promise, id)),
44+
global,
45+
)
46+
}
47+
}
48+
49+
impl DynamicModuleOwnerMethods for DynamicModuleOwner {
50+
// https://html.spec.whatwg.org/multipage/#integration-with-the-javascript-module-system:import()
51+
fn Promise(&self) -> Rc<Promise> {
52+
self.promise.clone()
53+
}
54+
}

components/script/dom/globalscope.rs

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

5-
use crate::dom::bindings::cell::DomRefCell;
5+
use crate::dom::bindings::cell::{DomRefCell, RefMut};
66
use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
77
use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods;
88
use crate::dom::bindings::codegen::Bindings::GPUValidationErrorBinding::GPUError;
@@ -55,7 +55,8 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
5555
use crate::dom::workletglobalscope::WorkletGlobalScope;
5656
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
5757
use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
58-
use crate::script_module::ModuleTree;
58+
use crate::script_module::{DynamicModuleList, ModuleTree};
59+
use crate::script_module::{ModuleScript, ScriptFetchOptions};
5960
use crate::script_runtime::{
6061
CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort,
6162
};
@@ -81,13 +82,16 @@ use embedder_traits::EmbedderMsg;
8182
use ipc_channel::ipc::{self, IpcSender};
8283
use ipc_channel::router::ROUTER;
8384
use js::glue::{IsWrapper, UnwrapObjectDynamic};
85+
use js::jsapi::Compile1;
86+
use js::jsapi::SetScriptPrivate;
8487
use js::jsapi::{CurrentGlobalOrNull, GetNonCCWObjectGlobal};
8588
use js::jsapi::{HandleObject, Heap};
8689
use js::jsapi::{JSContext, JSObject};
90+
use js::jsval::PrivateValue;
8791
use js::jsval::{JSVal, UndefinedValue};
8892
use js::panic::maybe_resume_unwind;
8993
use js::rust::transform_str_to_source_text;
90-
use js::rust::wrappers::Evaluate2;
94+
use js::rust::wrappers::{JS_ExecuteScript, JS_GetScriptPrivate};
9195
use js::rust::{get_object_class, CompileOptionsWrapper, ParentRuntime, Runtime};
9296
use js::rust::{HandleValue, MutableHandleValue};
9397
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
@@ -306,6 +310,9 @@ pub struct GlobalScope {
306310

307311
/// The stack of active group labels for the Console APIs.
308312
console_group_stack: DomRefCell<Vec<DOMString>>,
313+
314+
/// List of ongoing dynamic module imports.
315+
dynamic_modules: DomRefCell<DynamicModuleList>,
309316
}
310317

311318
/// A wrapper for glue-code between the ipc router and the event-loop.
@@ -757,6 +764,7 @@ impl GlobalScope {
757764
frozen_supported_performance_entry_types: DomRefCell::new(Default::default()),
758765
https_state: Cell::new(HttpsState::None),
759766
console_group_stack: DomRefCell::new(Vec::new()),
767+
dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
760768
}
761769
}
762770

@@ -2537,8 +2545,21 @@ impl GlobalScope {
25372545
}
25382546

25392547
/// Evaluate JS code on this global scope.
2540-
pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) -> bool {
2541-
self.evaluate_script_on_global_with_result(code, "", rval, 1)
2548+
pub fn evaluate_js_on_global_with_result(
2549+
&self,
2550+
code: &str,
2551+
rval: MutableHandleValue,
2552+
fetch_options: ScriptFetchOptions,
2553+
script_base_url: ServoUrl,
2554+
) -> bool {
2555+
self.evaluate_script_on_global_with_result(
2556+
code,
2557+
"",
2558+
rval,
2559+
1,
2560+
fetch_options,
2561+
script_base_url,
2562+
)
25422563
}
25432564

25442565
/// Evaluate a JS script on this global scope.
@@ -2549,6 +2570,8 @@ impl GlobalScope {
25492570
filename: &str,
25502571
rval: MutableHandleValue,
25512572
line_number: u32,
2573+
fetch_options: ScriptFetchOptions,
2574+
script_base_url: ServoUrl,
25522575
) -> bool {
25532576
let metadata = profile_time::TimerMetadata {
25542577
url: if filename.is_empty() {
@@ -2570,26 +2593,59 @@ impl GlobalScope {
25702593
let ar = enter_realm(&*self);
25712594

25722595
let _aes = AutoEntryScript::new(self);
2573-
let options =
2574-
unsafe { CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number) };
2575-
2576-
debug!("evaluating Dom string");
2577-
let result = unsafe {
2578-
Evaluate2(
2579-
*cx,
2580-
options.ptr,
2581-
&mut transform_str_to_source_text(code),
2582-
rval,
2583-
)
2584-
};
25852596

2586-
if !result {
2587-
debug!("error evaluating Dom string");
2588-
unsafe { report_pending_exception(*cx, true, InRealm::Entered(&ar)) };
2589-
}
2597+
unsafe {
2598+
let options = CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number);
25902599

2591-
maybe_resume_unwind();
2592-
result
2600+
debug!("compiling Dom string");
2601+
rooted!(in(*cx) let compiled_script =
2602+
Compile1(
2603+
*cx,
2604+
options.ptr,
2605+
&mut transform_str_to_source_text(code),
2606+
)
2607+
);
2608+
2609+
if compiled_script.is_null() {
2610+
debug!("error compiling Dom string");
2611+
report_pending_exception(*cx, true, InRealm::Entered(&ar));
2612+
return false;
2613+
}
2614+
2615+
rooted!(in(*cx) let mut script_private = UndefinedValue());
2616+
JS_GetScriptPrivate(*compiled_script, script_private.handle_mut());
2617+
2618+
// When `ScriptPrivate` for the compiled script is undefined,
2619+
// we need to set it so that it can be used in dynamic import context.
2620+
if script_private.is_undefined() {
2621+
debug!("Set script private for {}", script_base_url);
2622+
2623+
let module_script_data = Rc::new(ModuleScript::new(
2624+
script_base_url,
2625+
fetch_options,
2626+
// We can't initialize an module owner here because
2627+
// the executing context of script might be different
2628+
// from the dynamic import script's executing context.
2629+
None,
2630+
));
2631+
2632+
SetScriptPrivate(
2633+
*compiled_script,
2634+
&PrivateValue(Rc::into_raw(module_script_data) as *const _),
2635+
);
2636+
}
2637+
2638+
debug!("evaluating Dom string");
2639+
let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval);
2640+
2641+
if !result {
2642+
debug!("error evaluating Dom string");
2643+
report_pending_exception(*cx, true, InRealm::Entered(&ar));
2644+
}
2645+
2646+
maybe_resume_unwind();
2647+
result
2648+
}
25932649
},
25942650
)
25952651
}
@@ -2991,6 +3047,10 @@ impl GlobalScope {
29913047
pub(crate) fn pop_console_group(&self) {
29923048
let _ = self.console_group_stack.borrow_mut().pop();
29933049
}
3050+
3051+
pub(crate) fn dynamic_module_list(&self) -> RefMut<DynamicModuleList> {
3052+
self.dynamic_modules.borrow_mut()
3053+
}
29943054
}
29953055

29963056
fn timestamp_in_ms(time: Timespec) -> u64 {

0 commit comments

Comments
 (0)