Skip to content

Commit

Permalink
Merge f242368 into 431a358
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Mar 20, 2023
2 parents 431a358 + f242368 commit ccf84f4
Show file tree
Hide file tree
Showing 15 changed files with 583 additions and 35 deletions.
7 changes: 7 additions & 0 deletions boa_ast/src/expression/literal/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ impl AsRef<[Option<Expression>]> for ArrayLiteral {
}
}

impl AsMut<[Option<Expression>]> for ArrayLiteral {
#[inline]
fn as_mut(&mut self) -> &mut [Option<Expression>] {
&mut self.arr
}
}

impl<T> From<T> for ArrayLiteral
where
T: Into<Box<[Option<Expression>]>>,
Expand Down
7 changes: 7 additions & 0 deletions boa_ast/src/expression/literal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ pub enum Literal {
/// [spec]: https://tc39.es/ecma262/#sec-null-value
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/null
Null,

/// This represents the JavaScript `undefined` value, it does not reference the `undefined` global variable,
/// it will directly evaluate to `undefined`.
///
/// NOTE: This is used for optimizations.
Undefined,
}

impl From<Sym> for Literal {
Expand Down Expand Up @@ -173,6 +179,7 @@ impl ToInternedString for Literal {
Self::BigInt(ref num) => num.to_string(),
Self::Bool(v) => v.to_string(),
Self::Null => "null".to_owned(),
Self::Undefined => "undefined".to_owned(),
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions boa_ast/src/expression/operator/binary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ impl Binary {
pub const fn rhs(&self) -> &Expression {
&self.rhs
}

/// Gets the left hand side of the binary operation.
#[inline]
#[must_use]
pub fn lhs_mut(&mut self) -> &mut Expression {
&mut self.lhs
}

/// Gets the right hand side of the binary operation.
#[inline]
#[must_use]
pub fn rhs_mut(&mut self) -> &mut Expression {
&mut self.rhs
}
}

impl ToInternedString for Binary {
Expand Down
7 changes: 7 additions & 0 deletions boa_ast/src/expression/operator/unary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ impl Unary {
pub fn target(&self) -> &Expression {
self.target.as_ref()
}

/// Gets the target of this unary operator.
#[inline]
#[must_use]
pub fn target_mut(&mut self) -> &mut Expression {
self.target.as_mut()
}
}

impl ToInternedString for Unary {
Expand Down
60 changes: 42 additions & 18 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 All @@ -89,6 +90,7 @@ const READLINE_COLOR: Color = Color::Cyan;
// https://docs.rs/structopt/0.3.11/structopt/#type-magic
#[derive(Debug, Parser)]
#[command(author, version, about, name = "boa")]
#[allow(clippy::struct_excessive_bools)] // NOTE: Allow having more than 3 bools in struct
struct Opt {
/// The JavaScript file(s) to be evaluated.
#[arg(name = "FILE", value_hint = ValueHint::FilePath)]
Expand Down Expand Up @@ -118,6 +120,12 @@ struct Opt {
#[arg(long = "vi")]
vi_mode: bool,

#[arg(long, short = 'O', group = "optimizer")]
optimize: bool,

#[arg(long, requires = "optimizer")]
optimizer_statistics: bool,

/// Generate instruction flowgraph. Default is Graphviz.
#[arg(
long,
Expand Down Expand Up @@ -207,7 +215,11 @@ where
S: AsRef<[u8]> + ?Sized,
{
if let Some(ref arg) = args.dump_ast {
let ast = parse_tokens(src, context)?;
let mut ast = parse_tokens(src, context)?;

if args.optimize {
context.optimize_statement_list(&mut ast);
}

match arg {
Some(DumpFormat::Json) => println!(
Expand Down Expand Up @@ -251,31 +263,17 @@ fn generate_flowgraph(
Ok(result)
}

fn main() -> Result<(), io::Error> {
let args = Opt::parse();

let queue = Jobs::default();
let mut context = ContextBuilder::new()
.job_queue(&queue)
.build()
.expect("cannot fail with default global object");

// Strict mode
context.strict(args.strict);

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

fn evaluate_files(args: &Opt, context: &mut Context<'_>) -> Result<(), io::Error> {
for file in &args.files {
let buffer = read(file)?;

if args.has_dump_flag() {
if let Err(e) = dump(&buffer, &args, &mut context) {
if let Err(e) = dump(&buffer, args, context) {
eprintln!("{e}");
}
} else if let Some(flowgraph) = args.flowgraph {
match generate_flowgraph(
&mut context,
context,
&buffer,
flowgraph.unwrap_or(FlowgraphFormat::Graphviz),
args.flowgraph_direction,
Expand All @@ -292,6 +290,30 @@ fn main() -> Result<(), io::Error> {
}
}

Ok(())
}

fn main() -> Result<(), io::Error> {
let args = Opt::parse();

let queue = Jobs::default();
let mut context = ContextBuilder::new()
.job_queue(&queue)
.build()
.expect("cannot fail with default global object");

// Strict mode
context.strict(args.strict);

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

// 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()
.keyseq_timeout(1)
Expand Down Expand Up @@ -365,6 +387,8 @@ fn main() -> Result<(), io::Error> {
editor
.save_history(CLI_HISTORY)
.expect("could not save CLI history");
} else {
evaluate_files(&args, &mut context)?;
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions boa_engine/src/bytecompiler/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl ByteCompiler<'_, '_> {
AstLiteral::Bool(true) => self.emit(Opcode::PushTrue, &[]),
AstLiteral::Bool(false) => self.emit(Opcode::PushFalse, &[]),
AstLiteral::Null => self.emit(Opcode::PushNull, &[]),
AstLiteral::Undefined => self.emit(Opcode::PushUndefined, &[]),
}

if !use_expr {
Expand Down
3 changes: 1 addition & 2 deletions boa_engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
}

// Check if the f64 value can fit in an i32.
#[allow(clippy::float_cmp)]
if f64::from(value as i32) == value {
if f64::from(value as i32).to_bits() == value.to_bits() {
self.emit_push_integer(value as i32);
} else {
self.emit_opcode(Opcode::PushRational);
Expand Down
31 changes: 29 additions & 2 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
job::{IdleJobQueue, JobQueue, NativeJob},
native_function::NativeFunction,
object::{FunctionObjectBuilder, GlobalPropertyMap, JsObject},
optimizer::{Optimizer, OptimizerOptions, OptimizerStatistics},
property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm,
vm::{CallFrame, CodeBlock, Vm},
Expand Down Expand Up @@ -101,6 +102,8 @@ pub struct Context<'host> {
host_hooks: &'host dyn HostHooks,

job_queue: &'host dyn JobQueue,

optimizer_options: OptimizerOptions,
}

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

#[cfg(feature = "intl")]
debug.field("icu", &self.icu);
Expand Down Expand Up @@ -202,6 +206,15 @@ impl Context<'_> {
result
}

/// Applies optimizations to the [`StatementList`] inplace.
pub fn optimize_statement_list(
&mut self,
statement_list: &mut StatementList,
) -> OptimizerStatistics {
let mut optimizer = Optimizer::new(self);
optimizer.apply(statement_list)
}

/// Parse the given source script.
pub fn parse_script<R: Read>(
&mut self,
Expand All @@ -212,7 +225,11 @@ impl Context<'_> {
if self.strict {
parser.set_strict();
}
parser.parse_script(&mut self.interner)
let mut result = parser.parse_script(&mut self.interner)?;
if !self.optimizer_options().is_empty() {
self.optimize_statement_list(&mut result);
}
Ok(result)
}

/// Parse the given source script.
Expand Down Expand Up @@ -426,6 +443,15 @@ impl Context<'_> {
self.vm.trace = trace;
}

/// Get optimizer options.
pub const fn optimizer_options(&self) -> OptimizerOptions {
self.optimizer_options
}
/// 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.
pub fn strict(&mut self, strict: bool) {
self.strict = strict;
Expand Down Expand Up @@ -642,6 +668,7 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> {
kept_alive: Vec::new(),
host_hooks,
job_queue: self.job_queue.unwrap_or(&IdleJobQueue),
optimizer_options: OptimizerOptions::empty(),
};

builtins::set_default_global_bindings(&mut context)?;
Expand Down
2 changes: 2 additions & 0 deletions boa_engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub mod symbol;
pub mod value;
pub mod vm;

pub mod optimizer;

#[cfg(feature = "console")]
pub mod console;

Expand Down
Loading

0 comments on commit ccf84f4

Please sign in to comment.