Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: USDT tracing #474

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ rand = "0.8.5"
ryu-js = "1.0.1"
sonic-rs = "0.3.16"
unicode-normalization = "0.1.24"
usdt = { git = "https://github.com/aapoalas/usdt", branch = "feat/linux-stap-support" }
# usdt = { path = "../usdt/usdt" }
wtf8 = "0.1"
fast_float = "0.2.0"
3 changes: 3 additions & 0 deletions nova_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use nova_vm::{
types::{Object, String as JsString},
},
engine::context::GcScope,
register_probes,
};
use oxc_parser::Parser;
use oxc_semantic::{SemanticBuilder, SemanticBuilderReturn};
Expand Down Expand Up @@ -90,6 +91,8 @@ impl HostHooks for CliHostHooks {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Cli::parse();

register_probes().unwrap();

match args.command {
Command::Parse { path } => {
let file = std::fs::read_to_string(&path)?;
Expand Down
2 changes: 2 additions & 0 deletions nova_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ryu-js = { workspace = true }
small_string = { path = "../small_string" }
sonic-rs = { workspace = true, optional = true }
unicode-normalization = { workspace = true }
usdt = { workspace = true }
wtf8 = { workspace = true }

[features]
Expand All @@ -48,3 +49,4 @@ typescript = []

[build-dependencies]
small_string = { path = "../small_string" }
usdt = { workspace = true }
44 changes: 41 additions & 3 deletions nova_vm/src/ecmascript/builtins/builtin_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,27 @@ impl InternalMethods for BuiltinFunction {
this_argument: Value,
arguments_list: ArgumentsList,
) -> JsResult<Value> {
#[usdt::provider]
mod nova {
fn start_builtin_call(name: &str) {}
fn stop_builtin_call(name: &str) {}
}
nova::start_builtin_call!(|| {
agent[self]
.initial_name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
// 1. Return ? BuiltinCallOrConstruct(F, thisArgument, argumentsList, undefined).
builtin_call_or_construct(agent, gc, self, Some(this_argument), arguments_list, None)
let result =
builtin_call_or_construct(agent, gc, self, Some(this_argument), arguments_list, None);
nova::stop_builtin_call!(|| {
agent[self]
.initial_name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
result
}

/// ### [10.3.2 \[\[Construct\]\] ( argumentsList, newTarget )](https://tc39.es/ecma262/#sec-built-in-function-objects-construct-argumentslist-newtarget)
Expand All @@ -329,9 +348,28 @@ impl InternalMethods for BuiltinFunction {
arguments_list: ArgumentsList,
new_target: Function,
) -> JsResult<Object> {
#[usdt::provider]
mod nova {
fn start_builtin_constructor(name: &str) {}
fn stop_builtin_constructor(name: &str) {}
}
nova::start_builtin_constructor!(|| {
agent[self]
.initial_name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
// 1. Return ? BuiltinCallOrConstruct(F, uninitialized, argumentsList, newTarget).
builtin_call_or_construct(agent, gc, self, None, arguments_list, Some(new_target))
.map(|result| result.try_into().unwrap())
let result =
builtin_call_or_construct(agent, gc, self, None, arguments_list, Some(new_target))
.map(|result| result.try_into().unwrap());
nova::stop_builtin_constructor!(|| {
agent[self]
.initial_name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
result
}
}

Expand Down
50 changes: 42 additions & 8 deletions nova_vm/src/ecmascript/builtins/ecmascript_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ use oxc_ast::ast::{FormalParameters, FunctionBody};
use oxc_ecmascript::IsSimpleParameterList;
use oxc_span::Span;

use crate::engine::context::{GcScope, NoGcScope};
use crate::{
ecmascript::{
abstract_operations::type_conversion::to_object,
builtins::{
ordinary::{ordinary_create_from_constructor, ordinary_object_create_with_intrinsics},
ArgumentsList,
},
execution::{
agent::{
get_active_script_or_module,
Expand All @@ -38,17 +41,13 @@ use crate::{
BUILTIN_STRING_MEMORY,
},
},
engine::context::{GcScope, NoGcScope},
heap::{
indexes::ECMAScriptFunctionIndex, CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep,
WorkQueues,
},
};

use super::{
ordinary::{ordinary_create_from_constructor, ordinary_object_create_with_intrinsics},
ArgumentsList,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ECMAScriptFunction(ECMAScriptFunctionIndex);

Expand Down Expand Up @@ -421,6 +420,17 @@ impl InternalMethods for ECMAScriptFunction {
this_argument: Value,
arguments_list: ArgumentsList<'_>,
) -> JsResult<Value> {
#[usdt::provider]
mod nova {
fn start_function_call(name: &str) {}
fn stop_function_call(name: &str) {}
}
nova::start_function_call!(|| {
agent[self]
.name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
// 1. Let callerContext be the running execution context.
let _ = agent.running_execution_context();
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
Expand Down Expand Up @@ -462,6 +472,12 @@ impl InternalMethods for ECMAScriptFunction {
// 7. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
// NOTE: calleeContext must not be destroyed if it is suspended and retained for later resumption by an accessible Generator.
agent.execution_context_stack.pop();
nova::stop_function_call!(|| {
agent[self]
.name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
// 8. If result is a return completion, return result.[[Value]].
// 9. ReturnIfAbrupt(result).
// 10. Return undefined.
Expand All @@ -475,6 +491,17 @@ impl InternalMethods for ECMAScriptFunction {
arguments_list: ArgumentsList,
new_target: Function,
) -> JsResult<Object> {
#[usdt::provider]
mod nova {
fn start_ecmascript_constructor(name: &str) {}
fn stop_ecmascript_constructor(name: &str) {}
}
nova::start_ecmascript_constructor!(|| {
agent[self]
.name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
// 2. Let kind be F.[[ConstructorKind]].
let is_base = !agent[self]
.ecmascript_function
Expand Down Expand Up @@ -536,7 +563,7 @@ impl InternalMethods for ECMAScriptFunction {
let value = result?;
// 10. If result is a return completion, then
// a. If result.[[Value]] is an Object, return result.[[Value]].
if let Ok(value) = Object::try_from(value) {
let result = if let Ok(value) = Object::try_from(value) {
Ok(value)
} else
// b. If kind is base, return thisArgument.
Expand All @@ -562,7 +589,14 @@ impl InternalMethods for ECMAScriptFunction {

// 14. Return thisBinding.
Ok(this_binding)
}
};
nova::stop_ecmascript_constructor!(|| {
agent[self]
.name
.as_ref()
.map_or("anonymous", |name| name.as_str(agent))
});
result
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,11 @@ impl ObjectConstructor {
_this_value: Value,
arguments: ArgumentsList,
) -> JsResult<Value> {
#[usdt::provider]
mod nova {
fn get_prototype_of() {}
}
// nova::get_prototype_of!(|| ());
let obj = to_object(agent, gc.nogc(), arguments.get(0))?;
obj.internal_get_prototype_of(agent, gc)
.map(|proto| proto.map_or(Value::Null, |proto| proto.into_value()))
Expand Down
7 changes: 7 additions & 0 deletions nova_vm/src/heap/heap_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ pub fn heap_gc(
gc: GcScope<'_, '_>,
root_realms: &mut [Option<RealmIdentifier>],
) {
#[usdt::provider]
mod nova {
fn start_heap_gc() {}
fn stop_heap_gc() {}
}
nova::start_heap_gc!(|| ());
let Agent {
heap,
execution_context_stack,
Expand Down Expand Up @@ -995,6 +1001,7 @@ pub fn heap_gc(
}

sweep(agent, gc, &bits, root_realms);
nova::stop_heap_gc!(|| ());
}

fn sweep(
Expand Down
4 changes: 4 additions & 0 deletions nova_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ pub mod heap;
pub use engine::small_integer::SmallInteger;
use heap::Heap;
pub use small_string::SmallString;

// Expose the USDT probe registering function. In Linux this is a no-op but it
// is required on illumos and OS X for DTrace to work automatically.
pub use usdt::register_probes;