Skip to content

Commit 52aa3f4

Browse files
authored
Auto merge of #27026 - CYBAI:dynamic-module, r=<try>
Introduce dynamic module <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
2 parents 242e7e2 + 84efc1e commit 52aa3f4

30 files changed

+659
-410
lines changed

components/script/devtools.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
3434
let cx = global.get_cx();
3535
let _ac = enter_realm(global);
3636
rooted!(in(*cx) let mut rval = UndefinedValue());
37-
global.evaluate_script_on_global_with_result(&eval, "<eval>", rval.handle_mut(), 1);
37+
global.evaluate_script_on_global_with_result(&eval, "<eval>", rval.handle_mut(), 1, None);
3838

3939
if rval.is_undefined() {
4040
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: 36 additions & 2 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;
@@ -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;
@@ -251,6 +253,18 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS
251253
}
252254
}
253255

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

339+
unsafe impl JSTraceable for Heap<*mut JSString> {
340+
unsafe fn trace(&self, trc: *mut JSTracer) {
341+
if self.get().is_null() {
342+
return;
343+
}
344+
trace_string(trc, "heap string", self);
345+
}
346+
}
347+
325348
unsafe impl JSTraceable for Heap<JSVal> {
326349
unsafe fn trace(&self, trc: *mut JSTracer) {
327350
trace_jsval(trc, "heap value", self);
@@ -1066,6 +1089,17 @@ where
10661089
}
10671090
}
10681091

