Browse Source

Initialize `var` bindings in runtime environments with `undefined` (#2860)

Currently in draft, because it breaks some of the annexB [`Block-Level Function Declarations Web Legacy Compatibility Semantics`](https://tc39.es/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics) tests.

This Pull Request fixes #2795, fixes #2779 and fixes  #2760.

It changes the following:

- Initialize `var` bindings in runtime environments with `undefined`
- Add a missing environment at class construction time.
pull/2875/head
raskad 2 years ago
parent
commit
7eb2d4e408
  1. 16
      boa_engine/src/bytecompiler/class.rs
  2. 14
      boa_engine/src/environments/compile.rs
  3. 14
      boa_engine/src/environments/runtime.rs

16
boa_engine/src/bytecompiler/class.rs

@ -113,6 +113,15 @@ impl ByteCompiler<'_, '_> {
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
let class_env: Option<(super::Label, super::Label)> = match class.name() {
Some(name) if class.has_binding_identifier() => {
self.push_compile_environment(false);
self.create_immutable_binding(name, true);
Some(self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment))
}
_ => None,
};
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
if let Some(node) = class.super_ref() { if let Some(node) = class.super_ref() {
self.compile_expr(node, true); self.compile_expr(node, true);
@ -544,6 +553,13 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
if let Some(class_env) = class_env {
let env_info = self.pop_compile_environment();
self.patch_jump_with_target(class_env.0, env_info.num_bindings as u32);
self.patch_jump_with_target(class_env.1, env_info.index as u32);
self.emit_opcode(Opcode::PopEnvironment);
}
if !expression { if !expression {
self.emit_binding( self.emit_binding(
BindingOpcode::InitVar, BindingOpcode::InitVar,

14
boa_engine/src/environments/compile.rs

@ -217,4 +217,18 @@ impl CompileTimeEnvironment {
pub(crate) const fn environment_index(&self) -> usize { pub(crate) const fn environment_index(&self) -> usize {
self.environment_index self.environment_index
} }
/// Gets the indices of all `var` bindings in this environment.
pub(crate) fn var_binding_indices(&self) -> Vec<usize> {
self.bindings
.iter()
.filter_map(|(_, binding)| {
if binding.lex {
None
} else {
Some(binding.index)
}
})
.collect()
}
} }

14
boa_engine/src/environments/runtime.rs

@ -481,9 +481,14 @@ impl DeclarativeEnvironmentStack {
let this = this.unwrap_or(JsValue::Null); let this = this.unwrap_or(JsValue::Null);
let mut bindings = vec![None; num_bindings];
for index in compile_environment.borrow().var_binding_indices() {
bindings[index] = Some(JsValue::Undefined);
}
self.stack self.stack
.push(Environment::Declarative(Gc::new(DeclarativeEnvironment { .push(Environment::Declarative(Gc::new(DeclarativeEnvironment {
bindings: GcRefCell::new(vec![None; num_bindings]), bindings: GcRefCell::new(bindings),
compile: compile_environment, compile: compile_environment,
poisoned: Cell::new(poisoned), poisoned: Cell::new(poisoned),
with: Cell::new(with), with: Cell::new(with),
@ -534,9 +539,14 @@ impl DeclarativeEnvironmentStack {
) )
}; };
let mut bindings = vec![None; num_bindings];
for index in compile_environment.borrow().var_binding_indices() {
bindings[index] = Some(JsValue::Undefined);
}
self.stack self.stack
.push(Environment::Declarative(Gc::new(DeclarativeEnvironment { .push(Environment::Declarative(Gc::new(DeclarativeEnvironment {
bindings: GcRefCell::new(vec![None; num_bindings]), bindings: GcRefCell::new(bindings),
compile: compile_environment, compile: compile_environment,
poisoned: Cell::new(poisoned), poisoned: Cell::new(poisoned),
with: Cell::new(with), with: Cell::new(with),

Loading…
Cancel
Save