Skip to content

Commit

Permalink
Eliminate unneeded environemts
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Aug 1, 2023
1 parent ed60d63 commit 8f055b5
Show file tree
Hide file tree
Showing 17 changed files with 416 additions and 141 deletions.
7 changes: 7 additions & 0 deletions boa_ast/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2215,4 +2215,11 @@ impl<'ast> Visitor<'ast> for CanOptimizeLocalVariables {
fn visit_class(&mut self, _node: &'ast Class) -> ControlFlow<Self::BreakTy> {
ControlFlow::Break(())
}

fn visit_pattern(
&mut self,
_node: &'ast crate::pattern::Pattern,
) -> ControlFlow<Self::BreakTy> {
ControlFlow::Break(())
}
}
84 changes: 66 additions & 18 deletions boa_engine/src/bytecompiler/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use boa_interner::Sym;
#[cfg(feature = "annex-b")]
use boa_ast::operations::annex_b_function_declarations_names;

use super::EnvironmentAccess;

impl ByteCompiler<'_, '_> {
/// `GlobalDeclarationInstantiation ( script, env )`
///
Expand Down Expand Up @@ -568,9 +570,15 @@ impl ByteCompiler<'_, '_> {

// ii. Perform ! varEnv.InitializeBinding(F, undefined).
let binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::SetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}
}
}

Expand Down Expand Up @@ -737,10 +745,14 @@ impl ByteCompiler<'_, '_> {
if binding_exists {
// 1. Perform ! varEnv.SetMutableBinding(fn, fo, false).
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[index]);
}
Ok(binding) => match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::SetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::SetName, &[index]);
}
},
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[index]);
Expand All @@ -755,8 +767,12 @@ impl ByteCompiler<'_, '_> {
// 3. Perform ! varEnv.InitializeBinding(fn, fo).
self.create_mutable_binding(name, !strict);
let binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => self.emit(Opcode::SetLocal, &[index]),
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}
}
}
}
Expand All @@ -780,9 +796,13 @@ impl ByteCompiler<'_, '_> {
// 3. Perform ! varEnv.InitializeBinding(vn, undefined).
self.create_mutable_binding(name, !strict);
let binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => self.emit(Opcode::SetLocal, &[index]),
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}
}
}
}
Expand Down Expand Up @@ -914,6 +934,7 @@ impl ByteCompiler<'_, '_> {
// NOTE(HalidOdat): Has been moved up, so "arguments" gets registed as
// the first binding in the environment with index 0.
if arguments_object_needed {
let function_environment_index = self.function_environment_index.take();
// Note: This happens at runtime.
// a. If strict is true or simpleParameterList is false, then
// i. Let ao be CreateUnmappedArgumentsObject(argumentsList).
Expand All @@ -936,6 +957,13 @@ impl ByteCompiler<'_, '_> {
self.create_mutable_binding(arguments, false);
}

if self.can_optimize_local_variables {
let binding = self.get_binding_value(arguments);
self.get_or_insert_binding(binding);
}

self.function_environment_index = function_environment_index;

self.code_block_flags |= CodeBlockFlags::NEEDS_ARGUMENTS_OBJECT;
}

Expand Down Expand Up @@ -1051,15 +1079,25 @@ impl ByteCompiler<'_, '_> {
else {
// a. Let initialValue be ! env.GetBindingValue(n, false).
let binding = self.get_binding_value(n);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetName, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::GetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::GetName, &[index]);
}
}
}

// 5. Perform ! varEnv.InitializeBinding(n, initialValue).
let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => self.emit(Opcode::SetLocal, &[index]),
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}

// 6. NOTE: A var with the same name as a formal parameter initially has
// the same value as the corresponding initialized parameter.
Expand All @@ -1084,9 +1122,13 @@ impl ByteCompiler<'_, '_> {

// 3. Perform ! env.InitializeBinding(n, undefined).
let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => self.emit(Opcode::SetLocal, &[index]),
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}
}
}

Expand Down Expand Up @@ -1116,9 +1158,15 @@ impl ByteCompiler<'_, '_> {

// b. Perform ! varEnv.InitializeBinding(F, undefined).
let binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::SetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::DefInitVar, &[index]);
}
}

// c. Append F to instantiatedVarNames.
instantiated_var_names.push(f);
Expand Down
36 changes: 24 additions & 12 deletions boa_engine/src/bytecompiler/expression/assign.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
bytecompiler::{Access, ByteCompiler},
bytecompiler::{Access, ByteCompiler, EnvironmentAccess},
environments::BindingLocatorError,
vm::{BindingOpcode, Opcode},
};
Expand Down Expand Up @@ -56,14 +56,22 @@ impl ByteCompiler<'_, '_> {
match access {
Access::Variable { name } => {
let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
let lex = self.current_environment.is_lex_binding(name);

if lex {
self.emit(Opcode::GetName, &[index]);
} else {
self.emit(Opcode::GetNameAndLocator, &[index]);
}
let is_fast = match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::GetLocal, &[index]);
true
}
EnvironmentAccess::Slow { index } => {
if lex {
self.emit(Opcode::GetName, &[index]);
} else {
self.emit(Opcode::GetNameAndLocator, &[index]);
}
false
}
};

if short_circuit {
early_exit = Some(self.emit_opcode_with_operand(opcode));
Expand All @@ -75,12 +83,16 @@ impl ByteCompiler<'_, '_> {
if use_expr {
self.emit_opcode(Opcode::Dup);
}
if lex {
if lex || is_fast {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[index]);
}
Ok(binding) => match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::SetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::SetName, &[index]);
}
},
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[index]);
Expand Down
12 changes: 9 additions & 3 deletions boa_engine/src/bytecompiler/expression/unary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use boa_ast::{
};

use crate::{
bytecompiler::{Access, ByteCompiler},
bytecompiler::{Access, ByteCompiler, EnvironmentAccess},
vm::Opcode,
};

Expand All @@ -28,8 +28,14 @@ impl ByteCompiler<'_, '_> {
match unary.target().flatten() {
Expression::Identifier(identifier) => {
let binding = self.get_binding_value(*identifier);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetNameOrUndefined, &[index]);
match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::GetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::GetNameOrUndefined, &[index]);
}
}
}
expr => self.compile_expr(expr, true),
}
Expand Down
36 changes: 24 additions & 12 deletions boa_engine/src/bytecompiler/expression/update.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
bytecompiler::{Access, ByteCompiler},
bytecompiler::{Access, ByteCompiler, EnvironmentAccess},
environments::BindingLocatorError,
vm::Opcode,
};
Expand All @@ -24,14 +24,22 @@ impl ByteCompiler<'_, '_> {
match Access::from_update_target(update.target()) {
Access::Variable { name } => {
let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
let lex = self.current_environment.is_lex_binding(name);

if lex {
self.emit(Opcode::GetName, &[index]);
} else {
self.emit(Opcode::GetNameAndLocator, &[index]);
}
let is_fast = match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::GetLocal, &[index]);
true
}
EnvironmentAccess::Slow { index } => {
if lex {
self.emit(Opcode::GetName, &[index]);
} else {
self.emit(Opcode::GetNameAndLocator, &[index]);
}
false
}
};

self.emit_opcode(opcode);
if post {
Expand All @@ -40,12 +48,16 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup);
}

if lex {
if lex || is_fast {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[index]);
}
Ok(binding) => match self.get_or_insert_binding(binding) {
EnvironmentAccess::Fast { index } => {
self.emit(Opcode::SetLocal, &[index]);
}
EnvironmentAccess::Slow { index } => {
self.emit(Opcode::SetName, &[index]);
}
},
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[index]);
Expand Down
10 changes: 8 additions & 2 deletions boa_engine/src/bytecompiler/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ impl FunctionCompiler {
// Function environment
compiler.push_compile_environment(true);

compiler.function_environment_index =
Some(compiler.current_environment.environment_index());

// Taken from:
// - 15.9.3 Runtime Semantics: EvaluateAsyncConciseBody: <https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncconcisebody>
// - 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody: <https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncfunctionbody>
Expand Down Expand Up @@ -153,8 +156,8 @@ impl FunctionCompiler {

let can_optimize_params = can_optimize_local_variables(parameters);
let can_optimize_body = can_optimize_local_variables(body);
println!("Can optimize params: {can_optimize_params}");
println!("Can optimize body: {can_optimize_body}");
// println!("Can optimize params: {can_optimize_params}");
// println!("Can optimize body: {can_optimize_body}");

let can_optimize = can_optimize_params
&& can_optimize_body
Expand All @@ -164,6 +167,9 @@ impl FunctionCompiler {
&& parameters.is_simple();
println!("Can optimize function: {can_optimize}");

compiler.can_optimize_local_variables =
can_optimize && compiler.function_environment_index.is_some();

let (env_label, additional_env) = compiler.function_declaration_instantiation(
body,
parameters,
Expand Down
4 changes: 4 additions & 0 deletions boa_engine/src/bytecompiler/jump_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ impl JumpRecord {
return;
}
JumpRecordAction::PopEnvironments { count } => {
if compiler.can_optimize_local_variables {
continue;
}

for _ in 0..count {
compiler.emit_opcode(Opcode::PopEnvironment);
}
Expand Down
Loading

0 comments on commit 8f055b5

Please sign in to comment.