From 910d20f6a51a91374facd1462b927bdb7e6eb0a9 Mon Sep 17 00:00:00 2001 From: Jason Williams Date: Wed, 18 Sep 2019 21:24:40 +0100 Subject: [PATCH] support early returns, fixes #101 --- Cargo.toml | 4 ++++ benches/fib.rs | 30 ++++++++++++++++++++++++++++++ src/lib/exec.rs | 23 ++++++++++++++++++----- tests/js/test.js | 14 ++++++++++++-- 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 benches/fib.rs diff --git a/Cargo.toml b/Cargo.toml index 16d5145dae..45e845f5f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,10 @@ path = "src/lib/lib.rs" name = "string" harness = false +[[bench]] +name = "fib" +harness = false + [[bin]] name = "boa" path = "src/bin/bin.rs" diff --git a/benches/fib.rs b/benches/fib.rs new file mode 100644 index 0000000000..1ef30fbdec --- /dev/null +++ b/benches/fib.rs @@ -0,0 +1,30 @@ +#[macro_use] +extern crate criterion; + +use boa::exec; +use boa::syntax::lexer::Lexer; +use boa::syntax::parser::Parser; +use criterion::black_box; +use criterion::Criterion; + +static SRC: &str = r#" +let num = 12; + +function fib(n) { + if (n <= 1) return 1; + return fib(n - 1) + fib(n - 2); +} + +let res = fib(num); + +res; +"#; + +fn fibonacci(c: &mut Criterion) { + c.bench_function("fibonacci (Execution)", move |b| { + b.iter(|| exec(black_box(SRC))) + }); +} + +criterion_group!(benches, fibonacci); +criterion_main!(benches); diff --git a/src/lib/exec.rs b/src/lib/exec.rs index c4e843d9d3..4b42a2e196 100644 --- a/src/lib/exec.rs +++ b/src/lib/exec.rs @@ -30,6 +30,7 @@ pub trait Executor { pub struct Interpreter { /// An object representing the global object environment: LexicalEnvironment, + is_return: bool, } /// Builder for the [`Interpreter`] @@ -62,7 +63,13 @@ impl Executor for Interpreter { let mut obj = to_value(None::<()>); for e in es.iter() { let val = self.run(e)?; - if e == es.last().unwrap() { + // early return + if self.is_return { + obj = val; + self.is_return = false; + break; + } + if e == es.last().expect("unable to get last value") { obj = val; } } @@ -312,10 +319,15 @@ impl Executor for Interpreter { _ => Ok(Gc::new(ValueData::Undefined)), } } - ExprDef::Return(ref ret) => match *ret { - Some(ref v) => self.run(v), - None => Ok(Gc::new(ValueData::Undefined)), - }, + ExprDef::Return(ref ret) => { + let result = match *ret { + Some(ref v) => self.run(v), + None => Ok(Gc::new(ValueData::Undefined)), + }; + // Set flag for return + self.is_return = true; + result + } ExprDef::Throw(ref ex) => Err(self.run(ex)?), ExprDef::Assign(ref ref_e, ref val_e) => { let val = self.run(val_e)?; @@ -410,6 +422,7 @@ impl InterpreterBuilder { pub fn build(self) -> Interpreter { Interpreter { environment: LexicalEnvironment::new(self.global.clone()), + is_return: false, } } } diff --git a/tests/js/test.js b/tests/js/test.js index ffbdea4081..1946d591b6 100644 --- a/tests/js/test.js +++ b/tests/js/test.js @@ -1,2 +1,12 @@ -let a = "hello"; -print(a); +let num = 12; + +function fib(n) { + if (n <= 1) return 1; + return fib(n - 1) + fib(n - 2); +} + +let res = fib(num); + +res; + +// (2 - 1 = 1) + (2 - 2 = rt 1)