mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Create source actors from Debugger API notifications
Co-authored-by: atbrakhi <atbrakhi@igalia.com> Signed-off-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
bae25bb596
commit
aad368fabd
9 changed files with 144 additions and 75 deletions
|
@ -53,6 +53,8 @@ pub struct SourceActor {
|
|||
|
||||
pub content: Option<String>,
|
||||
pub content_type: Option<String>,
|
||||
|
||||
pub spidermonkey_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -103,6 +105,7 @@ impl SourceActor {
|
|||
url: ServoUrl,
|
||||
content: Option<String>,
|
||||
content_type: Option<String>,
|
||||
spidermonkey_id: u32,
|
||||
) -> SourceActor {
|
||||
SourceActor {
|
||||
name,
|
||||
|
@ -110,6 +113,7 @@ impl SourceActor {
|
|||
content,
|
||||
content_type,
|
||||
is_black_boxed: false,
|
||||
spidermonkey_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +123,17 @@ impl SourceActor {
|
|||
url: ServoUrl,
|
||||
content: Option<String>,
|
||||
content_type: Option<String>,
|
||||
spidermonkey_id: u32,
|
||||
) -> &SourceActor {
|
||||
let source_actor_name = actors.new_name("source");
|
||||
|
||||
let source_actor = SourceActor::new(source_actor_name.clone(), url, content, content_type);
|
||||
let source_actor = SourceActor::new(
|
||||
source_actor_name.clone(),
|
||||
url,
|
||||
content,
|
||||
content_type,
|
||||
spidermonkey_id,
|
||||
);
|
||||
actors.register(Box::new(source_actor));
|
||||
actors.register_source_actor(pipeline_id, &source_actor_name);
|
||||
|
||||
|
|
|
@ -549,6 +549,7 @@ impl DevtoolsInstance {
|
|||
source_info.url,
|
||||
source_info.content,
|
||||
source_info.content_type,
|
||||
source_info.spidermonkey_id,
|
||||
);
|
||||
let source_actor_name = source_actor.name.clone();
|
||||
let source_form = source_actor.source_form();
|
||||
|
|
|
@ -4,18 +4,22 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use base::id::{Index, PipelineId, PipelineNamespaceId};
|
||||
use constellation_traits::ScriptToConstellationChan;
|
||||
use crossbeam_channel::Sender;
|
||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use devtools_traits::{ScriptToDevtoolsControlMsg, SourceInfo};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::resources::{self, Resource};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::gc::HandleValue;
|
||||
use js::jsval::{UInt32Value, UndefinedValue};
|
||||
use js::rust::Runtime;
|
||||
use js::rust::wrappers::JS_DefineDebuggerObject;
|
||||
use net_traits::ResourceThreads;
|
||||
use profile_traits::{mem, time};
|
||||
use script_bindings::codegen::GenericBindings::DebuggerGlobalScopeBinding::{
|
||||
DebuggerGlobalScopeMethods, NotifyNewSource,
|
||||
};
|
||||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
use script_bindings::realms::InRealm;
|
||||
use script_bindings::reflector::DomObject;
|
||||
|
@ -102,6 +106,10 @@ impl DebuggerGlobalScope {
|
|||
GlobalScope::get_cx()
|
||||
}
|
||||
|
||||
pub(crate) fn as_global_scope(&self) -> &GlobalScope {
|
||||
self.upcast::<GlobalScope>()
|
||||
}
|
||||
|
||||
fn evaluate_js(&self, script: &str, can_gc: CanGc) -> bool {
|
||||
rooted!(in (*Self::get_cx()) let mut rval = UndefinedValue());
|
||||
self.global_scope.evaluate_js_on_global_with_result(
|
||||
|
@ -120,29 +128,83 @@ impl DebuggerGlobalScope {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn execute_with_global(&self, can_gc: CanGc, global: &GlobalScope) {
|
||||
pub(crate) fn execute_new_global(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
global: &GlobalScope,
|
||||
pipeline_id: PipelineId,
|
||||
) {
|
||||
let cx = Self::get_cx();
|
||||
rooted!(in(*cx) let mut property_value = UndefinedValue());
|
||||
rooted!(in(*cx) let pipeline_namespace_id = UInt32Value(pipeline_id.namespace_id.0));
|
||||
rooted!(in(*cx) let pipeline_index = UInt32Value(pipeline_id.index.0.get()));
|
||||
rooted!(in(*cx) let mut debuggee = UndefinedValue());
|
||||
|
||||
let _realm = enter_realm(self);
|
||||
// Convert the debuggee global’s reflector to a Value, wrapping it from its originating realm (debuggee realm)
|
||||
// into the active realm (debugger realm) so that it can be passed across compartments.
|
||||
global
|
||||
.reflector()
|
||||
.safe_to_jsval(cx, property_value.handle_mut());
|
||||
global.reflector().safe_to_jsval(cx, debuggee.handle_mut());
|
||||
|
||||
// TODO: what invariants do we need to uphold for the unsafe call?
|
||||
if let Err(()) = unsafe {
|
||||
set_dictionary_property(
|
||||
*cx,
|
||||
self.global_scope.reflector().get_jsobject(),
|
||||
"debuggee",
|
||||
property_value.handle(),
|
||||
)
|
||||
} {
|
||||
warn!("Failed to set debuggee");
|
||||
if let Err(()) = (|| -> Result<(), ()> {
|
||||
unsafe {
|
||||
set_dictionary_property(
|
||||
*cx,
|
||||
self.global_scope.reflector().get_jsobject(),
|
||||
"pipelineNamespaceId",
|
||||
pipeline_namespace_id.handle(),
|
||||
)?;
|
||||
set_dictionary_property(
|
||||
*cx,
|
||||
self.global_scope.reflector().get_jsobject(),
|
||||
"pipelineIndex",
|
||||
pipeline_index.handle(),
|
||||
)?;
|
||||
set_dictionary_property(
|
||||
*cx,
|
||||
self.global_scope.reflector().get_jsobject(),
|
||||
"debuggee",
|
||||
debuggee.handle(),
|
||||
)
|
||||
}
|
||||
})() {
|
||||
warn!("Failed to set properties");
|
||||
return;
|
||||
}
|
||||
self.execute(can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
impl DebuggerGlobalScopeMethods<crate::DomTypeHolder> for DebuggerGlobalScope {
|
||||
// check-tidy: no specs after this line
|
||||
fn NotifyNewSource(&self, args: &NotifyNewSource) {
|
||||
info!(
|
||||
"NotifyNewSource: ({},{}) {} {} {}",
|
||||
args.pipelineId.namespaceId,
|
||||
args.pipelineId.index,
|
||||
args.spidermonkeyId,
|
||||
args.url,
|
||||
args.text
|
||||
);
|
||||
if let Some(devtools_chan) = self.as_global_scope().devtools_chan() {
|
||||
let pipeline_id = PipelineId {
|
||||
namespace_id: PipelineNamespaceId(args.pipelineId.namespaceId),
|
||||
index: Index::new(args.pipelineId.index)
|
||||
.expect("`pipelineId.index` must not be zero"),
|
||||
};
|
||||
let source_info = SourceInfo {
|
||||
url: ServoUrl::parse(args.url.str()).expect("Failed to parse url"),
|
||||
external: true, // TODO
|
||||
worker_id: None, // TODO
|
||||
content: Some(args.text.to_string()),
|
||||
content_type: None, // TODO
|
||||
spidermonkey_id: args.spidermonkeyId,
|
||||
};
|
||||
devtools_chan
|
||||
.send(ScriptToDevtoolsControlMsg::CreateSourceActor(
|
||||
pipeline_id,
|
||||
source_info,
|
||||
))
|
||||
.expect("Failed to send to devtools server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::thread::{self, JoinHandle};
|
|||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||
use constellation_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
|
||||
use crossbeam_channel::{Receiver, Sender, unbounded};
|
||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, SourceInfo};
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use dom_struct::dom_struct;
|
||||
use headers::{HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader};
|
||||
use ipc_channel::ipc::IpcReceiver;
|
||||
|
@ -513,20 +513,6 @@ impl DedicatedWorkerGlobalScope {
|
|||
));
|
||||
global_scope.set_https_state(metadata.https_state);
|
||||
let source = String::from_utf8_lossy(&bytes);
|
||||
if let Some(chan) = global_scope.devtools_chan() {
|
||||
let pipeline_id = global_scope.pipeline_id();
|
||||
let source_info = SourceInfo {
|
||||
url: metadata.final_url,
|
||||
external: true, // Worker scripts are always external.
|
||||
worker_id: Some(global.upcast::<WorkerGlobalScope>().get_worker_id()),
|
||||
content: Some(source.to_string()),
|
||||
content_type: metadata.content_type.map(|c_type| c_type.0.to_string()),
|
||||
};
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::CreateSourceActor(
|
||||
pipeline_id,
|
||||
source_info,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Handle interrupt requests
|
||||
|
|
|
@ -1091,40 +1091,6 @@ impl HTMLScriptElement {
|
|||
Ok(script) => script,
|
||||
};
|
||||
|
||||
if let Some(chan) = self.global().devtools_chan() {
|
||||
let pipeline_id = self.global().pipeline_id();
|
||||
|
||||
let (url, content, content_type, is_external) = if script.external {
|
||||
let content = match &script.code {
|
||||
SourceCode::Text(text) => text.to_string(),
|
||||
SourceCode::Compiled(compiled) => compiled.original_text.to_string(),
|
||||
};
|
||||
|
||||
// content_type: https://html.spec.whatwg.org/multipage/#scriptingLanguages
|
||||
(script.url.clone(), Some(content), "text/javascript", true)
|
||||
} else {
|
||||
// TODO: if needed, fetch the page again, in the same way as in the original request.
|
||||
// Fetch it from cache, even if the original request was non-idempotent (e.g. POST).
|
||||
// If we can’t fetch it from cache, we should probably give up, because with a real
|
||||
// fetch, the server could return a different response.
|
||||
|
||||
// TODO: handle cases where Content-Type is not text/html.
|
||||
(doc.url(), None, "text/html", false)
|
||||
};
|
||||
|
||||
let source_info = SourceInfo {
|
||||
url,
|
||||
external: is_external,
|
||||
worker_id: None,
|
||||
content,
|
||||
content_type: Some(content_type.to_string()),
|
||||
};
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::CreateSourceActor(
|
||||
pipeline_id,
|
||||
source_info,
|
||||
));
|
||||
}
|
||||
|
||||
if script.type_ == ScriptType::Classic {
|
||||
unminify_js(&mut script);
|
||||
self.substitute_with_local_script(&mut script);
|
||||
|
|
|
@ -3430,8 +3430,9 @@ impl ScriptThread {
|
|||
incomplete.load_data.inherited_secure_context,
|
||||
incomplete.theme,
|
||||
);
|
||||
// TODO: call this for workers too
|
||||
self.debugger_global
|
||||
.execute_with_global(can_gc, window.upcast());
|
||||
.execute_new_global(can_gc, window.upcast(), incomplete.pipeline_id);
|
||||
|
||||
let _realm = enter_realm(&*window);
|
||||
|
||||
|
|
|
@ -6,4 +6,24 @@
|
|||
// web pages.
|
||||
[Global=DebuggerGlobalScope, Exposed=DebuggerGlobalScope]
|
||||
interface DebuggerGlobalScope: GlobalScope {
|
||||
undefined notifyNewSource(NotifyNewSource args);
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
dictionary NotifyNewSource {
|
||||
required PipelineId pipelineId;
|
||||
required unsigned long spidermonkeyId;
|
||||
required DOMString url;
|
||||
required DOMString text;
|
||||
|
||||
// FIXME: error[E0599]: the method `trace` exists for reference `&Option<TypedArray<Uint8, *mut JSObject>>`, but
|
||||
// its trait bounds were not satisfied
|
||||
// Uint8Array binary;
|
||||
|
||||
// TODO: contentType
|
||||
};
|
||||
|
||||
dictionary PipelineId {
|
||||
required unsigned long namespaceId;
|
||||
required unsigned long index;
|
||||
};
|
||||
|
|
|
@ -587,4 +587,5 @@ pub struct SourceInfo {
|
|||
pub worker_id: Option<WorkerId>,
|
||||
pub content: Option<String>,
|
||||
pub content_type: Option<String>,
|
||||
pub spidermonkey_id: u32,
|
||||
}
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
if (!("dbg" in this)) {
|
||||
dbg = new Debugger;
|
||||
debuggeesToPipelineIds = new Map;
|
||||
|
||||
dbg.onNewGlobalObject = function(global) {
|
||||
console.log("[debugger] onNewGlobalObject");
|
||||
console.log(this, global);
|
||||
console.log("[debugger] onNewGlobalObject", this, global);
|
||||
};
|
||||
|
||||
dbg.onNewScript = function(script, global) {
|
||||
console.log("[debugger] onNewScript");
|
||||
console.log(this, script, global);
|
||||
dbg.onNewScript = function(script, /* undefined; seems to be `script.global` now */ global) {
|
||||
try {
|
||||
console.log("[debugger] onNewScript url=", script.url, "source id=", script.source.id, "introductionType=", script.source.introductionType);
|
||||
try {
|
||||
console.log("[debugger] source binary=", typeof script.source.binary);
|
||||
} catch (error) {
|
||||
// Do nothing; the source is not wasm
|
||||
}
|
||||
notifyNewSource({
|
||||
pipelineId: debuggeesToPipelineIds.get(script.global),
|
||||
spidermonkeyId: script.source.id,
|
||||
url: script.source.url,
|
||||
text: script.source.text,
|
||||
});
|
||||
} catch (error) {
|
||||
logError(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,6 +30,13 @@ console.log("[debugger] Executing");
|
|||
|
||||
if ("debuggee" in this) {
|
||||
console.log("[debugger] Adding debuggee");
|
||||
dbg.addDebuggee(debuggee);
|
||||
console.log("[debugger] getDebuggees().length =", dbg.getDebuggees().length);
|
||||
const debuggerObject = dbg.addDebuggee(debuggee);
|
||||
debuggeesToPipelineIds.set(debuggerObject, {
|
||||
namespaceId: pipelineNamespaceId,
|
||||
index: pipelineIndex,
|
||||
});
|
||||
}
|
||||
|
||||
function logError(error) {
|
||||
console.log(`[debugger] ERROR at ${error.fileName}:${error.lineNumber}:${error.columnNumber}: ${error.name}: ${error.message}`);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue