Browse Source

Make environments opcodes use varying operands (#3340)

pull/3350/head
Haled Odat 1 year ago committed by GitHub
parent
commit
a51581bf94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      boa_engine/src/builtins/eval/mod.rs
  2. 37
      boa_engine/src/bytecompiler/class.rs
  3. 13
      boa_engine/src/bytecompiler/declarations.rs
  4. 17
      boa_engine/src/bytecompiler/env.rs
  5. 9
      boa_engine/src/bytecompiler/function.rs
  6. 8
      boa_engine/src/bytecompiler/statement/block.rs
  7. 74
      boa_engine/src/bytecompiler/statement/loop.rs
  8. 7
      boa_engine/src/bytecompiler/statement/switch.rs
  9. 7
      boa_engine/src/bytecompiler/statement/try.rs
  10. 3
      boa_engine/src/bytecompiler/statement/with.rs
  11. 14
      boa_engine/src/vm/code_block.rs
  12. 4
      boa_engine/src/vm/opcode/mod.rs
  13. 32
      boa_engine/src/vm/opcode/push/environment.rs

9
boa_engine/src/builtins/eval/mod.rs

@ -232,16 +232,13 @@ impl Eval {
context,
);
compiler.push_compile_environment(strict);
let push_env = compiler.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = compiler.push_compile_environment(strict);
compiler.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
compiler.eval_declaration_instantiation(&body, strict)?;
compiler.compile_statement_list(body.statements(), true, false);
let env_index = compiler.pop_compile_environment();
compiler.patch_jump_with_target(push_env, env_index);
compiler.pop_compile_environment();
compiler.emit_opcode(Opcode::PopEnvironment);
let code_block = Gc::new(compiler.finish());

37
boa_engine/src/bytecompiler/class.rs

@ -26,13 +26,14 @@ impl ByteCompiler<'_, '_> {
pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) {
let class_name = class.name().map_or(Sym::EMPTY_STRING, Identifier::sym);
let class_env: Option<super::Label> = match class.name() {
let class_env = match class.name() {
Some(name) if class.has_binding_identifier() => {
self.push_compile_environment(false);
let env_index = self.push_compile_environment(false);
self.create_immutable_binding(name, true);
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment))
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
true
}
_ => None,
_ => false,
};
let mut compiler = ByteCompiler::new(
@ -43,7 +44,8 @@ impl ByteCompiler<'_, '_> {
self.context,
);
compiler.push_compile_environment(true);
// Function environment
let _ = compiler.push_compile_environment(true);
if let Some(expr) = class.constructor() {
compiler.length = expr.parameters().length();
@ -59,15 +61,11 @@ impl ByteCompiler<'_, '_> {
compiler.compile_statement_list(expr.body().statements(), false, false);
let env_index = compiler.pop_compile_environment();
if let Some(env_label) = env_label {
compiler.patch_jump_with_target(env_label, env_index);
if env_label {
compiler.pop_compile_environment();
} else {
compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR;
}
compiler.emit_opcode(Opcode::PushUndefined);
} else {
if class.super_ref().is_some() {
@ -76,10 +74,10 @@ impl ByteCompiler<'_, '_> {
compiler.emit_opcode(Opcode::RestParameterPop);
compiler.emit_opcode(Opcode::PushUndefined);
}
compiler.pop_compile_environment();
compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR;
}
compiler.emit_opcode(Opcode::SetReturnValue);
compiler.pop_compile_environment();
let code = Gc::new(compiler.finish());
let index = self.functions.len() as u32;
@ -119,7 +117,7 @@ impl ByteCompiler<'_, '_> {
let mut static_elements = Vec::new();
let mut static_field_name_count = 0;
if class_env.is_some() {
if class_env {
self.emit_opcode(Opcode::Dup);
self.emit_binding(BindingOpcode::InitConst, class_name.into());
}
@ -282,7 +280,9 @@ impl ByteCompiler<'_, '_> {
self.current_environment.clone(),
self.context,
);
field_compiler.push_compile_environment(true);
// Function environment
let _ = field_compiler.push_compile_environment(true);
if let Some(node) = field {
field_compiler.compile_expr(node, true);
} else {
@ -314,7 +314,7 @@ impl ByteCompiler<'_, '_> {
self.current_environment.clone(),
self.context,
);
field_compiler.push_compile_environment(true);
let _ = field_compiler.push_compile_environment(true);
if let Some(node) = field {
field_compiler.compile_expr(node, true);
} else {
@ -358,7 +358,7 @@ impl ByteCompiler<'_, '_> {
self.current_environment.clone(),
self.context,
);
field_compiler.push_compile_environment(true);
let _ = field_compiler.push_compile_environment(true);
if let Some(node) = field {
field_compiler.compile_expr(node, true);
} else {
@ -393,7 +393,7 @@ impl ByteCompiler<'_, '_> {
self.current_environment.clone(),
self.context,
);
compiler.push_compile_environment(true);
let _ = compiler.push_compile_environment(true);
compiler.function_declaration_instantiation(
body,
@ -589,9 +589,8 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::Pop);
if let Some(class_env) = class_env {
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(class_env, env_index);
if class_env {
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}

13
boa_engine/src/bytecompiler/declarations.rs

@ -1,5 +1,5 @@
use crate::{
bytecompiler::{ByteCompiler, FunctionCompiler, FunctionSpec, Label, NodeKind},
bytecompiler::{ByteCompiler, FunctionCompiler, FunctionSpec, NodeKind},
environments::BindingLocatorError,
vm::{
create_function_object_fast, create_generator_function_object, BindingOpcode,
@ -809,8 +809,8 @@ impl ByteCompiler<'_, '_> {
arrow: bool,
strict: bool,
generator: bool,
) -> (Option<Label>, bool) {
let mut env_label = None;
) -> (bool, bool) {
let mut env_label = false;
let mut additional_env = false;
// 1. Let calleeContext be the running execution context.
@ -910,7 +910,7 @@ impl ByteCompiler<'_, '_> {
// c. Let env be NewDeclarativeEnvironment(calleeEnv).
// d. Assert: The VariableEnvironment of calleeContext is calleeEnv.
// e. Set the LexicalEnvironment of calleeContext to env.
self.push_compile_environment(false);
let _ = self.push_compile_environment(false);
additional_env = true;
}
@ -1030,8 +1030,9 @@ impl ByteCompiler<'_, '_> {
// visibility of declarations in the function body.
// b. Let varEnv be NewDeclarativeEnvironment(env).
// c. Set the VariableEnvironment of calleeContext to varEnv.
self.push_compile_environment(false);
env_label = Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment));
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
env_label = true;
// d. Let instantiatedVarNames be a new empty List.
let mut instantiated_var_names = Vec::new();

17
boa_engine/src/bytecompiler/env.rs

@ -6,29 +6,32 @@ use boa_ast::expression::Identifier;
impl ByteCompiler<'_, '_> {
/// Push either a new declarative or function environment on the compile time environment stack.
pub(crate) fn push_compile_environment(&mut self, function_scope: bool) {
#[must_use]
pub(crate) fn push_compile_environment(&mut self, function_scope: bool) -> u32 {
self.current_open_environments_count += 1;
self.current_environment = Rc::new(CompileTimeEnvironment::new(
self.current_environment.clone(),
function_scope,
));
let index = self.compile_environments.len() as u32;
self.compile_environments
.push(self.current_environment.clone());
index
}
/// Pops the top compile time environment and returns its index in the compile time environments array.
#[track_caller]
pub(crate) fn pop_compile_environment(&mut self) -> u32 {
pub(crate) fn pop_compile_environment(&mut self) {
self.current_open_environments_count -= 1;
let index = self.compile_environments.len() as u32;
self.compile_environments
.push(self.current_environment.clone());
let outer = self
.current_environment
.outer()
.expect("cannot pop the global environment");
self.current_environment = outer;
index
}
/// Get the binding locator of the binding at bytecode compile time.

9
boa_engine/src/bytecompiler/function.rs

@ -100,12 +100,12 @@ impl FunctionCompiler {
if let Some(binding_identifier) = self.binding_identifier {
compiler.code_block_flags |= CodeBlockFlags::HAS_BINDING_IDENTIFIER;
compiler.push_compile_environment(false);
let _ = compiler.push_compile_environment(false);
compiler.create_immutable_binding(binding_identifier.into(), self.strict);
}
// Function environment
compiler.push_compile_environment(true);
let _ = compiler.push_compile_environment(true);
// Taken from:
// - 15.9.3 Runtime Semantics: EvaluateAsyncConciseBody: <https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncconcisebody>
@ -155,9 +155,8 @@ impl FunctionCompiler {
compiler.compile_statement_list(body.statements(), false, false);
if let Some(env_labels) = env_label {
let env_index = compiler.pop_compile_environment();
compiler.patch_jump_with_target(env_labels, env_index);
if env_label {
compiler.pop_compile_environment();
}
if additional_env {

8
boa_engine/src/bytecompiler/statement/block.rs

@ -4,15 +4,13 @@ use boa_ast::statement::Block;
impl ByteCompiler<'_, '_> {
/// Compile a [`Block`] `boa_ast` node
pub(crate) fn compile_block(&mut self, block: &Block, use_expr: bool) {
self.push_compile_environment(false);
let push_env = self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
self.block_declaration_instantiation(block);
self.compile_statement_list(block.statement_list(), use_expr, true);
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(push_env, env_index);
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
}

74
boa_engine/src/bytecompiler/statement/loop.rs

@ -22,8 +22,7 @@ impl ByteCompiler<'_, '_> {
use_expr: bool,
) {
let mut let_binding_indices = None;
let mut env_labels = None;
let mut iteration_env_labels = None;
let mut has_lexical_environment_binding = false;
if let Some(init) = for_loop.init() {
match init {
@ -32,9 +31,9 @@ impl ByteCompiler<'_, '_> {
self.compile_var_decl(decl);
}
ForLoopInitializer::Lexical(decl) => {
self.push_compile_environment(false);
env_labels =
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment));
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
has_lexical_environment_binding = true;
let names = bound_names(decl);
if decl.is_const() {
@ -49,7 +48,7 @@ impl ByteCompiler<'_, '_> {
let index = self.get_or_insert_binding(binding);
indices.push(index);
}
let_binding_indices = Some(indices);
let_binding_indices = Some((indices, env_index));
}
self.compile_lexical_decl(decl);
}
@ -67,13 +66,14 @@ impl ByteCompiler<'_, '_> {
.expect("jump_control must exist as it was just pushed")
.set_start_address(start_address);
if let Some(let_binding_indices) = let_binding_indices {
for index in &let_binding_indices {
if let Some((let_binding_indices, env_index)) = &let_binding_indices {
for index in let_binding_indices {
self.emit_with_varying_operand(Opcode::GetName, *index);
}
self.emit_opcode(Opcode::PopEnvironment);
iteration_env_labels =
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment));
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, *env_index);
for index in let_binding_indices.iter().rev() {
self.emit_with_varying_operand(Opcode::PutLexicalValue, *index);
}
@ -100,16 +100,10 @@ impl ByteCompiler<'_, '_> {
self.patch_jump(exit);
self.pop_loop_control_info();
if env_labels.is_some() {
self.emit_opcode(Opcode::PopEnvironment);
}
if let Some(env_labels) = env_labels {
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(env_labels, env_index);
if let Some(iteration_env_labels) = iteration_env_labels {
self.patch_jump_with_target(iteration_env_labels, env_index);
}
if has_lexical_environment_binding {
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
}
@ -136,16 +130,15 @@ impl ByteCompiler<'_, '_> {
if initializer_bound_names.is_empty() {
self.compile_expr(for_in_loop.target(), true);
} else {
self.push_compile_environment(false);
let push_env = self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
for name in &initializer_bound_names {
self.create_mutable_binding(*name, false);
}
self.compile_expr(for_in_loop.target(), true);
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(push_env, env_index);
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
@ -162,12 +155,10 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::IteratorValue);
let iteration_environment = if initializer_bound_names.is_empty() {
None
} else {
self.push_compile_environment(false);
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment))
};
if !initializer_bound_names.is_empty() {
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
}
match for_in_loop.initializer() {
IterableLoopInitializer::Identifier(ident) => {
@ -219,9 +210,8 @@ impl ByteCompiler<'_, '_> {
self.compile_stmt(for_in_loop.body(), use_expr, true);
if let Some(iteration_environment) = iteration_environment {
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(iteration_environment, env_index);
if !initializer_bound_names.is_empty() {
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
@ -252,16 +242,15 @@ impl ByteCompiler<'_, '_> {
if initializer_bound_names.is_empty() {
self.compile_expr(for_of_loop.iterable(), true);
} else {
self.push_compile_environment(false);
let push_env = self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
for name in &initializer_bound_names {
self.create_mutable_binding(*name, false);
}
self.compile_expr(for_of_loop.iterable(), true);
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(push_env, env_index);
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
@ -290,11 +279,9 @@ impl ByteCompiler<'_, '_> {
let exit = self.jump_if_true();
self.emit_opcode(Opcode::IteratorValue);
let iteration_environment = if initializer_bound_names.is_empty() {
None
} else {
self.push_compile_environment(false);
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment))
if !initializer_bound_names.is_empty() {
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
};
let mut handler_index = None;
@ -388,9 +375,8 @@ impl ByteCompiler<'_, '_> {
self.compile_stmt(for_of_loop.body(), use_expr, true);
if let Some(iteration_environment) = iteration_environment {
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(iteration_environment, env_index);
if !initializer_bound_names.is_empty() {
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}

7
boa_engine/src/bytecompiler/statement/switch.rs

@ -6,8 +6,8 @@ impl ByteCompiler<'_, '_> {
pub(crate) fn compile_switch(&mut self, switch: &Switch, use_expr: bool) {
self.compile_expr(switch.val(), true);
self.push_compile_environment(false);
let push_env = self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
self.block_declaration_instantiation(switch);
@ -50,8 +50,7 @@ impl ByteCompiler<'_, '_> {
self.pop_switch_control_info();
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(push_env, env_index);
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}
}

7
boa_engine/src/bytecompiler/statement/try.rs

@ -111,8 +111,8 @@ impl ByteCompiler<'_, '_> {
pub(crate) fn compile_catch_stmt(&mut self, catch: &Catch, _has_finally: bool, use_expr: bool) {
// stack: exception
self.push_compile_environment(false);
let push_env = self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment);
let env_index = self.push_compile_environment(false);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
if let Some(binding) = catch.parameter() {
match binding {
@ -133,8 +133,7 @@ impl ByteCompiler<'_, '_> {
self.compile_catch_finally_block(catch.block(), use_expr);
let env_index = self.pop_compile_environment();
self.patch_jump_with_target(push_env, env_index);
self.pop_compile_environment();
self.emit_opcode(Opcode::PopEnvironment);
}

3
boa_engine/src/bytecompiler/statement/with.rs

@ -5,7 +5,8 @@ impl ByteCompiler<'_, '_> {
/// Compile a [`With`] `boa_ast` node
pub(crate) fn compile_with(&mut self, with: &With, use_expr: bool) {
self.compile_expr(with.expression(), true);
self.push_compile_environment(false);
let _ = self.push_compile_environment(false);
self.emit_opcode(Opcode::PushObjectEnvironment);
self.compile_stmt(with.statement(), use_expr, true);

14
boa_engine/src/vm/code_block.rs

@ -363,7 +363,7 @@ impl CodeBlock {
| Instruction::ConcatToString { value_count: value } => value.value().to_string(),
Instruction::PushDeclarativeEnvironment {
compile_environments_index,
} => compile_environments_index.to_string(),
} => compile_environments_index.value().to_string(),
Instruction::CopyDataProperties {
excluded_key_count: value1,
excluded_key_count_computed: value2,
@ -1062,7 +1062,7 @@ impl JsObject {
let env_fp = context.vm.environments.len() as u32;
let mut last_env = code.compile_environments.len() - 1;
let mut last_env = 0;
if code.has_binding_identifier() {
let index = context
@ -1073,7 +1073,7 @@ impl JsObject {
.vm
.environments
.put_lexical_value(index, 0, self.clone().into());
last_env -= 1;
last_env += 1;
}
context.vm.environments.push_function(
@ -1082,7 +1082,7 @@ impl JsObject {
);
if code.has_parameters_env_bindings() {
last_env -= 1;
last_env += 1;
context
.vm
.environments
@ -1204,7 +1204,7 @@ impl JsObject {
let new_target = this_target.as_object().expect("must be object");
let mut last_env = code.compile_environments.len() - 1;
let mut last_env = 0;
if code.has_binding_identifier() {
let index = context
@ -1215,7 +1215,7 @@ impl JsObject {
.vm
.environments
.put_lexical_value(index, 0, self.clone().into());
last_env -= 1;
last_env += 1;
}
context.vm.environments.push_function(
@ -1232,7 +1232,7 @@ impl JsObject {
let environment = context.vm.environments.current();
if code.has_parameters_env_bindings() {
last_env -= 1;
last_env += 1;
context
.vm
.environments

4
boa_engine/src/vm/opcode/mod.rs

@ -1738,10 +1738,10 @@ generate_opcodes! {
/// Push a declarative environment.
///
/// Operands: compile_environments_index: `u32`
/// Operands: compile_environments_index: `VaryingOperand`
///
/// Stack: **=>**
PushDeclarativeEnvironment { compile_environments_index: u32 },
PushDeclarativeEnvironment { compile_environments_index: VaryingOperand },
/// Push an object environment.
///

32
boa_engine/src/vm/opcode/push/environment.rs

@ -12,17 +12,36 @@ use boa_gc::Gc;
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushDeclarativeEnvironment;
impl PushDeclarativeEnvironment {
#[allow(clippy::unnecessary_wraps)]
fn operation(
context: &mut Context<'_>,
compile_environments_index: usize,
) -> JsResult<CompletionType> {
let compile_environment =
context.vm.frame().code_block.compile_environments[compile_environments_index].clone();
context.vm.environments.push_lexical(compile_environment);
Ok(CompletionType::Normal)
}
}
impl Operation for PushDeclarativeEnvironment {
const NAME: &'static str = "PushDeclarativeEnvironment";
const INSTRUCTION: &'static str = "INST - PushDeclarativeEnvironment";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let compile_environments_index = context.vm.read::<u32>();
let compile_environment = context.vm.frame().code_block.compile_environments
[compile_environments_index as usize]
.clone();
context.vm.environments.push_lexical(compile_environment);
Ok(CompletionType::Normal)
let compile_environments_index = context.vm.read::<u8>() as usize;
Self::operation(context, compile_environments_index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let compile_environments_index = context.vm.read::<u16>() as usize;
Self::operation(context, compile_environments_index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let compile_environments_index = context.vm.read::<u32>() as usize;
Self::operation(context, compile_environments_index)
}
}
@ -98,7 +117,6 @@ impl Operation for PopPrivateEnvironment {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.environments.pop_private();
Ok(CompletionType::Normal)
}
}

Loading…
Cancel
Save