Browse Source

Profiler using measureme (#317)

Profiler
pull/450/head
Jason Williams 4 years ago committed by GitHub
parent
commit
32b0741cc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      .gitignore
  2. 18
      .vscode/tasks.json
  3. 89
      Cargo.lock
  4. 4
      README.md
  5. 7
      boa/Cargo.toml
  6. 2
      boa/src/builtins/array/mod.rs
  7. 2
      boa/src/builtins/bigint/mod.rs
  8. 2
      boa/src/builtins/boolean/mod.rs
  9. 2
      boa/src/builtins/console/mod.rs
  10. 2
      boa/src/builtins/error/mod.rs
  11. 2
      boa/src/builtins/error/range.rs
  12. 9
      boa/src/builtins/function/mod.rs
  13. 3
      boa/src/builtins/json/mod.rs
  14. 3
      boa/src/builtins/math/mod.rs
  15. 2
      boa/src/builtins/number/mod.rs
  16. 7
      boa/src/builtins/object/internal_methods_trait.rs
  17. 5
      boa/src/builtins/object/mod.rs
  18. 2
      boa/src/builtins/regexp/mod.rs
  19. 2
      boa/src/builtins/string/mod.rs
  20. 2
      boa/src/builtins/symbol/mod.rs
  21. 2
      boa/src/builtins/value/conversions.rs
  22. 11
      boa/src/builtins/value/mod.rs
  23. 3
      boa/src/environment/lexical_environment.rs
  24. 2
      boa/src/exec/array/mod.rs
  25. 2
      boa/src/exec/block/mod.rs
  26. 2
      boa/src/exec/declaration/mod.rs
  27. 2
      boa/src/exec/expression/mod.rs
  28. 2
      boa/src/exec/iteration/mod.rs
  29. 2
      boa/src/exec/mod.rs
  30. 2
      boa/src/exec/operator/mod.rs
  31. 2
      boa/src/exec/statement_list.rs
  32. 2
      boa/src/exec/try_node/mod.rs
  33. 15
      boa/src/lib.rs
  34. 95
      boa/src/profiler.rs
  35. 3
      boa/src/realm.rs
  36. 6
      boa/src/syntax/lexer/mod.rs
  37. 6
      boa/src/syntax/parser/expression/assignment/arrow_function.rs
  38. 6
      boa/src/syntax/parser/expression/assignment/conditional.rs
  39. 6
      boa/src/syntax/parser/expression/assignment/exponentiation.rs
  40. 6
      boa/src/syntax/parser/expression/assignment/mod.rs
  41. 9
      boa/src/syntax/parser/expression/left_hand_side/arguments.rs
  42. 6
      boa/src/syntax/parser/expression/left_hand_side/call.rs
  43. 6
      boa/src/syntax/parser/expression/left_hand_side/member.rs
  44. 6
      boa/src/syntax/parser/expression/left_hand_side/mod.rs
  45. 6
      boa/src/syntax/parser/expression/mod.rs
  46. 9
      boa/src/syntax/parser/expression/primary/array_initializer/mod.rs
  47. 6
      boa/src/syntax/parser/expression/primary/function_expression.rs
  48. 6
      boa/src/syntax/parser/expression/primary/object_initializer/mod.rs
  49. 6
      boa/src/syntax/parser/statement/block/mod.rs
  50. 6
      boa/src/syntax/parser/statement/break_stm/mod.rs
  51. 6
      boa/src/syntax/parser/statement/continue_stm/mod.rs
  52. 6
      boa/src/syntax/parser/statement/declaration/hoistable.rs
  53. 6
      boa/src/syntax/parser/statement/declaration/lexical.rs
  54. 6
      boa/src/syntax/parser/statement/declaration/mod.rs
  55. 6
      boa/src/syntax/parser/statement/if_stm/mod.rs
  56. 10
      boa/src/syntax/parser/statement/iteration/do_while_statement.rs
  57. 6
      boa/src/syntax/parser/statement/iteration/for_statement.rs
  58. 10
      boa/src/syntax/parser/statement/iteration/while_statement.rs
  59. 10
      boa/src/syntax/parser/statement/mod.rs
  60. 10
      boa/src/syntax/parser/statement/return_stm/mod.rs
  61. 6
      boa/src/syntax/parser/statement/switch/mod.rs
  62. 10
      boa/src/syntax/parser/statement/throw/mod.rs
  63. 6
      boa/src/syntax/parser/statement/try_stm/catch.rs
  64. 6
      boa/src/syntax/parser/statement/try_stm/finally.rs
  65. 6
      boa/src/syntax/parser/statement/try_stm/mod.rs
  66. 6
      boa/src/syntax/parser/statement/variable.rs
  67. BIN
      docs/img/profiler.png
  68. 30
      docs/profiling.md

6
.gitignore vendored

@ -17,3 +17,9 @@ yarn-error.log
# tests/js/test.js is used for testing changes locally # tests/js/test.js is used for testing changes locally
tests/js/test.js tests/js/test.js
# Profiling
*.string_data
*.string_index
*.events
chrome_profiler.json

18
.vscode/tasks.json vendored

@ -20,6 +20,24 @@
"clear": true "clear": true
} }
}, },
{
"type": "process",
"label": "Cargo Run (Profiler)",
"command": "cargo",
"args": ["run", "--features", "Boa/profiler", "../tests/js/test.js"],
"problemMatcher": ["$rustc"],
"group": {
"kind": "build",
"isDefault": true
},
"options": {
"env": { "RUST_BACKTRACE": "full" },
"cwd": "${workspaceFolder}/boa_cli"
},
"presentation": {
"clear": true
}
},
{ {
"type": "process", "type": "process",
"label": "Get Tokens", "label": "Get Tokens",

89
Cargo.lock generated

@ -8,8 +8,10 @@ dependencies = [
"criterion", "criterion",
"gc", "gc",
"jemallocator", "jemallocator",
"measureme",
"num-bigint", "num-bigint",
"num-traits", "num-traits",
"once_cell",
"rand", "rand",
"regex", "regex",
"rustc-hash", "rustc-hash",
@ -136,6 +138,15 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]] [[package]]
name = "criterion" name = "criterion"
version = "0.3.2" version = "0.3.2"
@ -359,6 +370,15 @@ version = "0.2.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
[[package]]
name = "lock_api"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
dependencies = [
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.8" version = "0.4.8"
@ -374,12 +394,34 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]]
name = "measureme"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fef709d3257013bba7cff14fc504e07e80631d3fe0f6d38ce63b8f6510ccb932"
dependencies = [
"byteorder",
"memmap",
"parking_lot",
"rustc-hash",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.3" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.5.4" version = "0.5.4"
@ -430,12 +472,44 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "once_cell"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
[[package]] [[package]]
name = "oorandom" name = "oorandom"
version = "11.1.1" version = "11.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af325bc33c7f60191be4e2c984d48aaa21e2854f473b85398344b60c9b6358" checksum = "94af325bc33c7f60191be4e2c984d48aaa21e2854f473b85398344b60c9b6358"
[[package]]
name = "parking_lot"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
dependencies = [
"lock_api",
"parking_lot_core",
"rustc_version",
]
[[package]]
name = "parking_lot_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
dependencies = [
"cfg-if",
"cloudabi",
"libc",
"redox_syscall",
"rustc_version",
"smallvec",
"winapi",
]
[[package]] [[package]]
name = "plotters" name = "plotters"
version = "0.2.14" version = "0.2.14"
@ -563,6 +637,12 @@ dependencies = [
"num_cpus", "num_cpus",
] ]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.3.7" version = "1.3.7"
@ -672,6 +752,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "smallvec"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
dependencies = [
"maybe-uninit",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"

4
README.md

@ -71,6 +71,10 @@ See [CHANGELOG.md](./CHANGELOG.md).
- Run with `cargo run -- test.js` where `test.js` is an existing JS file. - Run with `cargo run -- test.js` where `test.js` is an existing JS file.
- If any JS doesn't work then it's a bug. Please raise an issue! - If any JS doesn't work then it's a bug. Please raise an issue!
## Profiling
See [Profiling](./docs/profiling.md)
## Command-line Options ## Command-line Options
``` ```

7
boa/Cargo.toml

@ -10,6 +10,9 @@ license = "Unlicense/MIT"
exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"] exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"]
edition = "2018" edition = "2018"
[features]
profiler = ["measureme", "once_cell"]
[dependencies] [dependencies]
gc = { version = "0.3.5", features = ["derive"] } gc = { version = "0.3.5", features = ["derive"] }
serde_json = "1.0.53" serde_json = "1.0.53"
@ -18,10 +21,12 @@ num-traits = "0.2.11"
regex = "1.3.7" regex = "1.3.7"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
num-bigint = { version = "0.2.6", features = ["serde"] } num-bigint = { version = "0.2.6", features = ["serde"] }
bitflags = "1.2.1"
# Optional Dependencies # Optional Dependencies
serde = { version = "1.0.110", features = ["derive"], optional = true } serde = { version = "1.0.110", features = ["derive"], optional = true }
bitflags = "1.2.1" measureme = { version = "0.7.1", optional = true }
once_cell = { version = "1.4.0", optional = true }
[dev-dependencies] [dev-dependencies]
criterion = "0.3.2" criterion = "0.3.2"

