Skip to content

Commit

Permalink
Add optimizer options and apply review
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Mar 20, 2023
1 parent cfc94e9 commit 05c8d73
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 58 deletions.
2 changes: 1 addition & 1 deletion boa_ast/src/expression/literal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub enum Literal {
Null,

/// This represents the JavaScript `undefined` value, it does not reference the `undefined` global variable,
/// it will directly evaluluate to `undefined`.
/// it will directly evaluate to `undefined`.
///
/// NOTE: This is used for optimizations.
Undefined,
Expand Down
9 changes: 7 additions & 2 deletions boa_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use boa_ast::StatementList;
use boa_engine::{
context::ContextBuilder,
job::{FutureJob, JobQueue, NativeJob},
optimizer::OptimizerOptions,
vm::flowgraph::{Direction, Graph},
Context, JsResult, Source,
};
Expand Down Expand Up @@ -306,8 +307,12 @@ fn main() -> Result<(), io::Error> {

// Trace Output
context.set_trace(args.trace);
context.optimize(args.optimize);
context.optimizer_statistics(args.optimizer_statistics);

// Configure optimizer options
let mut optimizer_options = OptimizerOptions::empty();
optimizer_options.set(OptimizerOptions::STATISTICS, args.optimizer_statistics);
optimizer_options.set(OptimizerOptions::OPTIMIZE_ALL, args.optimize);
context.set_optimizer_options(optimizer_options);

if args.files.is_empty() {
let config = Config::builder()
Expand Down
36 changes: 13 additions & 23 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ use crate::{
job::{IdleJobQueue, JobQueue, NativeJob},
native_function::NativeFunction,
object::{FunctionObjectBuilder, GlobalPropertyMap, JsObject},
optimizer::{Optimizer, OptimizerStatistics},
optimizer::{Optimizer, OptimizerOptions, OptimizerStatistics},
property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm,
vm::{CallFrame, CodeBlock, Vm},
JsResult, JsValue, Source,
};
use boa_ast::{visitor::VisitorMut, ModuleItemList, StatementList};
use boa_ast::{ModuleItemList, StatementList};
use boa_gc::Gc;
use boa_interner::{Interner, Sym};
use boa_parser::{Error as ParseError, Parser};
Expand Down Expand Up @@ -103,8 +103,7 @@ pub struct Context<'host> {

job_queue: &'host dyn JobQueue,

optimize: bool,
optimizer_statistics: bool,
optimizer_options: OptimizerOptions,
}

impl std::fmt::Debug for Context<'_> {
Expand All @@ -118,8 +117,7 @@ impl std::fmt::Debug for Context<'_> {
.field("strict", &self.strict)
.field("promise_job_queue", &"JobQueue")
.field("hooks", &"HostHooks")
.field("optimize", &self.optimize)
.field("optimizer_statistics", &self.optimizer_statistics);
.field("optimize", &self.optimizer_options);

#[cfg(feature = "intl")]
debug.field("icu", &self.icu);
Expand Down Expand Up @@ -214,12 +212,7 @@ impl Context<'_> {
statement_list: &mut StatementList,
) -> OptimizerStatistics {
let mut optimizer = Optimizer::new(self);
optimizer.visit_statement_list_mut(statement_list);
let statistics = optimizer.statistics();
if self.optimizer_statistics {
println!("{statistics}");
}
statistics
optimizer.apply(statement_list)
}

/// Parse the given source script.
Expand All @@ -233,7 +226,7 @@ impl Context<'_> {
parser.set_strict();
}
let mut result = parser.parse_script(&mut self.interner)?;
if self.optimize {
if !self.optimizer_options().is_empty() {
self.optimize_statement_list(&mut result);
}
Ok(result)
Expand Down Expand Up @@ -450,14 +443,13 @@ impl Context<'_> {
self.vm.trace = trace;
}

