|
|
|
//! Benchmarks of the whole execution engine in Boa.
|
|
|
|
|
|
|
|
use boa_engine::{
|
Implement `Hidden classes` (#2723)
This PR implements `Hidden Classes`, I named them as `Shapes` (like Spidermonkey does), calling them maps like v8 seems confusing because there already is a JS builtin, likewise with `Hidden classes` since there are already classes in JS.
There are two types of shapes: `shared` shapes that create the transition tree, and are shared between objects, this is mainly intended for user defined objects this makes more sense because shapes can create transitions trees, doing that for the builtins seems wasteful (unless users wanted to creating an object with the same property names and the same property attributes in the same order... which seems unlikely). That's why I added `unique` shapes, only one object has it. This is similar to previous solution, but this architecture enables us to use inline caching.
There will probably be a performance hit until we implement inline caching.
There still a lot of work that needs to be done, on this:
- [x] Move Property Attributes to shape
- [x] Move Prototype to shape
- [x] ~~Move extensible flag to shape~~, On further evaluation this doesn't give any benefit (at least right now), since it isn't used by inline caching also adding one more transition.
- [x] Implement delete for unique shapes.
- [x] If the chain is too long we should probably convert it into a `unique` shape
- [x] Figure out threshold ~~(maybe more that 256 properties ?)~~ curently set to an arbitrary number (`1024`)
- [x] Implement shared property table between shared shapes
- [x] Add code Document
- [x] Varying size storage for properties (get+set = 2, data = 1)
- [x] Add shapes to more object:
- [x] ordinary object
- [x] Arrays
- [x] Functions
- [x] Other builtins
- [x] Add `shapes.md` doc explaining shapes in depth with mermaid diagrams :)
- [x] Add `$boa.shape` module
- [x] `$boa.shape.id(o)`
- [x] `$boa.shape.type(o)`
- [x] `$boa.shape.same(o1, o2)`
- [x] add doc to `boa_object.md`
2 years ago
|
|
|
context::DefaultHooks, object::shape::SharedShape, optimizer::OptimizerOptions, realm::Realm,
|
|
|
|
Context, Source,
|
|
|
|
};
|
|
|
|
use criterion::{criterion_group, criterion_main, Criterion};
|
|
|
|
use std::hint::black_box;
|
|
|
|
|
|
|
|
#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
|
|
|
|
#[cfg_attr(
|
|
|
|
all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"),
|
|
|
|
global_allocator
|
|
|
|
)]
|
|
|
|
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|
|
|
|
|
|
|
fn create_realm(c: &mut Criterion) {
|
|
|
|
c.bench_function("Create Realm", move |b| {
|
Implement `Hidden classes` (#2723)
This PR implements `Hidden Classes`, I named them as `Shapes` (like Spidermonkey does), calling them maps like v8 seems confusing because there already is a JS builtin, likewise with `Hidden classes` since there are already classes in JS.
There are two types of shapes: `shared` shapes that create the transition tree, and are shared between objects, this is mainly intended for user defined objects this makes more sense because shapes can create transitions trees, doing that for the builtins seems wasteful (unless users wanted to creating an object with the same property names and the same property attributes in the same order... which seems unlikely). That's why I added `unique` shapes, only one object has it. This is similar to previous solution, but this architecture enables us to use inline caching.
There will probably be a performance hit until we implement inline caching.
There still a lot of work that needs to be done, on this:
- [x] Move Property Attributes to shape
- [x] Move Prototype to shape
- [x] ~~Move extensible flag to shape~~, On further evaluation this doesn't give any benefit (at least right now), since it isn't used by inline caching also adding one more transition.
- [x] Implement delete for unique shapes.
- [x] If the chain is too long we should probably convert it into a `unique` shape
- [x] Figure out threshold ~~(maybe more that 256 properties ?)~~ curently set to an arbitrary number (`1024`)
- [x] Implement shared property table between shared shapes
- [x] Add code Document
- [x] Varying size storage for properties (get+set = 2, data = 1)
- [x] Add shapes to more object:
- [x] ordinary object
- [x] Arrays
- [x] Functions
- [x] Other builtins
- [x] Add `shapes.md` doc explaining shapes in depth with mermaid diagrams :)
- [x] Add `$boa.shape` module
- [x] `$boa.shape.id(o)`
- [x] `$boa.shape.type(o)`
- [x] `$boa.shape.same(o1, o2)`
- [x] add doc to `boa_object.md`
2 years ago
|
|
|
let root_shape = SharedShape::root();
|
|
|
|
b.iter(|| Realm::create(&DefaultHooks, &root_shape))
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! full_benchmarks {
|
|
|
|
($({$id:literal, $name:ident}),*) => {
|
|
|
|
fn bench_parser(c: &mut Criterion) {
|
|
|
|
$(
|
|
|
|
{
|
|
|
|
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
|
|
|
|
let mut context = Context::default();
|
|
|
|
|
|
|
|
// Disable optimizations
|
|
|
|
context.set_optimizer_options(OptimizerOptions::empty());
|
|
|
|
|
|
|
|
c.bench_function(concat!($id, " (Parser)"), move |b| {
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
b.iter(|| context.parse_script(black_box(Source::from_bytes(CODE))))
|
|
|
|
});
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
fn bench_compile(c: &mut Criterion) {
|
|
|
|
$(
|
|
|
|
{
|
|
|
|
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
|
|
|
|
let mut context = Context::default();
|
|
|
|
|
|
|
|
// Disable optimizations
|
|
|
|
context.set_optimizer_options(OptimizerOptions::empty());
|
|
|
|
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
let statement_list = context.parse_script(Source::from_bytes(CODE)).expect("parsing failed");
|
|
|
|
c.bench_function(concat!($id, " (Compiler)"), move |b| {
|
|
|
|
b.iter(|| {
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
context.compile_script(black_box(&statement_list))
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
fn bench_execution(c: &mut Criterion) {
|
|
|
|
$(
|
|
|
|
{
|
|
|
|
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
|
|
|
|
let mut context = Context::default();
|
|
|
|
|
|
|
|
// Disable optimizations
|
|
|
|
context.set_optimizer_options(OptimizerOptions::empty());
|
|
|
|
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
let statement_list = context.parse_script(Source::from_bytes(CODE)).expect("parsing failed");
|
|
|
|
let code_block = context.compile_script(&statement_list).unwrap();
|
|
|
|
c.bench_function(concat!($id, " (Execution)"), move |b| {
|
|
|
|
b.iter(|| {
|
|
|
|
context.execute(black_box(code_block.clone())).unwrap()
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
full_benchmarks!(
|
|
|
|
{"Symbols", symbol_creation},
|
|
|
|
{"For loop", for_loop},
|
|
|
|
{"Fibonacci", fibonacci},
|
|
|
|
{"Object Creation", object_creation},
|
|
|
|
{"Static Object Property Access", object_prop_access_const},
|
|
|
|
{"Dynamic Object Property Access", object_prop_access_dyn},
|
|
|
|
{"RegExp Literal Creation", regexp_literal_creation},
|
|
|
|
{"RegExp Creation", regexp_creation},
|
|
|
|
{"RegExp Literal", regexp_literal},
|
|
|
|
{"RegExp", regexp},
|
|
|
|
{"Array access", array_access},
|
|
|
|
{"Array creation", array_create},
|
|
|
|
{"Array pop", array_pop},
|
|
|
|
{"String concatenation", string_concat},
|
|
|
|
{"String comparison", string_compare},
|
|
|
|
{"String copy", string_copy},
|
|
|
|
{"Number Object Access", number_object_access},
|
|
|
|
{"Boolean Object Access", boolean_object_access},
|
|
|
|
{"String Object Access", string_object_access},
|
|
|
|
{"Arithmetic operations", arithmetic_operations},
|
|
|
|
{"Clean js", clean_js},
|
|
|
|
{"Mini js", mini_js}
|
|
|
|
);
|
|
|
|
|
|
|
|
criterion_group!(
|
|
|
|
benches,
|
|
|
|
create_realm,
|
|
|
|
bench_parser,
|
|
|
|
bench_compile,
|
|
|
|
bench_execution,
|
|
|
|
);
|
|
|
|
criterion_main!(benches);
|