2
boa/src/builtins/array/mod.rs

@ -20,6 +20,7 @@ use crate::{
value::{same_value_zero, ResultValue, Value, ValueData}, value::{same_value_zero, ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use std::{ use std::{
borrow::Borrow, borrow::Borrow,
@ -1041,6 +1042,7 @@ impl Array {
/// Initialise the `Array` object on the global object. /// Initialise the `Array` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("array", "init");
global.set_field("Array", Self::create(global)); global.set_field("Array", Self::create(global));
} }
} }

2
boa/src/builtins/bigint/mod.rs

@ -19,6 +19,7 @@ use crate::{
}, },
exec::Interpreter, exec::Interpreter,
syntax::ast::bigint::BigInt as AstBigInt, syntax::ast::bigint::BigInt as AstBigInt,
BoaProfiler,
}; };
#[cfg(test)] #[cfg(test)]
@ -138,6 +139,7 @@ impl BigInt {
/// Initialise the `BigInt` object on the global object. /// Initialise the `BigInt` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("bigint", "init");
global.set_field("BigInt", Self::create(global)); global.set_field("BigInt", Self::create(global));
} }
} }

2
boa/src/builtins/boolean/mod.rs

@ -19,6 +19,7 @@ use crate::{
value::{ResultValue, Value, ValueData}, value::{ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use std::{borrow::Borrow, ops::Deref}; use std::{borrow::Borrow, ops::Deref};
@ -128,6 +129,7 @@ impl Boolean {
/// Initialise the `Boolean` object on the global object. /// Initialise the `Boolean` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("boolean", "init");
global.set_field("Boolean", Self::create(global)); global.set_field("Boolean", Self::create(global));
} }
} }

2
boa/src/builtins/console/mod.rs

@ -23,6 +23,7 @@ use crate::{
value::{display_obj, ResultValue, Value}, value::{display_obj, ResultValue, Value},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::time::SystemTime; use std::time::SystemTime;
@ -554,5 +555,6 @@ pub fn create(global: &Value) -> Value {
/// Initialise the `console` object on the global object. /// Initialise the `console` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("console", "init");
global.set_field("console", create(global)); global.set_field("console", create(global));
} }

2
boa/src/builtins/error/mod.rs

@ -17,6 +17,7 @@ use crate::{
value::{ResultValue, Value}, value::{ResultValue, Value},
}, },
exec::Interpreter, exec::Interpreter,
profiler::BoaProfiler,
}; };
// mod eval; // mod eval;
@ -81,6 +82,7 @@ impl Error {
/// Initialise the global object with the `Error` object. /// Initialise the global object with the `Error` object.
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("error", "init");
global.set_field("Error", Self::create(global)); global.set_field("Error", Self::create(global));
} }
} }

2
boa/src/builtins/error/range.rs

@ -17,6 +17,7 @@ use crate::{
value::{ResultValue, Value}, value::{ResultValue, Value},
}, },
exec::Interpreter, exec::Interpreter,
profiler::BoaProfiler,
}; };
/// JavaScript `RangeError` impleentation. /// JavaScript `RangeError` impleentation.
@ -71,6 +72,7 @@ impl RangeError {
/// Initialise the global object with the `RangeError` object. /// Initialise the global object with the `RangeError` object.
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("rangeerror", "init");
global.set_field("RangeError", Self::create(global)); global.set_field("RangeError", Self::create(global));
} }
} }

9
boa/src/builtins/function/mod.rs