/// Enable or disable optimizations
pub fn optimize(&mut self, optimize: bool) {
self.optimize = optimize;
/// Get optimizer options.
pub const fn optimizer_options(&self) -> OptimizerOptions {
self.optimizer_options
}

/// Print optimizer statistics to `stdout`. `false` by default.
pub fn optimizer_statistics(&mut self, show: bool) {
self.optimizer_statistics = show;
/// Enable or disable optimizations
pub fn set_optimizer_options(&mut self, optimizer_options: OptimizerOptions) {
self.optimizer_options = optimizer_options;
}

/// Changes the strictness mode of the context.
Expand Down Expand Up @@ -676,9 +668,7 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> {
kept_alive: Vec::new(),
host_hooks,
job_queue: self.job_queue.unwrap_or(&IdleJobQueue),
// TODO: maybe it should be off by default
optimize: true,
optimizer_statistics: false,
optimizer_options: OptimizerOptions::empty(),
};

builtins::set_default_global_bindings(&mut context)?;
Expand Down
48 changes: 34 additions & 14 deletions boa_engine/src/optimizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,27 @@ pub(crate) mod walker;

use self::{pass::ConstantFolding, walker::Walker};
use crate::Context;
use boa_ast::{visitor::VisitorMut, Expression};
use bitflags::bitflags;
use boa_ast::{visitor::VisitorMut, Expression, StatementList};
use std::{fmt, ops::ControlFlow};

bitflags! {
/// Optimizer options.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct OptimizerOptions: u8 {
/// Print statistics to `stdout`.
const STATISTICS = 0b0000_0001;

/// Apply contant folding optimization.
const CONSTANT_FOLDING = 0b0000_0010;

/// Apply all optimizations.
const OPTIMIZE_ALL = Self::CONSTANT_FOLDING.bits();
}
}

/// The action to be performed after an optimization step.
#[derive(Debug)]

pub(crate) enum PassAction<T> {
/// Keep the node, do nothing.
Keep,
Expand Down Expand Up @@ -87,20 +102,25 @@ impl<'context, 'host> Optimizer<'context, 'host> {
}

fn run_all(&mut self, expr: &mut Expression) {
// TODO: Add more optimizations here...
// loop {
// let mut changed = false;
// changed |= self.run_constant_folding_pass(expr);
//
// if !changed {
// break;
// }
// }
self.run_constant_folding_pass(expr);
if self
.context
.optimizer_options()
.contains(OptimizerOptions::CONSTANT_FOLDING)
{
self.run_constant_folding_pass(expr);
}
}

/// Get statistics
pub(crate) const fn statistics(&self) -> OptimizerStatistics {
/// Apply optimizations inplace.
pub(crate) fn apply(&mut self, statement_list: &mut StatementList) -> OptimizerStatistics {
self.visit_statement_list_mut(statement_list);
if self
.context
.optimizer_options()
.contains(OptimizerOptions::STATISTICS)
{
println!("{}", self.statistics);
}
self.statistics
}
}
Expand Down
39 changes: 25 additions & 14 deletions boa_tester/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
};
use boa_engine::{
context::ContextBuilder, job::SimpleJobQueue, native_function::NativeFunction,
object::FunctionObjectBuilder, property::Attribute, Context, JsArgs, JsNativeErrorKind,
JsValue, Source,
object::FunctionObjectBuilder, optimizer::OptimizerOptions, property::Attribute, Context,
JsArgs, JsNativeErrorKind, JsValue, Source,
};
use colored::Colorize;
use rayon::prelude::*;
Expand All @@ -22,7 +22,7 @@ impl TestSuite {
harness: &Harness,
verbose: u8,
parallel: bool,
optimize: bool,
optimizer_options: OptimizerOptions,
) -> SuiteResult {
if verbose != 0 {
println!("Suite {}:", self.path.display());
Expand All @@ -31,24 +31,24 @@ impl TestSuite {
let suites: Vec<_> = if parallel {
self.suites
.par_iter()
.map(|suite| suite.run(harness, verbose, parallel, optimize))
.map(|suite| suite.run(harness, verbose, parallel, optimizer_options))
.collect()
} else {
self.suites
.iter()
.map(|suite| suite.run(harness, verbose, parallel, optimize))
.map(|suite| suite.run(harness, verbose, parallel, optimizer_options))
.collect()
};

let tests: Vec<_> = if parallel {
self.tests
.par_iter()
.flat_map(|test| test.run(harness, verbose, optimize))
.flat_map(|test| test.run(harness, verbose, optimizer_options))
.collect()
} else {
self.tests
.iter()
.flat_map(|test| test.run(harness, verbose, optimize))
.flat_map(|test| test.run(harness, verbose, optimizer_options))
.collect()
};

Expand Down Expand Up @@ -119,21 +119,32 @@ impl TestSuite {

impl Test {
/// Runs the test.
pub(crate) fn run(&self, harness: &Harness, verbose: u8, optimize: bool) -> Vec<TestResult> {
pub(crate) fn run(
&self,
harness: &Harness,
verbose: u8,
optimizer_options: OptimizerOptions,
) -> Vec<TestResult> {
let mut results = Vec::new();
if self.flags.contains(TestFlags::STRICT) && !self.flags.contains(TestFlags::RAW) {
results.push(self.run_once(harness, true, verbose, optimize));
results.push(self.run_once(harness, true, verbose, optimizer_options));
}

if self.flags.contains(TestFlags::NO_STRICT) || self.flags.contains(TestFlags::RAW) {
results.push(self.run_once(harness, false, verbose, optimize));
results.push(self.run_once(harness, false, verbose, optimizer_options));
}

results
}

/// Runs the test once, in strict or non-strict mode
fn run_once(&self, harness: &Harness, strict: bool, verbose: u8, optimize: bool) -> TestResult {
fn run_once(
&self,
harness: &Harness,
strict: bool,
verbose: u8,
optimizer_options: OptimizerOptions,
) -> TestResult {
let Ok(source) = Source::from_filepath(&self.path) else {
if verbose > 1 {
println!(
Expand Down Expand Up @@ -191,7 +202,7 @@ impl Test {
return (false, e);
}
context.strict(strict);
context.optimize(optimize);
context.set_optimizer_options(optimizer_options);

// TODO: timeout
let value = match if self.is_module() {
Expand Down Expand Up @@ -231,7 +242,7 @@ impl Test {

let context = &mut Context::default();
context.strict(strict);
context.optimize(optimize);
context.set_optimizer_options(OptimizerOptions::OPTIMIZE_ALL);

if self.is_module() {
match context.parse_module(source) {
Expand Down Expand Up @@ -261,7 +272,7 @@ impl Test {
} => {
let context = &mut Context::default();
context.strict(strict);
context.optimize(optimize);
context.set_optimizer_options(optimizer_options);

if let Err(e) = self.set_up_env(harness, context, AsyncResult::default()) {
return (false, e);
Expand Down
13 changes: 9 additions & 4 deletions boa_tester/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ use self::{
results::{compare_results, write_json},
};
use bitflags::bitflags;
use boa_engine::optimizer::OptimizerOptions;
use clap::{ArgAction, Parser, ValueHint};
use color_eyre::{
eyre::{bail, WrapErr},
Expand Down Expand Up @@ -211,7 +212,11 @@ fn main() -> Result<()> {
suite.as_path(),
output.as_deref(),
ignore.as_path(),
optimize,
if optimize {
OptimizerOptions::OPTIMIZE_ALL
} else {
OptimizerOptions::empty()
},
),
Cli::Compare {
base,
Expand All @@ -229,7 +234,7 @@ fn run_test_suite(
suite: &Path,
output: Option<&Path>,
ignored: &Path,
optimize: bool,
optimizer_options: OptimizerOptions,
) -> Result<()> {
if let Some(path) = output {
if path.exists() {
Expand Down Expand Up @@ -263,7 +268,7 @@ fn run_test_suite(
if verbose != 0 {
println!("Test loaded, starting...");
}
test.run(&harness, verbose, optimize);
test.run(&harness, verbose, optimizer_options);

println!();
} else {
Expand All @@ -275,7 +280,7 @@ fn run_test_suite(
if verbose != 0 {
println!("Test suite loaded, starting tests...");
}
let results = suite.run(&harness, verbose, parallel, optimize);
let results = suite.run(&harness, verbose, parallel, optimizer_options);

println!();
println!("Results:");
Expand Down

0 comments on commit 05c8d73

Please sign in to comment.