Skip to content

Commit

Permalink
Refactor compile time environment handling (#3365)
Browse files Browse the repository at this point in the history
* Refactor compile time environment handling

* Apply review

* Apply review
  • Loading branch information
raskad authored Oct 10, 2023
1 parent 68b023a commit f654ad1
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 609 deletions.
22 changes: 13 additions & 9 deletions boa_engine/src/builtins/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,31 +224,35 @@ impl Eval {
}
});

let var_environment = context.vm.environments.outer_function_environment();
let mut var_env = var_environment.compile_env();

let mut compiler = ByteCompiler::new(
Sym::MAIN,
body.strict(),
false,
var_env.clone(),
context.vm.environments.current_compile_environment(),
context,
);

let env_index = compiler.push_compile_environment(strict);
compiler.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
let lex_env = compiler.lexical_environment.clone();
if strict {
var_env = lex_env.clone();
compiler.variable_environment = lex_env.clone();
}

compiler.eval_declaration_instantiation(&body, strict)?;
compiler.eval_declaration_instantiation(&body, strict, &var_env, &lex_env)?;
compiler.compile_statement_list(body.statements(), true, false);

compiler.pop_compile_environment();
compiler.emit_opcode(Opcode::PopEnvironment);

let code_block = Gc::new(compiler.finish());

// Indirect calls don't need extensions, because a non-strict indirect call modifies only
// the global object.
// Strict direct calls also don't need extensions, since all strict eval calls push a new
// Strict calls don't need extensions, since all strict eval calls push a new
// function environment before evaluating.
if direct && !strict {
context.vm.environments.extend_outer_function_environment();
if !strict {
var_environment.extend_from_compile();
}

let env_fp = context.vm.environments.len() as u32;
Expand Down
3 changes: 3 additions & 0 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ impl BuiltInFunctionObject {
&parameters,
&body,
context.realm().environment().compile_env(),
context.realm().environment().compile_env(),
context,
);

Expand All @@ -659,6 +660,7 @@ impl BuiltInFunctionObject {
&FormalParameterList::default(),
&FunctionBody::default(),
context.realm().environment().compile_env(),
context.realm().environment().compile_env(),
context,
);

Expand All @@ -680,6 +682,7 @@ impl BuiltInFunctionObject {
&FormalParameterList::default(),
&FunctionBody::default(),
context.realm().environment().compile_env(),
context.realm().environment().compile_env(),
context,
);

Expand Down
1 change: 1 addition & 0 deletions boa_engine/src/builtins/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ impl Json {
script.strict(),
true,
context.realm().environment().compile_env(),
context.realm().environment().compile_env(),
context,
);
compiler.compile_statement_list(script.statements(), true, false);
Expand Down
60 changes: 27 additions & 33 deletions boa_engine/src/bytecompiler/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,37 @@ 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 = match class.name() {
let old_lex_env = match class.name() {
Some(name) if class.has_binding_identifier() => {
let old_lex_env = self.lexical_environment.clone();
let env_index = self.push_compile_environment(false);
self.create_immutable_binding(name, true);
self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index);
true
self.lexical_environment
.create_immutable_binding(name, true);
Some(old_lex_env)
}
_ => false,
_ => None,
};

let mut compiler = ByteCompiler::new(
class_name,
true,
self.json_parse,
self.current_environment.clone(),
self.variable_environment.clone(),
self.lexical_environment.clone(),
self.context,
);

compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR;

// Function environment
let _ = compiler.push_compile_environment(true);

if let Some(expr) = class.constructor() {
compiler.length = expr.parameters().length();
compiler.params = expr.parameters().clone();

let (env_label, _) = compiler.function_declaration_instantiation(
compiler.function_declaration_instantiation(
expr.body(),
expr.parameters(),
false,
Expand All @@ -61,23 +66,14 @@ impl ByteCompiler<'_, '_> {

compiler.compile_statement_list(expr.body().statements(), false, false);

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() {
compiler.emit_opcode(Opcode::SuperCallDerived);
} else {
if class.super_ref().is_some() {
compiler.emit_opcode(Opcode::SuperCallDerived);
} else {
compiler.emit_opcode(Opcode::RestParameterPop);
compiler.emit_opcode(Opcode::PushUndefined);
}
compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR;
compiler.emit_opcode(Opcode::RestParameterPop);
compiler.emit_opcode(Opcode::PushUndefined);
}
compiler.emit_opcode(Opcode::SetReturnValue);
compiler.pop_compile_environment();

let code = Gc::new(compiler.finish());
let index = self.functions.len() as u32;
Expand Down Expand Up @@ -117,9 +113,9 @@ impl ByteCompiler<'_, '_> {
let mut static_elements = Vec::new();
let mut static_field_name_count = 0;

if class_env {
if old_lex_env.is_some() {
self.emit_opcode(Opcode::Dup);
self.emit_binding(BindingOpcode::InitConst, class_name.into());
self.emit_binding(BindingOpcode::InitLexical, class_name.into());
}

// TODO: set function name for getter and setters
Expand Down Expand Up @@ -277,7 +273,8 @@ impl ByteCompiler<'_, '_> {
Sym::EMPTY_STRING,
true,
self.json_parse,
self.current_environment.clone(),
self.variable_environment.clone(),
self.lexical_environment.clone(),
self.context,
);

Expand All @@ -290,8 +287,6 @@ impl ByteCompiler<'_, '_> {
}
field_compiler.emit_opcode(Opcode::SetReturnValue);

field_compiler.pop_compile_environment();

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;

let code = field_compiler.finish();
Expand All @@ -311,7 +306,8 @@ impl ByteCompiler<'_, '_> {
class_name,
true,
self.json_parse,
self.current_environment.clone(),
self.variable_environment.clone(),
self.lexical_environment.clone(),
self.context,
);
let _ = field_compiler.push_compile_environment(true);
Expand All @@ -320,8 +316,6 @@ impl ByteCompiler<'_, '_> {
} else {
field_compiler.emit_opcode(Opcode::PushUndefined);
}
field_compiler.pop_compile_environment();

field_compiler.emit_opcode(Opcode::SetReturnValue);

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
Expand Down Expand Up @@ -355,7 +349,8 @@ impl ByteCompiler<'_, '_> {
class_name,
true,
self.json_parse,
self.current_environment.clone(),
self.variable_environment.clone(),
self.lexical_environment.clone(),
self.context,
);
let _ = field_compiler.push_compile_environment(true);
Expand All @@ -366,8 +361,6 @@ impl ByteCompiler<'_, '_> {
}
field_compiler.emit_opcode(Opcode::SetReturnValue);

field_compiler.pop_compile_environment();

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;

let code = field_compiler.finish();
Expand All @@ -390,7 +383,8 @@ impl ByteCompiler<'_, '_> {
Sym::EMPTY_STRING,
true,
false,
self.current_environment.clone(),
self.variable_environment.clone(),
self.lexical_environment.clone(),
self.context,
);
let _ = compiler.push_compile_environment(true);
Expand All @@ -404,7 +398,6 @@ impl ByteCompiler<'_, '_> {
);

compiler.compile_statement_list(body.statements(), false, false);
compiler.pop_compile_environment();

let code = Gc::new(compiler.finish());
static_elements.push(StaticElement::StaticBlock(code));
Expand Down Expand Up @@ -589,8 +582,9 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::Pop);

if class_env {
if let Some(old_lex_env) = old_lex_env {
self.pop_compile_environment();
self.lexical_environment = old_lex_env;
self.emit_opcode(Opcode::PopEnvironment);
}

Expand Down
Loading

0 comments on commit f654ad1

Please sign in to comment.