@ -22,6 +22,7 @@ use crate::{
environment::lexical_environment::{new_function_environment, Environment}, environment::lexical_environment::{new_function_environment, Environment},
exec::{Executable, Interpreter}, exec::{Executable, Interpreter},
syntax::ast::node::{FormalParameter, StatementList}, syntax::ast::node::{FormalParameter, StatementList},
BoaProfiler,
}; };
use gc::{unsafe_empty_trace, Finalize, Trace}; use gc::{unsafe_empty_trace, Finalize, Trace};
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
@ -142,6 +143,7 @@ impl Function {
where where
P: Into<Box<[FormalParameter]>>, P: Into<Box<[FormalParameter]>>,
{ {
let _timer = BoaProfiler::global().start_event("function::builtin", "function");
Self::new( Self::new(
parameter_list.into(), parameter_list.into(),
None, None,
@ -163,6 +165,7 @@ impl Function {
interpreter: &mut Interpreter, interpreter: &mut Interpreter,
this_obj: &mut Value, this_obj: &mut Value,
) -> ResultValue { ) -> ResultValue {
let _timer = BoaProfiler::global().start_event("function::call", "function");
if self.callable { if self.callable {
match self.body { match self.body {
FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter),
@ -433,6 +436,9 @@ pub fn make_builtin_fn<N>(function: NativeFunctionData, name: N, parent: &Value,
where where
N: Into<String>, N: Into<String>,
{ {
let name_copy: String = name.into();
let label = format!("{}{}", String::from("make_builtin_fn: "), &name_copy);
let _timer = BoaProfiler::global().start_event(&label, "init");
let func = Function::builtin(Vec::new(), function); let func = Function::builtin(Vec::new(), function);
let mut new_func = Object::function(); let mut new_func = Object::function();
@ -441,11 +447,12 @@ where
let new_func_obj = Value::from(new_func); let new_func_obj = Value::from(new_func);
new_func_obj.set_field("length", length); new_func_obj.set_field("length", length);
parent.set_field(name.into(), new_func_obj); parent.set_field(Value::from(name_copy), new_func_obj);
} }
/// Initialise the `Function` object on the global object. /// Initialise the `Function` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("function", "init");
global.set_field("Function", create(global)); global.set_field("Function", create(global));
} }

3
boa/src/builtins/json/mod.rs

@ -19,7 +19,7 @@ use crate::builtins::{
property::Property, property::Property,
value::{ResultValue, Value}, value::{ResultValue, Value},
}; };
use crate::exec::Interpreter; use crate::{exec::Interpreter, BoaProfiler};
use serde_json::{self, Value as JSONValue}; use serde_json::{self, Value as JSONValue};
#[cfg(test)] #[cfg(test)]
@ -174,5 +174,6 @@ pub fn create(global: &Value) -> Value {
/// Initialise the `JSON` object on the global object. /// Initialise the `JSON` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("json", "init");
global.set_field("JSON", create(global)); global.set_field("JSON", create(global));
} }

3
boa/src/builtins/math/mod.rs

@ -17,6 +17,7 @@ use crate::{
value::{ResultValue, Value}, value::{ResultValue, Value},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use rand::random; use rand::random;
use std::f64; use std::f64;
@ -507,6 +508,7 @@ pub fn trunc(_: &mut Value, args: &[Value], _: &mut Interpreter) -> ResultValue
/// Create a new `Math` object /// Create a new `Math` object
pub fn create(global: &Value) -> Value { pub fn create(global: &Value) -> Value {
let _timer = BoaProfiler::global().start_event("math:create", "init");
let math = Value::new_object(Some(global)); let math = Value::new_object(Some(global));
math.set_field("E", Value::from(f64::consts::E)); math.set_field("E", Value::from(f64::consts::E));
@ -553,5 +555,6 @@ pub fn create(global: &Value) -> Value {
/// Initialise the `Math` object on the global object. /// Initialise the `Math` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("math", "init");
global.set_field("Math", create(global)); global.set_field("Math", create(global));
} }

2
boa/src/builtins/number/mod.rs

@ -26,6 +26,7 @@ use crate::{
value::{ResultValue, Value, ValueData}, value::{ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use num_traits::float::FloatCore; use num_traits::float::FloatCore;
use std::{borrow::Borrow, ops::Deref}; use std::{borrow::Borrow, ops::Deref};
@ -435,6 +436,7 @@ impl Number {
/// Initialise the `Number` object on the global object. /// Initialise the `Number` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("number", "init");
global.set_field("Number", Self::create(global)); global.set_field("Number", Self::create(global));
} }

7
boa/src/builtins/object/internal_methods_trait.rs

@ -5,10 +5,13 @@
//! //!
//! [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots //! [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots
use crate::builtins::{ use crate::{
builtins::{
object::{Object, INSTANCE_PROTOTYPE}, object::{Object, INSTANCE_PROTOTYPE},
property::Property, property::Property,
value::{same_value, Value, ValueData}, value::{same_value, Value, ValueData},
},
BoaProfiler,
}; };
use std::borrow::Borrow; use std::borrow::Borrow;
use std::ops::Deref; use std::ops::Deref;
@ -131,6 +134,7 @@ pub trait ObjectInternalMethods {
/// [[Set]] /// [[Set]]
/// <https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver> /// <https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver>
fn set(&mut self, field: Value, val: Value) -> bool { fn set(&mut self, field: Value, val: Value) -> bool {
let _timer = BoaProfiler::global().start_event("Object::set", "object");
// [1] // [1]
debug_assert!(Property::is_property_key(&field)); debug_assert!(Property::is_property_key(&field));
@ -168,6 +172,7 @@ pub trait ObjectInternalMethods {
} }
fn define_own_property(&mut self, property_key: String, desc: Property) -> bool { fn define_own_property(&mut self, property_key: String, desc: Property) -> bool {
let _timer = BoaProfiler::global().start_event("Object::define_own_property", "object");
let mut current = self.get_own_property(&Value::from(property_key.to_string())); let mut current = self.get_own_property(&Value::from(property_key.to_string()));
let extensible = self.is_extensible(); let extensible = self.is_extensible();

5
boa/src/builtins/object/mod.rs

@ -20,6 +20,7 @@ use crate::{
value::{same_value, ResultValue, Value, ValueData}, value::{same_value, ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use gc::{unsafe_empty_trace, Finalize, Trace}; use gc::{unsafe_empty_trace, Finalize, Trace};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -131,6 +132,7 @@ impl ObjectInternalMethods for Object {
/// Helper function to get an immutable internal slot or Null /// Helper function to get an immutable internal slot or Null
fn get_internal_slot(&self, name: &str) -> Value { fn get_internal_slot(&self, name: &str) -> Value {
let _timer = BoaProfiler::global().start_event("Object::get_internal_slot", "object");
match self.internal_slots.get(name) { match self.internal_slots.get(name) {
Some(v) => v.clone(), Some(v) => v.clone(),
None => Value::null(), None => Value::null(),
@ -146,6 +148,7 @@ impl ObjectInternalMethods for Object {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p
fn get_own_property(&self, prop: &Value) -> Property { fn get_own_property(&self, prop: &Value) -> Property {
let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object");
debug_assert!(Property::is_property_key(prop)); debug_assert!(Property::is_property_key(prop));
// Prop could either be a String or Symbol // Prop could either be a String or Symbol
match *(*prop) { match *(*prop) {
@ -352,6 +355,7 @@ impl Object {
/// Return a new ObjectData struct, with `kind` set to Ordinary /// Return a new ObjectData struct, with `kind` set to Ordinary
pub fn function() -> Self { pub fn function() -> Self {
let _timer = BoaProfiler::global().start_event("Object::Function", "object");
let mut object = Self { let mut object = Self {
kind: ObjectKind::Function, kind: ObjectKind::Function,
internal_slots: FxHashMap::default(), internal_slots: FxHashMap::default(),
@ -640,5 +644,6 @@ pub fn create(global: &Value) -> Value {
/// Initialise the `Object` object on the global object. /// Initialise the `Object` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("object", "init");
global.set_field("Object", create(global)); global.set_field("Object", create(global));
} }

2
boa/src/builtins/regexp/mod.rs

@ -21,6 +21,7 @@ use crate::{
value::{ResultValue, Value, ValueData}, value::{ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
#[cfg(test)] #[cfg(test)]
@ -491,6 +492,7 @@ impl RegExp {
/// Initialise the `RegExp` object on the global object. /// Initialise the `RegExp` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("regexp", "init");
global.set_field("RegExp", Self::create(global)); global.set_field("RegExp", Self::create(global));
} }
} }

2
boa/src/builtins/string/mod.rs

@ -21,6 +21,7 @@ use crate::{
RegExp, RegExp,
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use regex::Regex; use regex::Regex;
use std::string::String as StdString; use std::string::String as StdString;
@ -1077,6 +1078,7 @@ impl String {
/// Initialise the `String` object on the global object. /// Initialise the `String` object on the global object.
#[inline] #[inline]
pub(crate) fn init(global: &Value) { pub(crate) fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("string", "init");
global.set_field("String", Self::create(global)); global.set_field("String", Self::create(global));
} }
} }

2
boa/src/builtins/symbol/mod.rs

@ -28,6 +28,7 @@ use crate::{
value::{ResultValue, Value, ValueData}, value::{ResultValue, Value, ValueData},
}, },
exec::Interpreter, exec::Interpreter,
BoaProfiler,
}; };
use gc::{Gc, GcCell}; use gc::{Gc, GcCell};
use rand::random; use rand::random;
@ -100,5 +101,6 @@ pub fn create(global: &Value) -> Value {
/// Initialise the `Symbol` object on the global object. /// Initialise the `Symbol` object on the global object.
#[inline] #[inline]
pub fn init(global: &Value) { pub fn init(global: &Value) {
let _timer = BoaProfiler::global().start_event("symbol", "init");
global.set_field("Symbol", create(global)); global.set_field("Symbol", create(global));
} }

2
boa/src/builtins/value/conversions.rs

@ -9,6 +9,7 @@ impl From<&Value> for Value {
impl From<String> for Value { impl From<String> for Value {
fn from(value: String) -> Self { fn from(value: String) -> Self {
let _timer = BoaProfiler::global().start_event("From<String>", "value");
Self::string(value) Self::string(value)
} }
} }
@ -164,6 +165,7 @@ where
impl From<Object> for Value { impl From<Object> for Value {
fn from(object: Object) -> Self { fn from(object: Object) -> Self {
let _timer = BoaProfiler::global().start_event("From<Object>", "value");
Value::object(object) Value::object(object)
} }
} }

11
boa/src/builtins/value/mod.rs

@ -13,7 +13,7 @@ use crate::builtins::{
}, },
property::Property, property::Property,
}; };
use crate::syntax::ast::bigint::BigInt; use crate::{syntax::ast::bigint::BigInt, BoaProfiler};
use gc::{Finalize, Gc, GcCell, GcCellRef, Trace}; use gc::{Finalize, Gc, GcCell, GcCellRef, Trace};
use serde_json::{map::Map, Number as JSONNumber, Value as JSONValue}; use serde_json::{map::Map, Number as JSONNumber, Value as JSONValue};
use std::{ use std::{
@ -124,6 +124,7 @@ impl Value {
/// Returns a new empty object /// Returns a new empty object
pub fn new_object(global: Option<&Value>) -> Self { pub fn new_object(global: Option<&Value>) -> Self {
let _timer = BoaProfiler::global().start_event("new_object", "value");
if let Some(global) = global { if let Some(global) = global {
let object_prototype = global.get_field("Object").get_field(PROTOTYPE); let object_prototype = global.get_field("Object").get_field(PROTOTYPE);
@ -393,6 +394,7 @@ impl ValueData {
/// ///
/// A copy of the Property is returned. /// A copy of the Property is returned.
pub fn get_property(&self, field: &str) -> Option<Property> { pub fn get_property(&self, field: &str) -> Option<Property> {
let _timer = BoaProfiler::global().start_event("Value::get_property", "value");
// Spidermonkey has its own GetLengthProperty: https://searchfox.org/mozilla-central/source/js/src/vm/Interpreter-inl.h#154 // Spidermonkey has its own GetLengthProperty: https://searchfox.org/mozilla-central/source/js/src/vm/Interpreter-inl.h#154
// This is only for primitive strings, String() objects have their lengths calculated in string.rs // This is only for primitive strings, String() objects have their lengths calculated in string.rs
if self.is_string() && field == "length" { if self.is_string() && field == "length" {
@ -439,6 +441,7 @@ impl ValueData {
writable: Option<bool>, writable: Option<bool>,
configurable: Option<bool>, configurable: Option<bool>,
) { ) {
let _timer = BoaProfiler::global().start_event("Value::update_property", "value");
let obj: Option<Object> = match self { let obj: Option<Object> = match self {
Self::Object(ref obj) => Some(obj.borrow_mut().deref_mut().clone()), Self::Object(ref obj) => Some(obj.borrow_mut().deref_mut().clone()),
_ => None, _ => None,
@ -459,6 +462,7 @@ impl ValueData {
/// ///
/// Returns a copy of the Property. /// Returns a copy of the Property.
pub fn get_internal_slot(&self, field: &str) -> Value { pub fn get_internal_slot(&self, field: &str) -> Value {
let _timer = BoaProfiler::global().start_event("Value::get_internal_slot", "value");
let obj: Object = match *self { let obj: Object = match *self {
Self::Object(ref obj) => { Self::Object(ref obj) => {
let hash = obj.clone(); let hash = obj.clone();
@ -484,6 +488,7 @@ impl ValueData {
where where
F: Into<Value>, F: Into<Value>,
{ {
let _timer = BoaProfiler::global().start_event("Value::get_field", "value");
match *field.into() { match *field.into() {
// Our field will either be a String or a Symbol // Our field will either be a String or a Symbol
Self::String(ref s) => { Self::String(ref s) => {
@ -582,6 +587,7 @@ impl ValueData {
/// Check to see if the Value has the field, mainly used by environment records /// Check to see if the Value has the field, mainly used by environment records
pub fn has_field(&self, field: &str) -> bool { pub fn has_field(&self, field: &str) -> bool {
let _timer = BoaProfiler::global().start_event("Value::has_field", "value");
self.get_property(field).is_some() self.get_property(field).is_some()
} }
@ -592,6 +598,7 @@ impl ValueData {
F: Into<Value>, F: Into<Value>,
V: Into<Value>, V: Into<Value>,
{ {
let _timer = BoaProfiler::global().start_event("Value::set_field", "value");
let field = field.into(); let field = field.into();
let val = val.into(); let val = val.into();
@ -621,6 +628,7 @@ impl ValueData {
/// Set the private field in the value /// Set the private field in the value
pub fn set_internal_slot(&self, field: &str, val: Value) -> Value { pub fn set_internal_slot(&self, field: &str, val: Value) -> Value {
let _timer = BoaProfiler::global().start_event("Value::set_internal_slot", "exec");
if let Self::Object(ref obj) = *self { if let Self::Object(ref obj) = *self {
obj.borrow_mut() obj.borrow_mut()
.internal_slots .internal_slots
@ -766,6 +774,7 @@ impl ValueData {
/// ///
/// https://tc39.es/ecma262/#sec-typeof-operator /// https://tc39.es/ecma262/#sec-typeof-operator
pub fn get_type(&self) -> &'static str { pub fn get_type(&self) -> &'static str {
let _timer = BoaProfiler::global().start_event("Value::get_type", "value");
match *self { match *self {
Self::Rational(_) | Self::Integer(_) => "number", Self::Rational(_) | Self::Integer(_) => "number",
Self::String(_) => "string", Self::String(_) => "string",

3
boa/src/environment/lexical_environment.rs

@ -14,6 +14,7 @@ use crate::{
global_environment_record::GlobalEnvironmentRecord, global_environment_record::GlobalEnvironmentRecord,
object_environment_record::ObjectEnvironmentRecord, object_environment_record::ObjectEnvironmentRecord,
}, },
BoaProfiler,
}; };
use gc::{Gc, GcCell}; use gc::{Gc, GcCell};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -79,6 +80,7 @@ impl error::Error for EnvironmentError {
impl LexicalEnvironment { impl LexicalEnvironment {
pub fn new(global: Value) -> Self { pub fn new(global: Value) -> Self {
let _timer = BoaProfiler::global().start_event("LexicalEnvironment::new", "env");
let global_env = new_global_environment(global.clone(), global); let global_env = new_global_environment(global.clone(), global);
let mut lexical_env = Self { let mut lexical_env = Self {
environment_stack: VecDeque::new(), environment_stack: VecDeque::new(),
@ -219,6 +221,7 @@ impl LexicalEnvironment {
} }
pub fn new_declarative_environment(env: Option<Environment>) -> Environment { pub fn new_declarative_environment(env: Option<Environment>) -> Environment {
let _timer = BoaProfiler::global().start_event("new_declarative_environment", "env");
let boxed_env = Box::new(DeclarativeEnvironmentRecord { let boxed_env = Box::new(DeclarativeEnvironmentRecord {
env_rec: FxHashMap::default(), env_rec: FxHashMap::default(),
outer_env: env, outer_env: env,

2
boa/src/exec/array/mod.rs

@ -4,10 +4,12 @@ use super::{Executable, Interpreter};
use crate::{ use crate::{
builtins::{Array, ResultValue}, builtins::{Array, ResultValue},
syntax::ast::node::{ArrayDecl, Node}, syntax::ast::node::{ArrayDecl, Node},
BoaProfiler,
}; };
impl Executable for ArrayDecl { impl Executable for ArrayDecl {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("ArrayDecl", "exec");
let array = Array::new_array(interpreter)?; let array = Array::new_array(interpreter)?;
let mut elements = Vec::new(); let mut elements = Vec::new();
for elem in self.as_ref() { for elem in self.as_ref() {

2
boa/src/exec/block/mod.rs

@ -5,10 +5,12 @@ use crate::{
builtins::value::{ResultValue, Value}, builtins::value::{ResultValue, Value},
environment::lexical_environment::new_declarative_environment, environment::lexical_environment::new_declarative_environment,
syntax::ast::node::Block, syntax::ast::node::Block,
BoaProfiler,
}; };
impl Executable for Block { impl Executable for Block {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Block", "exec");
{ {
let env = &mut interpreter.realm_mut().environment; let env = &mut interpreter.realm_mut().environment;
env.push(new_declarative_environment(Some( env.push(new_declarative_environment(Some(

2
boa/src/exec/declaration/mod.rs

@ -10,10 +10,12 @@ use crate::{
syntax::ast::node::{ syntax::ast::node::{
ArrowFunctionDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDeclList, VarDeclList, ArrowFunctionDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDeclList, VarDeclList,
}, },
BoaProfiler,
}; };
impl Executable for FunctionDecl { impl Executable for FunctionDecl {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("FunctionDecl", "exec");
let val = interpreter.create_function( let val = interpreter.create_function(
self.parameters().to_vec(), self.parameters().to_vec(),
self.body().to_vec(), self.body().to_vec(),

2
boa/src/exec/expression/mod.rs

@ -7,10 +7,12 @@ use crate::{
value::{ResultValue, Value, ValueData}, value::{ResultValue, Value, ValueData},
}, },
syntax::ast::node::{Call, New, Node}, syntax::ast::node::{Call, New, Node},
BoaProfiler,
}; };
impl Executable for Call { impl Executable for Call {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Call", "exec");
let (mut this, func) = match self.expr() { let (mut this, func) = match self.expr() {
Node::GetConstField(ref obj, ref field) => { Node::GetConstField(ref obj, ref field) => {
let mut obj = obj.run(interpreter)?; let mut obj = obj.run(interpreter)?;

2
boa/src/exec/iteration/mod.rs

@ -5,11 +5,13 @@ use crate::{
builtins::value::{ResultValue, Value}, builtins::value::{ResultValue, Value},
environment::lexical_environment::new_declarative_environment, environment::lexical_environment::new_declarative_environment,
syntax::ast::node::ForLoop, syntax::ast::node::ForLoop,
BoaProfiler,
}; };
impl Executable for ForLoop { impl Executable for ForLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
// Create the block environment. // Create the block environment.
let _timer = BoaProfiler::global().start_event("ForLoop", "exec");
{ {
let env = &mut interpreter.realm_mut().environment; let env = &mut interpreter.realm_mut().environment;
env.push(new_declarative_environment(Some( env.push(new_declarative_environment(Some(

2
boa/src/exec/mod.rs

@ -29,6 +29,7 @@ use crate::{
constant::Const, constant::Const,
node::{FormalParameter, MethodDefinitionKind, Node, PropertyDefinition, StatementList}, node::{FormalParameter, MethodDefinitionKind, Node, PropertyDefinition, StatementList},
}, },
BoaProfiler,
}; };
use std::{borrow::Borrow, ops::Deref}; use std::{borrow::Borrow, ops::Deref};
@ -362,6 +363,7 @@ impl Interpreter {
impl Executable for Node { impl Executable for Node {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Executable", "exec");
match *self { match *self {
Node::Const(Const::Null) => Ok(Value::null()), Node::Const(Const::Null) => Ok(Value::null()),
Node::Const(Const::Undefined) => Ok(Value::undefined()), Node::Const(Const::Undefined) => Ok(Value::undefined()),

2
boa/src/exec/operator/mod.rs

@ -8,11 +8,13 @@ use crate::{
node::{Assign, BinOp, Node, UnaryOp}, node::{Assign, BinOp, Node, UnaryOp},
op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp},
}, },
BoaProfiler,
}; };
use std::borrow::BorrowMut; use std::borrow::BorrowMut;
impl Executable for Assign { impl Executable for Assign {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Assign", "exec");
let val = self.rhs().run(interpreter)?; let val = self.rhs().run(interpreter)?;
match self.lhs() { match self.lhs() {
Node::Identifier(ref name) => { Node::Identifier(ref name) => {

2
boa/src/exec/statement_list.rs

@ -4,10 +4,12 @@ use super::{Executable, Interpreter};
use crate::{ use crate::{
builtins::value::{ResultValue, Value}, builtins::value::{ResultValue, Value},
syntax::ast::node::StatementList, syntax::ast::node::StatementList,
BoaProfiler,
}; };
impl Executable for StatementList { impl Executable for StatementList {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("StatementList", "exec");
let mut obj = Value::null(); let mut obj = Value::null();
for (i, item) in self.statements().iter().enumerate() { for (i, item) in self.statements().iter().enumerate() {
let val = item.run(interpreter)?; let val = item.run(interpreter)?;

2
boa/src/exec/try_node/mod.rs

@ -5,6 +5,7 @@ use crate::{
builtins::value::ResultValue, builtins::value::ResultValue,
environment::lexical_environment::{new_declarative_environment, VariableScope}, environment::lexical_environment::{new_declarative_environment, VariableScope},
syntax::ast::node::Try, syntax::ast::node::Try,
BoaProfiler,
}; };
#[cfg(test)] #[cfg(test)]
@ -12,6 +13,7 @@ mod tests;
impl Executable for Try { impl Executable for Try {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Try", "exec");
let res = self.block().run(interpreter).map_or_else( let res = self.block().run(interpreter).map_or_else(
|err| { |err| {
if let Some(catch) = self.catch() { if let Some(catch) = self.catch() {

15
boa/src/lib.rs

@ -30,18 +30,21 @@
clippy::must_use_candidate, clippy::must_use_candidate,
clippy::missing_errors_doc, clippy::missing_errors_doc,
clippy::as_conversions, clippy::as_conversions,
clippy::let_unit_value,
missing_doc_code_examples missing_doc_code_examples
)] )]
pub mod builtins; pub mod builtins;
pub mod environment; pub mod environment;
pub mod exec; pub mod exec;
pub mod profiler;
pub mod realm; pub mod realm;
pub mod syntax; pub mod syntax;
use crate::{builtins::value::ResultValue, syntax::ast::node::StatementList}; use crate::{builtins::value::ResultValue, syntax::ast::node::StatementList};
pub use crate::{ pub use crate::{
exec::{Executable, Interpreter}, exec::{Executable, Interpreter},
profiler::BoaProfiler,
realm::Realm, realm::Realm,
syntax::{lexer::Lexer, parser::Parser}, syntax::{lexer::Lexer, parser::Parser},
}; };
@ -71,15 +74,23 @@ pub fn forward(engine: &mut Interpreter, src: &str) -> String {
/// The str is consumed and the state of the Interpreter is changed /// The str is consumed and the state of the Interpreter is changed
/// Similar to `forward`, except the current value is returned instad of the string /// Similar to `forward`, except the current value is returned instad of the string
/// If the interpreter fails parsing an error value is returned instead (error object) /// If the interpreter fails parsing an error value is returned instead (error object)
#[allow(clippy::unit_arg, clippy::drop_copy)]
pub fn forward_val(engine: &mut Interpreter, src: &str) -> ResultValue { pub fn forward_val(engine: &mut Interpreter, src: &str) -> ResultValue {
let main_timer = BoaProfiler::global().start_event("Main", "Main");
// Setup executor // Setup executor
match parser_expr(src) { let result = match parser_expr(src) {
Ok(expr) => expr.run(engine), Ok(expr) => expr.run(engine),
Err(e) => { Err(e) => {
eprintln!("{}", e); eprintln!("{}", e);
std::process::exit(1); std::process::exit(1);
} }
} };
// The main_timer needs to be dropped before the BoaProfiler is.
drop(main_timer);
BoaProfiler::global().drop();
result
} }
/// Create a clean Interpreter and execute the code /// Create a clean Interpreter and execute the code

95
boa/src/profiler.rs

@ -0,0 +1,95 @@
#![allow(missing_copy_implementations, missing_debug_implementations)]
#[cfg(feature = "profiler")]
use measureme::{EventId, Profiler, TimingGuard};
#[cfg(feature = "profiler")]
use once_cell::sync::OnceCell;
use std::fmt::{self, Debug};
#[cfg(feature = "profiler")]
use std::{
path::Path,
thread::{current, ThreadId},
};
/// MmapSerializatioSink is faster on macOS and Linux
/// but FileSerializationSink is faster on Windows
#[cfg(not(windows))]
#[cfg(feature = "profiler")]
type SerializationSink = measureme::MmapSerializationSink;
#[cfg(windows)]
#[cfg(feature = "profiler")]
type SerializationSink = measureme::FileSerializationSink;
#[cfg(feature = "profiler")]
pub struct BoaProfiler {
profiler: Profiler<SerializationSink>,
}
/// This static instance should never be public, and its only access should be done through the `global()` and `drop()` methods
/// This is because `get_or_init` manages synchronisation and the case of an empty value
#[cfg(feature = "profiler")]
static mut INSTANCE: OnceCell<BoaProfiler> = OnceCell::new();
#[cfg(feature = "profiler")]
impl BoaProfiler {
pub fn start_event(&self, label: &str, category: &str) -> TimingGuard<'_, SerializationSink> {
let kind = self.profiler.alloc_string(category);
let id = EventId::from_label(self.profiler.alloc_string(label));
let thread_id = Self::thread_id_to_u32(current().id());
self.profiler
.start_recording_interval_event(kind, id, thread_id)
}
pub fn default() -> BoaProfiler {
let profiler = Profiler::new(Path::new("./my_trace")).unwrap();
BoaProfiler { profiler }
}
pub fn global() -> &'static BoaProfiler {
unsafe { INSTANCE.get_or_init(Self::default) }
}
pub fn drop(&self) {
// In order to drop the INSTANCE we need to get ownership of it, which isn't possible on a static unless you make it a mutable static
// mutating statics is unsafe, so we need to wrap it as so.
// This is actually safe though because init and drop are only called at the beginning and end of the application
unsafe {
INSTANCE
.take()
.expect("Could not take back profiler instance");
}
}
// Sadly we need to use the unsafe method until this is resolved:
// https://github.com/rust-lang/rust/issues/67939
// Once `as_64()` is in stable we can do this:
// https://github.com/rust-lang/rust/pull/68531/commits/ea42b1c5b85f649728e3a3b334489bac6dce890a
// Until then our options are: use rust-nightly or use unsafe {}
fn thread_id_to_u32(tid: ThreadId) -> u32 {
unsafe { std::mem::transmute::<ThreadId, u64>(tid) as u32 }
}
}
impl Debug for BoaProfiler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt("no debug implemented", f)
}
}
#[cfg(not(feature = "profiler"))]
pub struct BoaProfiler;
#[allow(clippy::unused_unit)]
#[cfg(not(feature = "profiler"))]
impl BoaProfiler {
pub fn start_event(&self, _label: &str, _category: &str) -> () {
()
}
pub fn drop(&self) {
()
}
pub fn global() -> BoaProfiler {
BoaProfiler
}
}

3
boa/src/realm.rs

@ -16,6 +16,7 @@ use crate::{
lexical_environment::LexicalEnvironment, lexical_environment::LexicalEnvironment,
object_environment_record::ObjectEnvironmentRecord, object_environment_record::ObjectEnvironmentRecord,
}, },
BoaProfiler,
}; };
use gc::{Gc, GcCell}; use gc::{Gc, GcCell};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -32,6 +33,7 @@ pub struct Realm {
impl Realm { impl Realm {
pub fn create() -> Self { pub fn create() -> Self {
let _timer = BoaProfiler::global().start_event("Realm::create", "realm");
// Create brand new global object // Create brand new global object
// Global has no prototype to pass None to new_obj // Global has no prototype to pass None to new_obj
let global = Value::new_object(None); let global = Value::new_object(None);
@ -53,6 +55,7 @@ impl Realm {
// Sets up the default global objects within Global // Sets up the default global objects within Global
fn create_instrinsics(&self) { fn create_instrinsics(&self) {
let _timer = BoaProfiler::global().start_event("create_instrinsics", "realm");
let global = &self.global_obj; let global = &self.global_obj;
// Create intrinsics, add global objects here // Create intrinsics, add global objects here
builtins::init(global); builtins::init(global);

6
boa/src/syntax/lexer/mod.rs

@ -7,9 +7,12 @@
mod tests; mod tests;
use crate::syntax::ast::bigint::BigInt; use crate::syntax::ast::bigint::BigInt;
use crate::syntax::ast::{ use crate::{
syntax::ast::{
token::{NumericLiteral, Token, TokenKind}, token::{NumericLiteral, Token, TokenKind},
Position, Punctuator, Span, Position, Punctuator, Span,
},
BoaProfiler,
}; };
use std::{ use std::{
char::{decode_utf16, from_u32}, char::{decode_utf16, from_u32},
@ -486,6 +489,7 @@ impl<'a> Lexer<'a> {
/// } /// }
/// ``` /// ```
pub fn lex(&mut self) -> Result<(), LexerError> { pub fn lex(&mut self) -> Result<(), LexerError> {
let _timer = BoaProfiler::global().start_event("lex", "lexing");
loop { loop {
// Check if we've reached the end // Check if we've reached the end
if self.preview_next().is_none() { if self.preview_next().is_none() {

6
boa/src/syntax/parser/expression/assignment/arrow_function.rs

@ -8,7 +8,8 @@
//! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions //! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions
use super::AssignmentExpression; use super::AssignmentExpression;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{ArrowFunctionDecl, FormalParameter, Node, StatementList}, node::{ArrowFunctionDecl, FormalParameter, Node, StatementList},
Punctuator, TokenKind, Punctuator, TokenKind,
@ -19,6 +20,8 @@ use crate::syntax::{
statement::BindingIdentifier, statement::BindingIdentifier,
AllowAwait, AllowIn, AllowYield, Cursor, TokenParser, AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Arrow function parsing. /// Arrow function parsing.
@ -60,6 +63,7 @@ impl TokenParser for ArrowFunction {
type Output = ArrowFunctionDecl; type Output = ArrowFunctionDecl;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("ArrowFunction", "Parsing");
let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &next_token.kind { let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &next_token.kind {
// CoverParenthesizedExpressionAndArrowParameterList // CoverParenthesizedExpressionAndArrowParameterList

6
boa/src/syntax/parser/expression/assignment/conditional.rs

@ -7,12 +7,15 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
//! [spec]: https://tc39.es/ecma262/#sec-conditional-operator //! [spec]: https://tc39.es/ecma262/#sec-conditional-operator
use crate::syntax::{ use crate::{
syntax::{
ast::{Node, Punctuator, TokenKind}, ast::{Node, Punctuator, TokenKind},
parser::{ parser::{
expression::{AssignmentExpression, LogicalORExpression}, expression::{AssignmentExpression, LogicalORExpression},
AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser, AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Conditional expression parsing. /// Conditional expression parsing.
@ -54,6 +57,7 @@ impl TokenParser for ConditionalExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("Conditional", "Parsing");
// TODO: coalesce expression // TODO: coalesce expression
let lhs = LogicalORExpression::new(self.allow_in, self.allow_yield, self.allow_await) let lhs = LogicalORExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?; .parse(cursor)?;

6
boa/src/syntax/parser/expression/assignment/exponentiation.rs

@ -7,7 +7,8 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation
//! [spec]: https://tc39.es/ecma262/#sec-exp-operator //! [spec]: https://tc39.es/ecma262/#sec-exp-operator
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{BinOp, Node}, node::{BinOp, Node},
op::NumOp, op::NumOp,
@ -17,6 +18,8 @@ use crate::syntax::{
expression::{unary::UnaryExpression, update::UpdateExpression}, expression::{unary::UnaryExpression, update::UpdateExpression},
AllowAwait, AllowYield, Cursor, ParseResult, TokenParser, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses an exponentiation expression. /// Parses an exponentiation expression.
@ -71,6 +74,7 @@ impl TokenParser for ExponentiationExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ExponentiationExpression", "Parsing");
if Self::is_unary_expression(cursor) { if Self::is_unary_expression(cursor) {
return UnaryExpression::new(self.allow_yield, self.allow_await).parse(cursor); return UnaryExpression::new(self.allow_yield, self.allow_await).parse(cursor);
} }

6
boa/src/syntax/parser/expression/assignment/mod.rs

@ -12,12 +12,15 @@ mod conditional;
mod exponentiation; mod exponentiation;
use self::{arrow_function::ArrowFunction, conditional::ConditionalExpression}; use self::{arrow_function::ArrowFunction, conditional::ConditionalExpression};
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{Assign, BinOp, Node}, node::{Assign, BinOp, Node},
Keyword, Punctuator, TokenKind, Keyword, Punctuator, TokenKind,
}, },
parser::{AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser}, parser::{AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser},
},
BoaProfiler,
}; };
pub(super) use exponentiation::ExponentiationExpression; pub(super) use exponentiation::ExponentiationExpression;
@ -70,6 +73,7 @@ impl TokenParser for AssignmentExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("AssignmentExpression", "Parsing");
// Arrow function // Arrow function
let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
match next_token.kind { match next_token.kind {

9
boa/src/syntax/parser/expression/left_hand_side/arguments.rs

@ -7,11 +7,15 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Argument //! [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Argument
//! [spec]: https://tc39.es/ecma262/#prod-Arguments //! [spec]: https://tc39.es/ecma262/#prod-Arguments
use crate::syntax::{ use crate::{
syntax::{
ast::{Node, Punctuator, TokenKind}, ast::{Node, Punctuator, TokenKind},
parser::{ parser::{
expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser, expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError,
TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses a list of arguments. /// Parses a list of arguments.
@ -46,6 +50,7 @@ impl TokenParser for Arguments {
type Output = Box<[Node]>; type Output = Box<[Node]>;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("Arguments", "Parsing");
cursor.expect(Punctuator::OpenParen, "arguments")?; cursor.expect(Punctuator::OpenParen, "arguments")?;
let mut args = Vec::new(); let mut args = Vec::new();
loop { loop {

6
boa/src/syntax/parser/expression/left_hand_side/call.rs

@ -8,7 +8,8 @@
//! [spec]: https://tc39.es/ecma262/#prod-CallExpression //! [spec]: https://tc39.es/ecma262/#prod-CallExpression
use super::arguments::Arguments; use super::arguments::Arguments;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{Call, Node}, node::{Call, Node},
Punctuator, TokenKind, Punctuator, TokenKind,
@ -17,6 +18,8 @@ use crate::syntax::{
expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, ParseResult, expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, ParseResult,
TokenParser, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses a call expression. /// Parses a call expression.
@ -51,6 +54,7 @@ impl TokenParser for CallExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("CallExpression", "Parsing");
let mut lhs = match cursor.peek(0) { let mut lhs = match cursor.peek(0) {
Some(tk) if tk.kind == TokenKind::Punctuator(Punctuator::OpenParen) => { Some(tk) if tk.kind == TokenKind::Punctuator(Punctuator::OpenParen) => {
let args = Arguments::new(self.allow_yield, self.allow_await).parse(cursor)?; let args = Arguments::new(self.allow_yield, self.allow_await).parse(cursor)?;

6
boa/src/syntax/parser/expression/left_hand_side/member.rs

@ -6,7 +6,8 @@
//! [spec]: https://tc39.es/ecma262/#prod-MemberExpression //! [spec]: https://tc39.es/ecma262/#prod-MemberExpression
use super::arguments::Arguments; use super::arguments::Arguments;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{Call, New, Node}, node::{Call, New, Node},
Keyword, Punctuator, TokenKind, Keyword, Punctuator, TokenKind,
@ -15,6 +16,8 @@ use crate::syntax::{
expression::{primary::PrimaryExpression, Expression}, expression::{primary::PrimaryExpression, Expression},
AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser, AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses a member expression. /// Parses a member expression.
@ -47,6 +50,7 @@ impl TokenParser for MemberExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("MemberExpression", "Parsing");
let mut lhs = if cursor.peek(0).ok_or(ParseError::AbruptEnd)?.kind let mut lhs = if cursor.peek(0).ok_or(ParseError::AbruptEnd)?.kind
== TokenKind::Keyword(Keyword::New) == TokenKind::Keyword(Keyword::New)
{ {

6
boa/src/syntax/parser/expression/left_hand_side/mod.rs

@ -12,9 +12,12 @@ mod call;
mod member; mod member;
use self::{call::CallExpression, member::MemberExpression}; use self::{call::CallExpression, member::MemberExpression};
use crate::syntax::{ use crate::{
syntax::{
ast::{Node, Punctuator, TokenKind}, ast::{Node, Punctuator, TokenKind},
parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser},
},
BoaProfiler,
}; };
/// Parses a left hand side expression. /// Parses a left hand side expression.
@ -49,6 +52,7 @@ impl TokenParser for LeftHandSideExpression {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("LeftHandSIdeExpression", "Parsing");
// TODO: Implement NewExpression: new MemberExpression // TODO: Implement NewExpression: new MemberExpression
let lhs = MemberExpression::new(self.allow_yield, self.allow_await).parse(cursor)?; let lhs = MemberExpression::new(self.allow_yield, self.allow_await).parse(cursor)?;
match cursor.peek(0) { match cursor.peek(0) {

6
boa/src/syntax/parser/expression/mod.rs

@ -18,9 +18,12 @@ mod update;
use self::assignment::ExponentiationExpression; use self::assignment::ExponentiationExpression;
pub(super) use self::{assignment::AssignmentExpression, primary::Initializer}; pub(super) use self::{assignment::AssignmentExpression, primary::Initializer};
use super::{AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser}; use super::{AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser};
use crate::syntax::ast::{ use crate::{
profiler::BoaProfiler,
syntax::ast::{
node::{BinOp, Node}, node::{BinOp, Node},
Keyword, Punctuator, TokenKind, Keyword, Punctuator, TokenKind,
},
}; };
// For use in the expression! macro to allow for both Punctuator and Keyword parameters. // For use in the expression! macro to allow for both Punctuator and Keyword parameters.
@ -51,6 +54,7 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("Expression", "Parsing");
let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor)?; let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor)?;
while let Some(tok) = cursor.peek(0) { while let Some(tok) = cursor.peek(0) {
match tok.kind { match tok.kind {

9
boa/src/syntax/parser/expression/primary/array_initializer/mod.rs

@ -10,14 +10,18 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{ArrayDecl, Node}, node::{ArrayDecl, Node},
Const, Punctuator, Const, Punctuator,
}, },
parser::{ parser::{
expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser, expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError,
TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses an array literal. /// Parses an array literal.
@ -52,6 +56,7 @@ impl TokenParser for ArrayLiteral {
type Output = ArrayDecl; type Output = ArrayDecl;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("ArrayLiteral", "Parsing");
let mut elements = Vec::new(); let mut elements = Vec::new();
loop { loop {

6
boa/src/syntax/parser/expression/primary/function_expression.rs

@ -7,13 +7,16 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
//! [spec]: https://tc39.es/ecma262/#prod-FunctionExpression //! [spec]: https://tc39.es/ecma262/#prod-FunctionExpression
use crate::syntax::{ use crate::{
syntax::{
ast::{node::FunctionExpr, Punctuator}, ast::{node::FunctionExpr, Punctuator},
parser::{ parser::{
function::{FormalParameters, FunctionBody}, function::{FormalParameters, FunctionBody},
statement::BindingIdentifier, statement::BindingIdentifier,
Cursor, ParseError, TokenParser, Cursor, ParseError, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Function expression parsing. /// Function expression parsing.
@ -31,6 +34,7 @@ impl TokenParser for FunctionExpression {
type Output = FunctionExpr; type Output = FunctionExpr;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("FunctionExpression", "Parsing");
let name = BindingIdentifier::new(false, false).try_parse(cursor); let name = BindingIdentifier::new(false, false).try_parse(cursor);
cursor.expect(Punctuator::OpenParen, "function expression")?; cursor.expect(Punctuator::OpenParen, "function expression")?;

6
boa/src/syntax/parser/expression/primary/object_initializer/mod.rs

@ -10,7 +10,8 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{self, FunctionExpr, MethodDefinitionKind, Node}, node::{self, FunctionExpr, MethodDefinitionKind, Node},
token::{Token, TokenKind}, token::{Token, TokenKind},
@ -21,6 +22,8 @@ use crate::syntax::{
function::{FormalParameters, FunctionBody}, function::{FormalParameters, FunctionBody},
AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser, AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses an object literal. /// Parses an object literal.
@ -55,6 +58,7 @@ impl TokenParser for ObjectLiteral {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ObjectLiteral", "Parsing");
let mut elements = Vec::new(); let mut elements = Vec::new();
loop { loop {

6
boa/src/syntax/parser/statement/block/mod.rs

@ -11,9 +11,12 @@
mod tests; mod tests;
use super::StatementList; use super::StatementList;
use crate::syntax::{ use crate::{
profiler::BoaProfiler,
syntax::{
ast::{node, Punctuator, TokenKind}, ast::{node, Punctuator, TokenKind},
parser::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser}, parser::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser},
},
}; };
/// A `BlockStatement` is equivalent to a `Block`. /// A `BlockStatement` is equivalent to a `Block`.
@ -59,6 +62,7 @@ impl TokenParser for Block {
type Output = node::Block; type Output = node::Block;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("Block", "Parsing");
cursor.expect(Punctuator::OpenBlock, "block")?; cursor.expect(Punctuator::OpenBlock, "block")?;
if let Some(tk) = cursor.peek(0) { if let Some(tk) = cursor.peek(0) {
if tk.kind == TokenKind::Punctuator(Punctuator::CloseBlock) { if tk.kind == TokenKind::Punctuator(Punctuator::CloseBlock) {

6
boa/src/syntax/parser/statement/break_stm/mod.rs

@ -11,9 +11,12 @@
mod tests; mod tests;
use super::LabelIdentifier; use super::LabelIdentifier;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser},
},
BoaProfiler,
}; };
/// Break statement parsing /// Break statement parsing
@ -48,6 +51,7 @@ impl TokenParser for BreakStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("BreakStatement", "Parsing");
cursor.expect(Keyword::Break, "break statement")?; cursor.expect(Keyword::Break, "break statement")?;
let label = if let (true, tok) = cursor.peek_semicolon(false) { let label = if let (true, tok) = cursor.peek_semicolon(false) {

6
boa/src/syntax/parser/statement/continue_stm/mod.rs

@ -11,9 +11,12 @@
mod tests; mod tests;
use super::LabelIdentifier; use super::LabelIdentifier;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser},
},
BoaProfiler,
}; };
/// For statement parsing /// For statement parsing
@ -48,6 +51,7 @@ impl TokenParser for ContinueStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ContinueStatement", "Parsing");
cursor.expect(Keyword::Continue, "continue statement")?; cursor.expect(Keyword::Continue, "continue statement")?;
let label = if let (true, tok) = cursor.peek_semicolon(false) { let label = if let (true, tok) = cursor.peek_semicolon(false) {

6
boa/src/syntax/parser/statement/declaration/hoistable.rs

@ -5,12 +5,15 @@
//! //!
//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration //! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration
use crate::syntax::{ use crate::{
syntax::{
ast::{node::FunctionDecl, Keyword, Node, Punctuator}, ast::{node::FunctionDecl, Keyword, Node, Punctuator},
parser::{ parser::{
function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, function::FormalParameters, function::FunctionBody, statement::BindingIdentifier,
AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Hoistable declaration parsing. /// Hoistable declaration parsing.
@ -46,6 +49,7 @@ impl TokenParser for HoistableDeclaration {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing");
// TODO: check for generators and async functions + generators // TODO: check for generators and async functions + generators
FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default)
.parse(cursor) .parse(cursor)

6
boa/src/syntax/parser/statement/declaration/lexical.rs

@ -7,7 +7,8 @@
//! //!
//! [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations //! [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{ConstDecl, ConstDeclList, LetDecl, LetDeclList, Node}, node::{ConstDecl, ConstDeclList, LetDecl, LetDeclList, Node},
Keyword, Punctuator, TokenKind, Keyword, Punctuator, TokenKind,
@ -16,6 +17,8 @@ use crate::syntax::{
expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield, expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield,
Cursor, ParseError, ParseResult, TokenParser, Cursor, ParseError, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Parses a lexical declaration. /// Parses a lexical declaration.
@ -51,6 +54,7 @@ impl TokenParser for LexicalDeclaration {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("LexicalDeclaration", "Parsing");
let tok = cursor.next().ok_or(ParseError::AbruptEnd)?; let tok = cursor.next().ok_or(ParseError::AbruptEnd)?;
match tok.kind { match tok.kind {

6
boa/src/syntax/parser/statement/declaration/mod.rs

@ -13,9 +13,12 @@ mod lexical;
mod tests; mod tests;
use self::{hoistable::HoistableDeclaration, lexical::LexicalDeclaration}; use self::{hoistable::HoistableDeclaration, lexical::LexicalDeclaration};
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, TokenKind}, ast::{Keyword, Node, TokenKind},
parser::{AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser}, parser::{AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser},
},
BoaProfiler,
}; };
/// Parses a declaration. /// Parses a declaration.
@ -47,6 +50,7 @@ impl TokenParser for Declaration {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("Declaration", "Parsing");
let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
match tok.kind { match tok.kind {

6
boa/src/syntax/parser/statement/if_stm/mod.rs

@ -2,12 +2,15 @@
mod tests; mod tests;
use super::Statement; use super::Statement;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{ parser::{
expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseResult, expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseResult,
TokenParser, TokenParser,
}, },
},
BoaProfiler,
}; };
/// If statement parsing. /// If statement parsing.
@ -47,6 +50,7 @@ impl TokenParser for IfStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("IfStatement", "Parsing");
cursor.expect(Keyword::If, "if statement")?; cursor.expect(Keyword::If, "if statement")?;
cursor.expect(Punctuator::OpenParen, "if statement")?; cursor.expect(Punctuator::OpenParen, "if statement")?;

10
boa/src/syntax/parser/statement/iteration/do_while_statement.rs

@ -7,12 +7,15 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
//! [spec]: https://tc39.es/ecma262/#sec-do-while-statement //! [spec]: https://tc39.es/ecma262/#sec-do-while-statement
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{ parser::{
expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield,
ParseError, ParseResult, TokenParser, Cursor, ParseError, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Do...while statement parsing /// Do...while statement parsing
@ -54,6 +57,7 @@ impl TokenParser for DoWhileStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("DoWhileStatement", "Parsing");
cursor.expect(Keyword::Do, "do while statement")?; cursor.expect(Keyword::Do, "do while statement")?;
let body = let body =

6
boa/src/syntax/parser/statement/iteration/for_statement.rs

@ -7,7 +7,8 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
//! [spec]: https://tc39.es/ecma262/#sec-for-statement //! [spec]: https://tc39.es/ecma262/#sec-for-statement
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{ForLoop, Node}, node::{ForLoop, Node},
Const, Keyword, Punctuator, TokenKind, Const, Keyword, Punctuator, TokenKind,
@ -18,6 +19,8 @@ use crate::syntax::{
statement::{variable::VariableDeclarationList, Statement}, statement::{variable::VariableDeclarationList, Statement},
AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser,
}, },
},
BoaProfiler,
}; };
/// For statement parsing /// For statement parsing
@ -59,6 +62,7 @@ impl TokenParser for ForStatement {
type Output = ForLoop; type Output = ForLoop;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<ForLoop, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<ForLoop, ParseError> {
let _timer = BoaProfiler::global().start_event("ForStatement", "Parsing");
cursor.expect(Keyword::For, "for statement")?; cursor.expect(Keyword::For, "for statement")?;
cursor.expect(Punctuator::OpenParen, "for statement")?; cursor.expect(Punctuator::OpenParen, "for statement")?;

10
boa/src/syntax/parser/statement/iteration/while_statement.rs

@ -1,9 +1,12 @@
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator}, ast::{Keyword, Node, Punctuator},
parser::{ parser::{
expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield,
ParseResult, TokenParser, Cursor, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// While statement parsing /// While statement parsing
@ -45,6 +48,7 @@ impl TokenParser for WhileStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("WhileStatement", "Parsing");
cursor.expect(Keyword::While, "while statement")?; cursor.expect(Keyword::While, "while statement")?;
cursor.expect(Punctuator::OpenParen, "while statement")?; cursor.expect(Punctuator::OpenParen, "while statement")?;

10
boa/src/syntax/parser/statement/mod.rs

@ -36,7 +36,10 @@ use super::{
expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, ParseResult, expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, ParseResult,
TokenParser, TokenParser,
}; };
use crate::syntax::ast::{node, Keyword, Node, Punctuator, TokenKind}; use crate::{
syntax::ast::{node, Keyword, Node, Punctuator, TokenKind},
BoaProfiler,
};
/// Statement parsing. /// Statement parsing.
/// ///
@ -90,6 +93,7 @@ impl TokenParser for Statement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("Statement", "Parsing");
// TODO: add BreakableStatement and divide Whiles, fors and so on to another place. // TODO: add BreakableStatement and divide Whiles, fors and so on to another place.
let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
@ -197,6 +201,7 @@ impl TokenParser for StatementList {
type Output = node::StatementList; type Output = node::StatementList;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("StatementList", "Parsing");
let mut items = Vec::new(); let mut items = Vec::new();
loop { loop {
@ -270,6 +275,7 @@ impl TokenParser for StatementListItem {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("StatementListItem", "Parsing");
let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
match tok.kind { match tok.kind {
@ -315,6 +321,7 @@ impl TokenParser for ExpressionStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ExpressionStatement", "Parsing");
// TODO: lookahead // TODO: lookahead
let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
@ -364,6 +371,7 @@ impl TokenParser for BindingIdentifier {
type Output = Box<str>; type Output = Box<str>;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("BindingIdentifier", "Parsing");
// TODO: strict mode. // TODO: strict mode.
let next_token = cursor.next().ok_or(ParseError::AbruptEnd)?; let next_token = cursor.next().ok_or(ParseError::AbruptEnd)?;

10
boa/src/syntax/parser/statement/return_stm/mod.rs

@ -1,9 +1,14 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, parser::{
expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser,
},
},
BoaProfiler,
}; };
/// Return statement parsing /// Return statement parsing
@ -38,6 +43,7 @@ impl TokenParser for ReturnStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ReturnStatement", "Parsing");
cursor.expect(Keyword::Return, "return statement")?; cursor.expect(Keyword::Return, "return statement")?;
if let (true, tok) = cursor.peek_semicolon(false) { if let (true, tok) = cursor.peek_semicolon(false) {

6
boa/src/syntax/parser/statement/switch/mod.rs

@ -1,12 +1,15 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator}, ast::{Keyword, Node, Punctuator},
parser::{ parser::{
expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError,
ParseResult, TokenParser, ParseResult, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Switch statement parsing. /// Switch statement parsing.
@ -44,6 +47,7 @@ impl TokenParser for SwitchStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("SwitchStatement", "Parsing");
cursor.expect(Keyword::Switch, "switch statement")?; cursor.expect(Keyword::Switch, "switch statement")?;
cursor.expect(Punctuator::OpenParen, "switch statement")?; cursor.expect(Punctuator::OpenParen, "switch statement")?;

10
boa/src/syntax/parser/statement/throw/mod.rs

@ -1,9 +1,14 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::syntax::{ use crate::{
syntax::{
ast::{Keyword, Node, Punctuator, TokenKind}, ast::{Keyword, Node, Punctuator, TokenKind},
parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, parser::{
expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser,
},
},
BoaProfiler,
}; };
/// For statement parsing /// For statement parsing
@ -38,6 +43,7 @@ impl TokenParser for ThrowStatement {
type Output = Node; type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ThrowStatement", "Parsing");
cursor.expect(Keyword::Throw, "throw statement")?; cursor.expect(Keyword::Throw, "throw statement")?;
cursor.peek_expect_no_lineterminator(0)?; cursor.peek_expect_no_lineterminator(0)?;

6
boa/src/syntax/parser/statement/try_stm/catch.rs

@ -1,4 +1,5 @@
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{self, Identifier}, node::{self, Identifier},
Keyword, Punctuator, Keyword, Punctuator,
@ -7,6 +8,8 @@ use crate::syntax::{
statement::{block::Block, BindingIdentifier}, statement::{block::Block, BindingIdentifier},
AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Catch parsing /// Catch parsing
@ -44,6 +47,7 @@ impl TokenParser for Catch {
type Output = node::Catch; type Output = node::Catch;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("Catch", "Parsing");
cursor.expect(Keyword::Catch, "try statement")?; cursor.expect(Keyword::Catch, "try statement")?;
let catch_param = if cursor.next_if(Punctuator::OpenParen).is_some() { let catch_param = if cursor.next_if(Punctuator::OpenParen).is_some() {
let catch_param = let catch_param =

6
boa/src/syntax/parser/statement/try_stm/finally.rs

@ -1,9 +1,12 @@
use crate::syntax::{ use crate::{
syntax::{
ast::{node, Keyword}, ast::{node, Keyword},
parser::{ parser::{
statement::block::Block, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, statement::block::Block, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError,
TokenParser, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Finally parsing /// Finally parsing
@ -41,6 +44,7 @@ impl TokenParser for Finally {
type Output = node::Finally; type Output = node::Finally;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("Finally", "Parsing");
cursor.expect(Keyword::Finally, "try statement")?; cursor.expect(Keyword::Finally, "try statement")?;
Ok( Ok(
Block::new(self.allow_yield, self.allow_await, self.allow_return) Block::new(self.allow_yield, self.allow_await, self.allow_return)

6
boa/src/syntax/parser/statement/try_stm/mod.rs

@ -7,9 +7,12 @@ mod tests;
use self::catch::Catch; use self::catch::Catch;
use self::finally::Finally; use self::finally::Finally;
use super::block::Block; use super::block::Block;
use crate::syntax::{ use crate::{
syntax::{
ast::{node::Try, Keyword, TokenKind}, ast::{node::Try, Keyword, TokenKind},
parser::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser}, parser::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser},
},
BoaProfiler,
}; };
/// Try...catch statement parsing /// Try...catch statement parsing
@ -47,6 +50,7 @@ impl TokenParser for TryStatement {
type Output = Try; type Output = Try;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Try, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Try, ParseError> {
let _timer = BoaProfiler::global().start_event("TryStatement", "Parsing");
// TRY // TRY
cursor.expect(Keyword::Try, "try statement")?; cursor.expect(Keyword::Try, "try statement")?;

6
boa/src/syntax/parser/statement/variable.rs

@ -1,5 +1,6 @@
// use super::lexical_declaration_continuation; // use super::lexical_declaration_continuation;
use crate::syntax::{ use crate::{
syntax::{
ast::{ ast::{
node::{VarDecl, VarDeclList}, node::{VarDecl, VarDeclList},
Keyword, Punctuator, TokenKind, Keyword, Punctuator, TokenKind,
@ -8,6 +9,8 @@ use crate::syntax::{
expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield, expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield,
Cursor, ParseError, TokenParser, Cursor, ParseError, TokenParser,
}, },
},
BoaProfiler,
}; };
/// Variable statement parsing. /// Variable statement parsing.
@ -44,6 +47,7 @@ impl TokenParser for VariableStatement {
type Output = VarDeclList; type Output = VarDeclList;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("VariableStatement", "Parsing");
cursor.expect(Keyword::Var, "variable statement")?; cursor.expect(Keyword::Var, "variable statement")?;
let decl_list = let decl_list =

BIN
docs/img/profiler.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

30
docs/profiling.md

@ -0,0 +1,30 @@
# Profiling
![Example](img/profiler.png)
It's possible to get a full profile of Boa in action.
Sometimes this is needed to figure out where it is spending most of it's time.
We use a crate called [measureme](https://github.com/rust-lang/measureme), which helps us keep track of timing functions during runtime.
When the "profiler" flag is enabled, you compile with the profiler and it is called throughout the interpreter.
when the feature flag is not enabled, you have an empty dummy implementation that is just no ops. rustc should completely optimize that away. So there should be no performance downgrade from these changes
## Prerequesites
- [Crox](https://github.com/rust-lang/measureme/blob/master/crox/Readme.md)
## How To Use
You can run boa using the "profiler" feature flag to enable profiling. Seeing as you'll most likely be using boa_cli you can pass this through, like so:
`cargo run --features Boa/profiler ../tests/js/test.js`
Once finished you should see some trace files left in the directory (boa_cli in this case).
In the same directory as the `.events, string_data, string_index` files run `crox my_trace` or whatever the name of the files are. This will generate a chrome_profiler.json file, you can load this into Chrome Dev tools.
## More Info
- https://blog.rust-lang.org/inside-rust/2020/02/25/intro-rustc-self-profile.html
- https://github.com/rust-lang/measureme
- https://github.com/rust-lang/measureme/blob/master/crox/Readme.md
Loading…
Cancel
Save