From 7f2353767b510dbf49eed80f4f92077b9c7565a7 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 22 Aug 2020 16:10:01 +0100 Subject: [PATCH] Catchup new_lexer (#657) * Added CLEAN_JS and MINI_JS benches (#581) * Added CLEAN_JS and MINI_JS benches These benches are arbitrary code which is subject to change, functionally the programs are identical. * Forgot semicolon * Adding parsing benchmarks for CleanJS & MiniJS Added identical benchmark cases for parser. * Migrating Clean and Mini benchmarks to new format Adding js scripts in bench_scripts & moving exec, full and parser benchmarks to new include_str!() macro. * Move `require_object_coercible` to `Value` (#654) Co-authored-by: neeldug <5161147+neeldug@users.noreply.github.com> Co-authored-by: HalidOdat --- boa/benches/bench_scripts/clean_js.js | 15 ++++++++++++++ boa/benches/bench_scripts/mini_js.js | 1 + boa/benches/exec.rs | 28 +++++++++++++++++++++++++++ boa/benches/full.rs | 18 +++++++++++++++++ boa/benches/parser.rs | 28 +++++++++++++++++++++++++++ boa/src/builtins/string/mod.rs | 14 +++++++------- boa/src/builtins/value/mod.rs | 20 +++++++++++++++++++ boa/src/exec/mod.rs | 20 ------------------- 8 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 boa/benches/bench_scripts/clean_js.js create mode 100644 boa/benches/bench_scripts/mini_js.js diff --git a/boa/benches/bench_scripts/clean_js.js b/boa/benches/bench_scripts/clean_js.js new file mode 100644 index 00000000000..848ee4d8a0f --- /dev/null +++ b/boa/benches/bench_scripts/clean_js.js @@ -0,0 +1,15 @@ +!function () { + var M = new Array(); + for (i = 0; i < 100; i++) { + M.push(Math.floor(Math.random() * 100)); + } + var test = []; + for (i = 0; i < 100; i++) { + if (M[i] > 50) { + test.push(M[i]); + } + } + test.forEach(elem => { + 0 + }); +}(); diff --git a/boa/benches/bench_scripts/mini_js.js b/boa/benches/bench_scripts/mini_js.js new file mode 100644 index 00000000000..e7a82793a72 --- /dev/null +++ b/boa/benches/bench_scripts/mini_js.js @@ -0,0 +1 @@ +!function(){var r=new Array();for(i=0;i<100;i++)r.push(Math.floor(100*Math.random()));var a=[];for(i=0;i<100;i++)r[i]>50&&a.push(r[i]);a.forEach(i=>{0})}(); diff --git a/boa/benches/exec.rs b/boa/benches/exec.rs index 9c316e6d5ba..5e1e3799ce7 100644 --- a/boa/benches/exec.rs +++ b/boa/benches/exec.rs @@ -318,6 +318,32 @@ fn arithmetic_operations(c: &mut Criterion) { }); } +static CLEAN_JS: &str = include_str!("bench_scripts/clean_js.js"); + +fn clean_js(c: &mut Criterion) { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + let mut lexer = Lexer::new(CLEAN_JS); + lexer.lex().expect("failed to lex"); + let nodes = Parser::new(&lexer.tokens).parse_all().unwrap(); + c.bench_function("Clean js (Execution)", move |b| { + b.iter(|| black_box(&nodes).run(&mut engine).unwrap()) + }); +} + +static MINI_JS: &str = include_str!("bench_scripts/mini_js.js"); + +fn mini_js(c: &mut Criterion) { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + let mut lexer = Lexer::new(MINI_JS); + lexer.lex().expect("failed to lex"); + let nodes = Parser::new(&lexer.tokens).parse_all().unwrap(); + c.bench_function("Mini js (Execution)", move |b| { + b.iter(|| black_box(&nodes).run(&mut engine).unwrap()) + }); +} + criterion_group!( execution, create_realm, @@ -341,5 +367,7 @@ criterion_group!( boolean_object_access, string_object_access, arithmetic_operations, + clean_js, + mini_js, ); criterion_main!(execution); diff --git a/boa/benches/full.rs b/boa/benches/full.rs index 55dd5fab6ef..d979c5ea68f 100644 --- a/boa/benches/full.rs +++ b/boa/benches/full.rs @@ -178,6 +178,22 @@ fn arithmetic_operations(c: &mut Criterion) { }); } +static CLEAN_JS: &str = include_str!("bench_scripts/clean_js.js"); + +fn clean_js(c: &mut Criterion) { + c.bench_function("Clean js (Full)", move |b| { + b.iter(|| exec(black_box(CLEAN_JS))) + }); +} + +static MINI_JS: &str = include_str!("bench_scripts/mini_js.js"); + +fn mini_js(c: &mut Criterion) { + c.bench_function("Mini js (Full)", move |b| { + b.iter(|| exec(black_box(MINI_JS))) + }); +} + criterion_group!( full, symbol_creation, @@ -200,5 +216,7 @@ criterion_group!( boolean_object_access, string_object_access, arithmetic_operations, + clean_js, + mini_js, ); criterion_main!(full); diff --git a/boa/benches/parser.rs b/boa/benches/parser.rs index 869ce248c20..e0444984bf9 100644 --- a/boa/benches/parser.rs +++ b/boa/benches/parser.rs @@ -70,6 +70,32 @@ fn goal_symbol_switch(c: &mut Criterion) { }); } +static CLEAN_JS: &str = include_str!("bench_scripts/clean_js.js"); + +fn clean_js(c: &mut Criterion) { + c.bench_function("Clean js (Parser)", move |b| { + b.iter(|| { + let mut lexer = Lexer::new(black_box(CLEAN_JS)); + lexer.lex().expect("failed to lex"); + + Parser::new(&black_box(lexer.tokens)).parse_all() + }) + }); +} + +static MINI_JS: &str = include_str!("bench_scripts/mini_js.js"); + +fn mini_js(c: &mut Criterion) { + c.bench_function("Mini js (Parser)", move |b| { + b.iter(|| { + let mut lexer = Lexer::new(black_box(MINI_JS)); + lexer.lex().expect("failed to lex"); + + Parser::new(&black_box(lexer.tokens)).parse_all() + }) + }); +} + criterion_group!( parser, expression_parser, @@ -77,5 +103,7 @@ criterion_group!( for_loop_parser, long_file_parser, goal_symbol_switch, + clean_js, + mini_js, ); criterion_main!(parser); diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 1bfb0b749b8..9720f1b33d4 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -199,7 +199,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.concat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat pub(crate) fn concat(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result { - let object = ctx.require_object_coercible(this)?; + let object = this.require_object_coercible(ctx)?; let mut string = object.to_string(ctx)?.to_string(); for arg in args { @@ -221,7 +221,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.repeat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat pub(crate) fn repeat(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result { - let object = ctx.require_object_coercible(this)?; + let object = this.require_object_coercible(ctx)?; let string = object.to_string(ctx)?; if let Some(arg) = args.get(0) { @@ -563,7 +563,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.indexof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf pub(crate) fn index_of(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result { - let this = ctx.require_object_coercible(this)?; + let this = this.require_object_coercible(ctx)?; let string = this.to_string(ctx)?; let search_string = args @@ -610,7 +610,7 @@ impl String { args: &[Value], ctx: &mut Interpreter, ) -> Result { - let this = ctx.require_object_coercible(this)?; + let this = this.require_object_coercible(ctx)?; let string = this.to_string(ctx)?; let search_string = args @@ -776,7 +776,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trim /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim pub(crate) fn trim(this: &Value, _: &[Value], ctx: &mut Interpreter) -> Result { - let this = ctx.require_object_coercible(this)?; + let this = this.require_object_coercible(ctx)?; let string = this.to_string(ctx)?; Ok(Value::from( string.trim_matches(Self::is_trimmable_whitespace), @@ -796,7 +796,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trimstart /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimStart pub(crate) fn trim_start(this: &Value, _: &[Value], ctx: &mut Interpreter) -> Result { - let this = ctx.require_object_coercible(this)?; + let this = this.require_object_coercible(ctx)?; let string = this.to_string(ctx)?; Ok(Value::from( string.trim_start_matches(Self::is_trimmable_whitespace), @@ -816,7 +816,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trimend /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimEnd pub(crate) fn trim_end(this: &Value, _: &[Value], ctx: &mut Interpreter) -> Result { - let this = ctx.require_object_coercible(this)?; + let this = this.require_object_coercible(ctx)?; let string = this.to_string(ctx)?; Ok(Value::from( string.trim_end_matches(Self::is_trimmable_whitespace), diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 21811146a88..145c15e619a 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -916,6 +916,26 @@ impl Value { } primitive.to_number(ctx) } + + /// Check if the `Value` can be converted to an `Object` + /// + /// The abstract operation `RequireObjectCoercible` takes argument argument. + /// It throws an error if argument is a value that cannot be converted to an Object using `ToObject`. + /// It is defined by [Table 15][table] + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [table]: https://tc39.es/ecma262/#table-14 + /// [spec]: https://tc39.es/ecma262/#sec-requireobjectcoercible + #[inline] + pub fn require_object_coercible<'a>(&'a self, ctx: &mut Interpreter) -> Result<&'a Value> { + if self.is_null_or_undefined() { + Err(ctx.construct_type_error("cannot convert null or undefined to Object")) + } else { + Ok(self) + } + } } impl Default for Value { diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index af9f92f382b..2c05da1a474 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -333,26 +333,6 @@ impl Interpreter { &self.state } - /// Check if the `Value` can be converted to an `Object` - /// - /// The abstract operation `RequireObjectCoercible` takes argument argument. - /// It throws an error if argument is a value that cannot be converted to an Object using `ToObject`. - /// It is defined by [Table 15][table] - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - /// [table]: https://tc39.es/ecma262/#table-14 - /// [spec]: https://tc39.es/ecma262/#sec-requireobjectcoercible - #[inline] - pub fn require_object_coercible<'a>(&mut self, value: &'a Value) -> Result<&'a Value> { - if value.is_null_or_undefined() { - Err(self.construct_type_error("cannot convert null or undefined to Object")) - } else { - Ok(value) - } - } - /// A helper function for getting a immutable reference to the `console` object. pub(crate) fn console(&self) -> &Console { &self.console