1092+
impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
1093+
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1094+
// Briefly resurrect the real Box value so we can rely on the existing calculations.
1095+
// Then immediately forget about it again to avoid dropping the box.
1096+
let inner = unsafe { Box::from_raw(self.ptr) };
1097+
let size = inner.size_of(ops);
1098+
mem::forget(inner);
1099+
size
1100+
}
1101+
}
1102+
10691103
impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
10701104
fn default() -> RootedTraceableBox<T> {
10711105
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: 60 additions & 22 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::ImageBitmapBinding::{
@@ -51,7 +51,8 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
5151
use crate::dom::workletglobalscope::WorkletGlobalScope;
5252
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
5353
use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
54-
use crate::script_module::ModuleTree;
54+
use crate::script_module::{DynamicModuleList, ModuleTree};
55+
use crate::script_module::{ModuleScript, ScriptFetchOptions};
5556
use crate::script_runtime::{
5657
CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort,
5758
};
@@ -77,13 +78,16 @@ use embedder_traits::EmbedderMsg;
7778
use ipc_channel::ipc::{self, IpcSender};
7879
use ipc_channel::router::ROUTER;
7980
use js::glue::{IsWrapper, UnwrapObjectDynamic};
81+
use js::jsapi::CompileForNonSyntacticScope1;
8082
use js::jsapi::{CurrentGlobalOrNull, GetNonCCWObjectGlobal};
83+
use js::jsapi::{GetScriptPrivate, SetScriptPrivate};
8184
use js::jsapi::{HandleObject, Heap};
8285
use js::jsapi::{JSContext, JSObject};
86+
use js::jsval::PrivateValue;
8387
use js::jsval::{JSVal, UndefinedValue};
8488
use js::panic::maybe_resume_unwind;
8589
use js::rust::transform_str_to_source_text;
86-
use js::rust::wrappers::Evaluate2;
90+
use js::rust::wrappers::JS_ExecuteScript;
8791
use js::rust::{get_object_class, CompileOptionsWrapper, ParentRuntime, Runtime};
8892
use js::rust::{HandleValue, MutableHandleValue};
8993
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
@@ -298,6 +302,9 @@ pub struct GlobalScope {
298302

299303
/// The stack of active group labels for the Console APIs.
300304
console_group_stack: DomRefCell<Vec<DOMString>>,
305+
306+
/// List of ongoing dynamic module imports.
307+
dynamic_modules: DomRefCell<DynamicModuleList>,
301308
}
302309

303310
/// A wrapper for glue-code between the ipc router and the event-loop.
@@ -748,6 +755,7 @@ impl GlobalScope {
748755
frozen_supported_performance_entry_types: DomRefCell::new(Default::default()),
749756
https_state: Cell::new(HttpsState::None),
750757
console_group_stack: DomRefCell::new(Vec::new()),
758+
dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
751759
}
752760
}
753761

@@ -2529,7 +2537,7 @@ impl GlobalScope {
25292537

25302538
/// Evaluate JS code on this global scope.
25312539
pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) -> bool {
2532-
self.evaluate_script_on_global_with_result(code, "", rval, 1)
2540+
self.evaluate_script_on_global_with_result(code, "", rval, 1, None)
25332541
}
25342542

25352543
/// Evaluate a JS script on this global scope.
@@ -2540,6 +2548,7 @@ impl GlobalScope {
25402548
filename: &str,
25412549
rval: MutableHandleValue,
25422550
line_number: u32,
2551+
script_url: Option<ServoUrl>,
25432552
) -> bool {
25442553
let metadata = profile_time::TimerMetadata {
25452554
url: if filename.is_empty() {
@@ -2561,26 +2570,51 @@ impl GlobalScope {
25612570
let ar = enter_realm(&*self);
25622571

25632572
let _aes = AutoEntryScript::new(self);
2564-
let options =
2565-
unsafe { CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number) };
2566-
2567-
debug!("evaluating Dom string");
2568-
let result = unsafe {
2569-
Evaluate2(
2570-
*cx,
2571-
options.ptr,
2572-
&mut transform_str_to_source_text(code),
2573-
rval,
2574-
)
2575-
};
25762573

2577-
if !result {
2578-
debug!("error evaluating Dom string");
2579-
unsafe { report_pending_exception(*cx, true, InRealm::Entered(&ar)) };
2580-
}
2574+
unsafe {
2575+
let options = CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number);
2576+
2577+
rooted!(in(*cx) let compiled_script = {
2578+
CompileForNonSyntacticScope1(
2579+
*cx,
2580+
options.ptr,
2581+
&mut transform_str_to_source_text(code),
2582+
)
2583+
});
2584+
2585+
// When `ScriptPrivate` for the compiled script is undefined,
2586+
// we need to set it so that it can be used in dynamic import context.
2587+
if GetScriptPrivate(*compiled_script).is_undefined() {
2588+
let base_url = script_url.unwrap_or(self.api_base_url());
2589+
2590+
debug!("Set script private for {}", base_url);
2591+
2592+
let module_script_data = Box::new(ModuleScript::new(
2593+
base_url,
2594+
ScriptFetchOptions::default_classic_script(&self),
2595+
// We can't initialize an module owner here because
2596+
// the executing context of script might be different
2597+
// from the dynamic import script's executing context.
2598+
None,
2599+
));
2600+
2601+
SetScriptPrivate(
2602+
*compiled_script,
2603+
&PrivateValue(Box::into_raw(module_script_data) as *const _),
2604+
);
2605+
}
2606+
2607+
debug!("evaluating Dom string");
2608+
let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval);
2609+
2610+
if !result {
2611+
debug!("error evaluating Dom string");
2612+
report_pending_exception(*cx, true, InRealm::Entered(&ar));
2613+
}
25812614

2582-
maybe_resume_unwind();
2583-
result
2615+
maybe_resume_unwind();
2616+
result
2617+
}
25842618
},
25852619
)
25862620
}
@@ -2953,6 +2987,10 @@ impl GlobalScope {
29532987
pub(crate) fn pop_console_group(&self) {
29542988
let _ = self.console_group_stack.borrow_mut().pop();
29552989
}
2990+
2991+
pub(crate) fn dynamic_module_list(&self) -> RefMut<DynamicModuleList> {
2992+
self.dynamic_modules.borrow_mut()
2993+
}
29562994
}
29572995

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

0 commit comments

Comments
 (0)