Bug 1643632 - Use BaseScopeData. r=yulia

Differential Revision: https://phabricator.services.mozilla.com/D78475
This commit is contained in:
Tooru Fujisawa 2020-06-05 10:34:56 +00:00
Родитель 654c97a626
Коммит 2c4cbe5c6f
30 изменённых файлов: 1560 добавлений и 647 удалений

Просмотреть файл

@ -30,7 +30,7 @@ rev = "57a07e89e9ac92756b60b67c4a6ee06975b86288"
[source."https://github.com/mozilla-spidermonkey/jsparagus"]
git = "https://github.com/mozilla-spidermonkey/jsparagus"
replace-with = "vendored-sources"
rev = "a62ca363140935fdd77549b6e17bb9d79f76af75"
rev = "bc612163f379fa9978571981e860ec34b6ad59bd"
[source."https://github.com/kvark/spirv_cross"]
branch = "wgpu3"

16
Cargo.lock сгенерированный
Просмотреть файл

@ -2373,7 +2373,7 @@ dependencies = [
[[package]]
name = "jsparagus"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"jsparagus-ast",
"jsparagus-emitter",
@ -2387,7 +2387,7 @@ dependencies = [
[[package]]
name = "jsparagus-ast"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"bumpalo",
"indexmap",
@ -2398,7 +2398,7 @@ dependencies = [
[[package]]
name = "jsparagus-emitter"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"bumpalo",
"byteorder",
@ -2411,7 +2411,7 @@ dependencies = [
[[package]]
name = "jsparagus-generated-parser"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"bumpalo",
"jsparagus-ast",
@ -2421,12 +2421,12 @@ dependencies = [
[[package]]
name = "jsparagus-json-log"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
[[package]]
name = "jsparagus-parser"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"bumpalo",
"jsparagus-ast",
@ -2437,7 +2437,7 @@ dependencies = [
[[package]]
name = "jsparagus-scope"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"indexmap",
"jsparagus-ast",
@ -2447,7 +2447,7 @@ dependencies = [
[[package]]
name = "jsparagus-stencil"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
dependencies = [
"jsparagus-ast",
]

Просмотреть файл

@ -12,12 +12,12 @@ log = "0.4"
# Disable regex feature for code size.
env_logger = {version = "0.6", default-features = false}
# For non-jsparagus developers.
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "a62ca363140935fdd77549b6e17bb9d79f76af75" }
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "bc612163f379fa9978571981e860ec34b6ad59bd" }
# For local development, replace above with
# jsparagus = { path = "{path to jsparagus}" }
[build-dependencies]
# For non-jsparagus developers.
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "a62ca363140935fdd77549b6e17bb9d79f76af75" }
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "bc612163f379fa9978571981e860ec34b6ad59bd" }
# For local development, replace above with
# jsparagus = { path = "{path to jsparagus}" }

Просмотреть файл

@ -142,7 +142,7 @@ impl From<ScopeData> for SmooshScopeData {
match data {
ScopeData::Global(data) => Self {
kind: SmooshScopeDataKind::Global,
bindings: CVec::from(data.bindings.into_iter().map(|x| x.into()).collect()),
bindings: CVec::from(data.base.bindings.into_iter().map(|x| x.into()).collect()),
let_start: data.let_start,
const_start: data.const_start,
enclosing: 0,
@ -150,7 +150,7 @@ impl From<ScopeData> for SmooshScopeData {
},
ScopeData::Lexical(data) => Self {
kind: SmooshScopeDataKind::Lexical,
bindings: CVec::from(data.bindings.into_iter().map(|x| x.into()).collect()),
bindings: CVec::from(data.base.bindings.into_iter().map(|x| x.into()).collect()),
let_start: 0,
const_start: data.const_start,
enclosing: data.enclosing.into(),

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"ccbba839b0e9d3f2ea0106439920ed41476a7ca186a8e80584bb936775f1e91f","ast.json":"8bee02b419d90de0203ba7378aedecd5c94a447128b11231970119c9ecfecb77","generate_ast.py":"0c24431d9c07af42d7d17739c2e21465964151562437cfca093ceddde898bc93","src/arena.rs":"03ef07c963556160a6f1a85fd901833d7322f8a5f265c20d3e3543432dd2a96d","src/associated_data.rs":"028b7d2b370e75da153b50d86d9ff809e871d81a7fd3266e2d3727ce2bcc178d","src/dump_generated.rs":"a1368d31a8e3d286f230058e4a007ce7cd94240f2e59c0cc31c8a56756b1c1b3","src/json.rs":"ccc437c27f3fdaabb3d92b28eeb6bdee083bdf8014639ce09e7204a6529661a9","src/lib.rs":"b35553bedec9f6d88cc5194592f857dc13669559cbc8b206048c35299c4f86be","src/source_atom_set.rs":"1e6fb4be166c9fe4cf63ae6475f1abb12cb3dfa268250328a60f483a09e1481c","src/source_location.rs":"3832440ecec6de726262837072810410bddb45c075288386509511c153f6afd9","src/source_location_accessor_generated.rs":"4a016e4860a2b6b9b7637dff10c634255f6c1942231eb75224261679944fa169","src/source_slice_list.rs":"c82413b3081e091a3c4ce5d2c3624e54ecbeb0bb9952f10d373d10faf589955a","src/type_id_generated.rs":"c70cbdc0f84c2fd7e84fa6ef1614be22f63e52ffcbf2f93714c189dce3dad557","src/types_generated.rs":"965e0619315156b9fd918f26f6317aa98970b535a7df7442f163b23ee5eaf641","src/visit_generated.rs":"d09510127771be0c3a20c95ed48a4e4d387144e6cb08b02783a81739539111ed"},"package":null}
{"files":{"Cargo.toml":"ccbba839b0e9d3f2ea0106439920ed41476a7ca186a8e80584bb936775f1e91f","ast.json":"8bee02b419d90de0203ba7378aedecd5c94a447128b11231970119c9ecfecb77","generate_ast.py":"0c24431d9c07af42d7d17739c2e21465964151562437cfca093ceddde898bc93","src/arena.rs":"03ef07c963556160a6f1a85fd901833d7322f8a5f265c20d3e3543432dd2a96d","src/associated_data.rs":"aad369f45eca0506632d3c6aa2f487debb81d0dbc5a73eda46ee97478d51eaf3","src/dump_generated.rs":"a1368d31a8e3d286f230058e4a007ce7cd94240f2e59c0cc31c8a56756b1c1b3","src/json.rs":"ccc437c27f3fdaabb3d92b28eeb6bdee083bdf8014639ce09e7204a6529661a9","src/lib.rs":"b35553bedec9f6d88cc5194592f857dc13669559cbc8b206048c35299c4f86be","src/source_atom_set.rs":"1e6fb4be166c9fe4cf63ae6475f1abb12cb3dfa268250328a60f483a09e1481c","src/source_location.rs":"3832440ecec6de726262837072810410bddb45c075288386509511c153f6afd9","src/source_location_accessor_generated.rs":"4a016e4860a2b6b9b7637dff10c634255f6c1942231eb75224261679944fa169","src/source_slice_list.rs":"c82413b3081e091a3c4ce5d2c3624e54ecbeb0bb9952f10d373d10faf589955a","src/type_id_generated.rs":"c70cbdc0f84c2fd7e84fa6ef1614be22f63e52ffcbf2f93714c189dce3dad557","src/types_generated.rs":"965e0619315156b9fd918f26f6317aa98970b535a7df7442f163b23ee5eaf641","src/visit_generated.rs":"d09510127771be0c3a20c95ed48a4e4d387144e6cb08b02783a81739539111ed"},"package":null}

Просмотреть файл

@ -4,13 +4,13 @@ use crate::SourceLocation;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Key {
struct Key {
type_id: NodeTypeId,
loc: SourceLocation,
}
impl Key {
pub fn new<NodeT>(node: &NodeT) -> Self
fn new<NodeT>(node: &NodeT) -> Self
where
NodeT: SourceLocationAccessor + NodeTypeIdAccessor,
{

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"00c740f44b5681e3277e519d2e143e6edfbff186ca31a07ddce2eb46b803ddd7","src/array_emitter.rs":"bbc6528321f1d11d7c86c4f2bfdcfc9dced8f0b8b1c30c9f0a5355f300d196b6","src/ast_emitter.rs":"75ffb4b14483ac450b6e8c868a1b589a0d2a181ec59970ccc6c1146461f5862c","src/block_emitter.rs":"2aad01fd24b4165fe11d0f05949690d6a4010aa52d59203c0b7a923001cb540c","src/compilation_info.rs":"593509d0699213e07336d38279dbaa5fbcdff5969be8a357d4e9858e59091b46","src/control_structures.rs":"5d7ec0cc3234cba80d27d2f298eb39cefa135a6d0cb66247ebdd0711269867aa","src/dis.rs":"4a335d813fa965482ca0f20a7b9295a55ce7625b577d42bd8b33b156b81c6306","src/emitter.rs":"33598c3b3b29a8d226fdf58284707c7428cf0103732e052469e4c1513d961ba9","src/emitter_scope.rs":"0908a6a1587dc2eeb63115c483c4b126e214cd0a2bb390b399f5083ba7c48218","src/expression_emitter.rs":"f8e02785dffb179bbe9fe58e45bbfccc08adc3ad0a071a0073bed0feedc8ed9a","src/function_declaration_emitter.rs":"919fa60d230d0be59bd7872ffe0179adb923e70012160088ed6975952a13e1af","src/lib.rs":"31bf61e0527907e45d58d3a554825bf060e55d2d8c711627a41e03f82e8c2999","src/object_emitter.rs":"998423b3d6ef8797fadef6763803627df72fde292b1b34d6a41b2e66a331a181","src/reference_op_emitter.rs":"f3641a7c94f648b146d2e93321a9a1968a5bcedcccdd325c834d4a62eddbb173","src/script_emitter.rs":"44a6be5ecdcde3c32d78d100a205d38be2591c7c2cc109967579af7393e09fe8"},"package":null}
{"files":{"Cargo.toml":"00c740f44b5681e3277e519d2e143e6edfbff186ca31a07ddce2eb46b803ddd7","src/array_emitter.rs":"bbc6528321f1d11d7c86c4f2bfdcfc9dced8f0b8b1c30c9f0a5355f300d196b6","src/ast_emitter.rs":"f781c84197ca49e784733532c8d7155b884299ec3f941fa12e24ea668f0dc057","src/block_emitter.rs":"78965260d87a66c5324d6f3bdfea0f1938f8037f70adde148dbb2db599d1b2c0","src/compilation_info.rs":"8c8abbf777f03c6c9fc8dbf903c4f9f65304f96bc17f04a0868b3dd22cb1d113","src/control_structures.rs":"bdb186e98c14fa4e769b23b3dee4376683e6c6530af0856d55c055aff4398b84","src/dis.rs":"4a335d813fa965482ca0f20a7b9295a55ce7625b577d42bd8b33b156b81c6306","src/emitter.rs":"134f9f38f7f1adecfc43d230e602b7a87a89757af0fc1f6939bf181775ce4164","src/emitter_scope.rs":"07a904b6973bd2dbc1f9395022c15f11f6befc9b0fb4f2f251ccfc3f09aff380","src/expression_emitter.rs":"f8e02785dffb179bbe9fe58e45bbfccc08adc3ad0a071a0073bed0feedc8ed9a","src/function_declaration_emitter.rs":"74610fae178ed14c99e3dd7de01dc611718203adf0a85c7fa5209d27f1520379","src/lib.rs":"7d5c1d2f6fa25a2c18dd08c8361b30e1ceeb207c91542b3cd19f7cd2ab4ef131","src/object_emitter.rs":"998423b3d6ef8797fadef6763803627df72fde292b1b34d6a41b2e66a331a181","src/reference_op_emitter.rs":"4ead96ef4424e3937c3f73e22b4e103f97cee522b9926345caeddcf4643ff843","src/script_emitter.rs":"44a6be5ecdcde3c32d78d100a205d38be2591c7c2cc109967579af7393e09fe8"},"package":null}

Просмотреть файл

@ -8,7 +8,10 @@ use crate::compilation_info::CompilationInfo;
use crate::emitter::{EmitError, EmitOptions, InstructionWriter};
use crate::emitter_scope::{EmitterScopeStack, NameLocation};
use crate::expression_emitter::*;
use crate::function_declaration_emitter::{FunctionDeclarationEmitter, LazyFunctionEmitter};
use crate::function_declaration_emitter::{
AnnexBFunctionDeclarationEmitter, LazyFunctionEmitter, LexicalFunctionDeclarationEmitter,
TopLevelFunctionDeclarationEmitter,
};
use crate::object_emitter::*;
use crate::reference_op_emitter::{
AssignmentEmitter, CallEmitter, DeclarationEmitter, ElemReferenceEmitter, GetElemEmitter,
@ -18,7 +21,6 @@ use crate::reference_op_emitter::{
use crate::script_emitter::ScriptEmitter;
use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
use ast::types::*;
use std::collections::HashSet;
use stencil::opcode::Opcode;
use stencil::regexp::RegExpItem;
use stencil::result::EmitResult;
@ -59,10 +61,6 @@ pub struct AstEmitter<'alloc, 'opt> {
pub options: &'opt EmitOptions,
pub compilation_info: &'opt mut CompilationInfo<'alloc>,
pub control_stack: ControlStructureStack,
/// Holds the offset of top-level function declarations, to check if the
/// given function function declaration is top-level.
top_level_function_offsets: HashSet<usize>,
}
impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
@ -76,7 +74,6 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
options,
compilation_info,
control_stack: ControlStructureStack::new(),
top_level_function_offsets: HashSet::new(),
}
}
@ -86,7 +83,7 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
fn emit_script(mut self, ast: &Script) -> Result<ScriptStencil, EmitError> {
let scope_data_map = &self.compilation_info.scope_data_map;
let function_map = &self.compilation_info.function_map;
let function_declarations = &self.compilation_info.function_declarations;
let scope_index = scope_data_map.get_global_index();
let scope_data = scope_data_map.get_global_at(scope_index);
@ -94,13 +91,13 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
let top_level_functions: Vec<&Function> = scope_data
.functions
.iter()
.map(|key| *function_map.get(key).expect("function should exist"))
.map(|key| {
*function_declarations
.get(key)
.expect("function should exist")
})
.collect();
for fun in &top_level_functions {
self.note_top_level_function(fun);
}
ScriptEmitter {
top_level_functions: top_level_functions.iter(),
top_level_function: |emitter, fun| emitter.emit_top_level_function_declaration(fun),
@ -120,12 +117,43 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
.expect("FunctionStencil should be created");
let fun_index = LazyFunctionEmitter { stencil_index }.emit(self);
FunctionDeclarationEmitter { fun: fun_index }.emit(self);
TopLevelFunctionDeclarationEmitter { fun_index }.emit(self);
Err(EmitError::NotImplemented(
"TODO: closed over bindings for function",
"TODO: Populate FunctionStencil fields",
))
}
fn emit_non_top_level_function_declaration(&mut self, fun: &Function) -> Result<(), EmitError> {
let stencil_index = *self
.compilation_info
.function_stencil_indices
.get(fun)
.expect("FunctionStencil should be created");
let is_annex_b = self
.compilation_info
.function_declaration_properties
.is_annex_b(stencil_index);
let fun_index = LazyFunctionEmitter { stencil_index }.emit(self);
let name = self
.compilation_info
.functions
.get(stencil_index)
.name()
.expect("Function declaration should have name");
if is_annex_b {
AnnexBFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
} else {
LexicalFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
}
Err(EmitError::NotImplemented(
"TODO: Populate FunctionStencil fields",
))
//Ok(())
}
fn emit_statement(&mut self, ast: &Statement) -> Result<(), EmitError> {
@ -134,8 +162,26 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
return Err(EmitError::NotImplemented("TODO: ClassDeclaration"));
}
Statement::BlockStatement { block, .. } => {
let scope_data_map = &self.compilation_info.scope_data_map;
let function_declarations = &self.compilation_info.function_declarations;
let scope_index = scope_data_map.get_index(block);
let scope_data = scope_data_map.get_lexical_at(scope_index);
let functions: Vec<&Function> = scope_data
.functions
.iter()
.map(|key| {
*function_declarations
.get(key)
.expect("function should exist")
})
.collect();
BlockEmitter {
scope_index: self.compilation_info.scope_data_map.get_index(block),
functions: functions.iter(),
function: |emitter, fun| emitter.emit_non_top_level_function_declaration(fun),
statements: block.statements.iter(),
statement: |emitter, statement| emitter.emit_statement(statement),
}
@ -255,26 +301,12 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
Statement::WithStatement { .. } => {
return Err(EmitError::NotImplemented("TODO: WithStatement"));
}
Statement::FunctionDeclaration(fun) => {
if !self.is_top_level_function(fun) {
return Err(EmitError::NotImplemented(
"TODO: non-top-level FunctionDeclaration",
));
}
}
Statement::FunctionDeclaration(_) => {}
};
Ok(())
}
fn note_top_level_function(&mut self, fun: &Function) {
self.top_level_function_offsets.insert(fun.loc.start);
}
fn is_top_level_function(&self, fun: &Function) -> bool {
self.top_level_function_offsets.contains(&fun.loc.start)
}
fn emit_variable_declaration_statement(
&mut self,
ast: &VariableDeclaration,

Просмотреть файл

@ -2,17 +2,21 @@ use crate::ast_emitter::AstEmitter;
use crate::emitter::EmitError;
use stencil::scope::ScopeIndex;
pub struct BlockEmitter<'a, StmtT, StmtF>
pub struct BlockEmitter<'a, FuncT, FuncF, StmtT, StmtF>
where
FuncF: Fn(&mut AstEmitter, &FuncT) -> Result<(), EmitError>,
StmtF: Fn(&mut AstEmitter, &StmtT) -> Result<(), EmitError>,
{
pub scope_index: ScopeIndex,
pub functions: std::slice::Iter<'a, FuncT>,
pub function: FuncF,
pub statements: std::slice::Iter<'a, StmtT>,
pub statement: StmtF,
}
impl<'a, StmtT, StmtF> BlockEmitter<'a, StmtT, StmtF>
impl<'a, FuncT, FuncF, StmtT, StmtF> BlockEmitter<'a, FuncT, FuncF, StmtT, StmtF>
where
FuncF: Fn(&mut AstEmitter, &FuncT) -> Result<(), EmitError>,
StmtF: Fn(&mut AstEmitter, &StmtT) -> Result<(), EmitError>,
{
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
@ -22,6 +26,10 @@ where
self.scope_index,
);
for fun in self.functions {
(self.function)(emitter, fun)?;
}
for statement in self.statements {
(self.statement)(emitter, statement)?;
}

Просмотреть файл

@ -2,6 +2,8 @@ use ast::associated_data::AssociatedData;
use ast::source_atom_set::SourceAtomSet;
use ast::source_slice_list::SourceSliceList;
use ast::types::Function;
use scope::data::FunctionDeclarationPropertyMap;
use std::collections::HashMap;
use stencil::function::{FunctionStencilIndex, FunctionStencilList};
use stencil::scope::ScopeDataMap;
@ -9,8 +11,9 @@ pub struct CompilationInfo<'alloc> {
pub atoms: SourceAtomSet<'alloc>,
pub slices: SourceSliceList<'alloc>,
pub scope_data_map: ScopeDataMap,
pub function_map: AssociatedData<&'alloc Function<'alloc>>,
pub function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
pub function_declaration_properties: FunctionDeclarationPropertyMap,
pub functions: FunctionStencilList,
}
@ -19,16 +22,18 @@ impl<'alloc> CompilationInfo<'alloc> {
atoms: SourceAtomSet<'alloc>,
slices: SourceSliceList<'alloc>,
scope_data_map: ScopeDataMap,
function_map: AssociatedData<&'alloc Function<'alloc>>,
function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
function_stencil_indices: AssociatedData<FunctionStencilIndex>,
function_declaration_properties: FunctionDeclarationPropertyMap,
functions: FunctionStencilList,
) -> Self {
Self {
atoms,
slices,
scope_data_map,
function_map,
function_declarations,
function_stencil_indices,
function_declaration_properties,
functions,
}
}

Просмотреть файл

@ -1,7 +1,7 @@
use crate::ast_emitter::AstEmitter;
use crate::emitter::EmitError;
use crate::emitter::InstructionWriter;
use crate::emitter_scope::EmitterScopeDepth;
use crate::emitter_scope::{EmitterScope, EmitterScopeDepth};
use ast::source_atom_set::SourceAtomSetIndex;
use stencil::bytecode_offset::{BytecodeOffset, BytecodeOffsetDiff};
@ -674,31 +674,35 @@ where
};
// Step 2: find the current emitter scope
let current_scope_index = emitter.scope_stack.current_depth();
let mut parent_scope_note_index = emitter.scope_stack.get_current_scope_note_index();
// Step 3: iterate over scopes that have been entered since the enclosing scope,
// add a scope note hole for each one as we exit
// Step 3: iterate over scopes that have been entered since the
// enclosing scope, add a scope note hole for each one as we exit
let mut holes = Vec::new();
let scope_indicies = emitter
for item in emitter
.scope_stack
.scope_note_indices_from_to(&enclosing_emitter_scope_depth, &current_scope_index);
let mut parent_scope_note_index = emitter
.scope_stack
.get_scope_note_index_for(current_scope_index);
for maybe_scope_note_index in scope_indicies.iter().rev() {
let scope_note_index = emitter
.emit
.enter_scope_hole(maybe_scope_note_index, parent_scope_note_index);
holes.push(scope_note_index);
parent_scope_note_index = Some(scope_note_index);
.walk_up_to_including(enclosing_emitter_scope_depth)
{
// We're entering `item.outer` as a scope hole of `item.inner`.
let hole_scope_note_index = match item.inner {
EmitterScope::Global(_) => panic!("global shouldn't be enclosed by other scope"),
EmitterScope::Lexical(scope) => emitter.emit.enter_scope_hole_from_lexical(
&item.outer.scope_note_index(),
parent_scope_note_index,
scope.has_environment_object(),
),
};
holes.push(hole_scope_note_index);
parent_scope_note_index = Some(hole_scope_note_index);
}
// Step 4: perform the jump
self.registered_jump.emit(emitter);
// Step 5: close each scope hole after the jump
for scope_note_hole_index in holes.iter() {
emitter.emit.leave_scope_hole(*scope_note_hole_index);
for hole_scope_note_index in holes.iter() {
emitter.emit.leave_scope_hole(*hole_scope_note_index);
}
}
}

Просмотреть файл

@ -1204,9 +1204,9 @@ impl InstructionWriter {
self.write_g_c_thing_index(name_index);
}
pub fn push_lexical_env(&mut self, lexical_scope_index: u32) {
pub fn push_lexical_env(&mut self, lexical_scope_index: GCThingIndex) {
self.emit_op(Opcode::PushLexicalEnv);
self.write_u32(lexical_scope_index);
self.write_g_c_thing_index(lexical_scope_index);
}
pub fn pop_lexical_env(&mut self) {
@ -1225,14 +1225,14 @@ impl InstructionWriter {
self.emit_op(Opcode::FreshenLexicalEnv);
}
pub fn push_var_env(&mut self, scope_index: u32) {
pub fn push_var_env(&mut self, scope_index: GCThingIndex) {
self.emit_op(Opcode::PushVarEnv);
self.write_u32(scope_index);
self.write_g_c_thing_index(scope_index);
}
pub fn enter_with(&mut self, static_with_index: u32) {
pub fn enter_with(&mut self, static_with_index: GCThingIndex) {
self.emit_op(Opcode::EnterWith);
self.write_u32(static_with_index);
self.write_g_c_thing_index(static_with_index);
}
pub fn leave_with(&mut self) {
@ -1394,6 +1394,7 @@ impl InstructionWriter {
scope_index: ScopeIndex,
parent_scope_note_index: Option<ScopeNoteIndex>,
next_frame_slot: FrameSlot,
needs_environment_object: bool,
) -> ScopeNoteIndex {
self.update_max_frame_slots(next_frame_slot);
@ -1402,27 +1403,46 @@ impl InstructionWriter {
let note_index =
self.scope_notes
.enter_scope(gcthing_index, offset, parent_scope_note_index);
if needs_environment_object {
self.push_lexical_env(gcthing_index);
}
note_index
}
pub fn leave_lexical_scope(&mut self, index: ScopeNoteIndex) {
self.debug_leave_lexical_env();
pub fn leave_lexical_scope(&mut self, index: ScopeNoteIndex, needs_environment_object: bool) {
self.emit_leave_lexical_scope(needs_environment_object);
let offset = self.bytecode_offset();
self.scope_notes.leave_scope(index, offset);
}
pub fn enter_scope_hole(
fn emit_leave_lexical_scope(&mut self, needs_environment_object: bool) {
if needs_environment_object {
self.pop_lexical_env();
} else {
self.debug_leave_lexical_env();
}
}
pub fn enter_scope_hole_from_lexical(
&mut self,
maybe_scope_note_index: &Option<ScopeNoteIndex>,
maybe_hole_scope_note_index: &Option<ScopeNoteIndex>,
parent_scope_note_index: Option<ScopeNoteIndex>,
needs_environment_object: bool,
) -> ScopeNoteIndex {
self.emit_leave_lexical_scope(needs_environment_object);
self.enter_scope_hole(maybe_hole_scope_note_index, parent_scope_note_index)
}
fn enter_scope_hole(
&mut self,
maybe_hole_scope_note_index: &Option<ScopeNoteIndex>,
parent_scope_note_index: Option<ScopeNoteIndex>,
) -> ScopeNoteIndex {
// TODO: the bytecode sequence before leaving scope (entering hole) depends on the kind
// of scope (and also controls). This is currently only debug_leave_lexical_env because
// there's only simple lexical scope.
self.debug_leave_lexical_env();
let offset = self.bytecode_offset();
let gcthing_index = match maybe_scope_note_index {
let gcthing_index = match maybe_hole_scope_note_index {
Some(index) => self.scope_notes.get_scope_hole_gcthing_index(index),
None => self
.body_scope_index

Просмотреть файл

@ -7,6 +7,8 @@
use crate::emitter::InstructionWriter;
use ast::source_atom_set::SourceAtomSetIndex;
use std::collections::HashMap;
use std::iter::Iterator;
use stencil::env_coord::{EnvironmentHops, EnvironmentSlot};
use stencil::frame_slot::FrameSlot;
use stencil::scope::{BindingKind, GlobalScopeData, LexicalScopeData, ScopeDataMap, ScopeIndex};
use stencil::scope_notes::ScopeNoteIndex;
@ -20,6 +22,7 @@ pub enum NameLocation {
Dynamic,
Global(BindingKind),
FrameSlot(FrameSlot, BindingKind),
EnvironmentCoord(EnvironmentHops, EnvironmentSlot, BindingKind),
}
#[derive(Debug, Copy, Clone, PartialEq)]
@ -27,12 +30,26 @@ pub struct EmitterScopeDepth {
index: usize,
}
impl EmitterScopeDepth {
fn has_parent(&self) -> bool {
self.index > 0
}
fn parent(&self) -> Self {
debug_assert!(self.has_parent());
Self {
index: self.index - 1,
}
}
}
// --- EmitterScope types
//
// These types are the variants of enum EmitterScope.
#[derive(Debug)]
struct GlobalEmitterScope {
pub struct GlobalEmitterScope {
cache: HashMap<SourceAtomSetIndex, NameLocation>,
}
@ -59,28 +76,59 @@ impl GlobalEmitterScope {
fn scope_note_index(&self) -> Option<ScopeNoteIndex> {
None
}
fn has_environment_object(&self) -> bool {
false
}
}
struct LexicalEnvironmentObject {}
impl LexicalEnvironmentObject {
fn first_free_slot() -> u32 {
// FIXME: This is the value of
// `JSSLOT_FREE(&LexicalEnvironmentObject::class_)`
// in SpiderMonkey
2
}
}
#[derive(Debug)]
pub struct LexicalEmitterScope {
cache: HashMap<SourceAtomSetIndex, NameLocation>,
next_frame_slot: FrameSlot,
needs_environment_object: bool,
scope_note_index: Option<ScopeNoteIndex>,
}
impl LexicalEmitterScope {
pub fn new(data: &LexicalScopeData, first_frame_slot: FrameSlot) -> Self {
let is_all_bindings_closed_over = data.base.is_all_bindings_closed_over();
let mut needs_environment_object = false;
let mut cache = HashMap::new();
let mut slot = first_frame_slot;
let mut frame_slot = first_frame_slot;
let mut env_slot = EnvironmentSlot::new(LexicalEnvironmentObject::first_free_slot());
for item in data.iter() {
// FIXME: support environment (item.is_closed_over()).
cache.insert(item.name(), NameLocation::FrameSlot(slot, item.kind()));
slot.next();
if is_all_bindings_closed_over || item.is_closed_over() {
cache.insert(
item.name(),
NameLocation::EnvironmentCoord(EnvironmentHops::new(0), env_slot, item.kind()),
);
env_slot.next();
needs_environment_object = true;
} else {
cache.insert(
item.name(),
NameLocation::FrameSlot(frame_slot, item.kind()),
);
frame_slot.next();
}
}
Self {
cache,
next_frame_slot: slot,
next_frame_slot: frame_slot,
needs_environment_object,
scope_note_index: None,
}
}
@ -99,11 +147,15 @@ impl LexicalEmitterScope {
fn scope_note_index(&self) -> Option<ScopeNoteIndex> {
self.scope_note_index
}
pub fn has_environment_object(&self) -> bool {
self.needs_environment_object
}
}
/// The information about a scope needed for emitting bytecode.
#[derive(Debug)]
enum EmitterScope {
pub enum EmitterScope {
Global(GlobalEmitterScope),
Lexical(LexicalEmitterScope),
}
@ -129,6 +181,13 @@ impl EmitterScope {
EmitterScope::Lexical(scope) => scope.scope_note_index(),
}
}
fn has_environment_object(&self) -> bool {
match self {
EmitterScope::Global(scope) => scope.has_environment_object(),
EmitterScope::Lexical(scope) => scope.has_environment_object(),
}
}
}
/// Stack that tracks the current scope chain while emitting bytecode.
@ -176,7 +235,7 @@ impl EmitterScopeStack {
// Enter global scope here, before emitting any name ops below.
emit.enter_global_scope(scope_index);
if scope_data.bindings.len() > 0 {
if scope_data.base.bindings.len() > 0 {
emit.check_global_or_eval_decl();
}
@ -247,14 +306,18 @@ impl EmitterScopeStack {
) {
let mut scope_data = scope_data_map.get_lexical_at_mut(scope_index);
let first_frame_slot = self.innermost().next_frame_slot();
let parent_scope_note_index = self.innermost().scope_note_index();
let first_frame_slot = self.innermost().next_frame_slot();
scope_data.first_frame_slot = first_frame_slot;
let mut lexical_scope = LexicalEmitterScope::new(scope_data, first_frame_slot);
let next_frame_slot = lexical_scope.next_frame_slot;
let index = emit.enter_lexical_scope(scope_index, parent_scope_note_index, next_frame_slot);
let index = emit.enter_lexical_scope(
scope_index,
parent_scope_note_index,
next_frame_slot,
lexical_scope.needs_environment_object,
);
lexical_scope.scope_note_index = Some(index);
let scope = EmitterScope::Lexical(lexical_scope);
@ -273,6 +336,7 @@ impl EmitterScopeStack {
lexical_scope
.scope_note_index
.expect("scope note index should be populated"),
lexical_scope.needs_environment_object,
);
}
@ -283,43 +347,88 @@ impl EmitterScopeStack {
///
/// [1]: https://tc39.es/ecma262/#sec-resolvebinding
pub fn lookup_name(&mut self, name: SourceAtomSetIndex) -> NameLocation {
let mut hops = EnvironmentHops::new(0);
for scope in self.scope_stack.iter().rev() {
if let Some(loc) = scope.lookup_name(name) {
// FIXME: handle hops in aliased var.
return loc;
return match loc {
NameLocation::EnvironmentCoord(orig_hops, slot, kind) => {
debug_assert!(u8::from(orig_hops) == 0u8);
NameLocation::EnvironmentCoord(hops, slot, kind)
}
_ => loc,
};
}
if scope.has_environment_object() {
hops.next();
}
}
NameLocation::Dynamic
}
pub fn current_depth(&mut self) -> EmitterScopeDepth {
pub fn current_depth(&self) -> EmitterScopeDepth {
EmitterScopeDepth {
index: self.scope_stack.len() - 1,
}
}
pub fn scope_note_indices_from_to(
&self,
from: &EmitterScopeDepth,
to: &EmitterScopeDepth,
) -> Vec<Option<ScopeNoteIndex>> {
let mut indices = Vec::new();
for scope in self
.scope_stack
.iter()
.skip(from.index)
.take(to.index - from.index)
{
indices.push(scope.scope_note_index());
}
indices
/// Walk the scope stack up to and including `to` depth.
/// See EmitterScopeWalker for the details.
pub fn walk_up_to_including<'a>(&'a self, to: EmitterScopeDepth) -> EmitterScopeWalker<'a> {
EmitterScopeWalker::new(self, to)
}
pub fn get_scope_note_index_for(&self, index: EmitterScopeDepth) -> Option<ScopeNoteIndex> {
pub fn get_current_scope_note_index(&self) -> Option<ScopeNoteIndex> {
self.innermost().scope_note_index()
}
fn get<'a>(&'a self, index: EmitterScopeDepth) -> &'a EmitterScope {
self.scope_stack
.get(index.index)
.expect("scope should exist")
.scope_note_index()
}
}
/// Walk the scope stack up to `to`, and yields EmitterScopeWalkItem for
/// each scope.
///
/// The first item is `{ outer: parent-of-innermost, inner: innermost }`, and
/// the last item is `{ outer: to, inner: child-of-to }`.
pub struct EmitterScopeWalker<'a> {
stack: &'a EmitterScopeStack,
to: EmitterScopeDepth,
current: EmitterScopeDepth,
}
impl<'a> EmitterScopeWalker<'a> {
fn new(stack: &'a EmitterScopeStack, to: EmitterScopeDepth) -> Self {
let current = stack.current_depth();
Self { stack, to, current }
}
}
pub struct EmitterScopeWalkItem<'a> {
pub outer: &'a EmitterScope,
pub inner: &'a EmitterScope,
}
impl<'a> Iterator for EmitterScopeWalker<'a> {
type Item = EmitterScopeWalkItem<'a>;
fn next(&mut self) -> Option<EmitterScopeWalkItem<'a>> {
if self.current == self.to {
return None;
}
let outer_index = self.current.parent();
let inner_index = self.current;
self.current = outer_index;
Some(EmitterScopeWalkItem {
inner: self.stack.get(inner_index),
outer: self.stack.get(outer_index),
})
}
}

Просмотреть файл

@ -1,4 +1,7 @@
use crate::ast_emitter::AstEmitter;
use crate::emitter::EmitError;
use crate::reference_op_emitter::{AssignmentEmitter, DeclarationEmitter, NameReferenceEmitter};
use ast::source_atom_set::SourceAtomSetIndex;
use stencil::function::FunctionStencilIndex;
use stencil::gcthings::GCThingIndex;
@ -12,13 +15,53 @@ impl LazyFunctionEmitter {
}
}
pub struct FunctionDeclarationEmitter {
pub fun: GCThingIndex,
pub struct TopLevelFunctionDeclarationEmitter {
pub fun_index: GCThingIndex,
}
impl FunctionDeclarationEmitter {
impl TopLevelFunctionDeclarationEmitter {
pub fn emit(self, emitter: &mut AstEmitter) {
emitter.emit.lambda(self.fun);
emitter.emit.lambda(self.fun_index);
emitter.emit.def_fun();
}
}
pub struct LexicalFunctionDeclarationEmitter {
pub name: SourceAtomSetIndex,
pub fun_index: GCThingIndex,
}
impl LexicalFunctionDeclarationEmitter {
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
DeclarationEmitter {
lhs: |emitter| {
Ok(NameReferenceEmitter { name: self.name }.emit_for_declaration(emitter))
},
rhs: |emitter| {
emitter.emit.lambda(self.fun_index);
Ok(())
},
}
.emit(emitter)
}
}
pub struct AnnexBFunctionDeclarationEmitter {
pub name: SourceAtomSetIndex,
pub fun_index: GCThingIndex,
}
impl AnnexBFunctionDeclarationEmitter {
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
AssignmentEmitter {
lhs: |emitter| {
Ok(NameReferenceEmitter { name: self.name }.emit_for_assignment(emitter))
},
rhs: |emitter| {
emitter.emit.lambda(self.fun_index);
Ok(())
},
}
.emit(emitter)
}
}

Просмотреть файл

@ -34,16 +34,18 @@ pub fn emit<'alloc>(
) -> Result<EmitResult<'alloc>, EmitError> {
let ScopePassResult {
scope_data_map,
function_map,
function_declarations,
function_stencil_indices,
function_declaration_properties,
functions,
} = scope::generate_scope_data(ast);
let compilation_info = CompilationInfo::new(
atoms,
slices,
scope_data_map,
function_map,
function_declarations,
function_stencil_indices,
function_declaration_properties,
functions,
);
ast_emitter::emit_program(ast, options, compilation_info)

Просмотреть файл

@ -2,6 +2,7 @@ use crate::ast_emitter::AstEmitter;
use crate::emitter::EmitError;
use crate::emitter_scope::NameLocation;
use ast::source_atom_set::SourceAtomSetIndex;
use stencil::env_coord::{EnvironmentHops, EnvironmentSlot};
use stencil::frame_slot::FrameSlot;
use stencil::gcthings::GCThingIndex;
use stencil::scope::BindingKind;
@ -12,6 +13,8 @@ enum AssignmentReferenceKind {
GlobalLexical(GCThingIndex),
FrameSlotLexical(FrameSlot),
FrameSlotNonLexical(FrameSlot),
EnvironmentCoordLexical(EnvironmentHops, EnvironmentSlot),
EnvironmentCoordNonLexical(EnvironmentHops, EnvironmentSlot),
Dynamic(GCThingIndex),
#[allow(dead_code)]
Prop(GCThingIndex),
@ -37,6 +40,8 @@ impl AssignmentReference {
AssignmentReferenceKind::GlobalLexical(_) => 1,
AssignmentReferenceKind::FrameSlotLexical(_) => 0,
AssignmentReferenceKind::FrameSlotNonLexical(_) => 0,
AssignmentReferenceKind::EnvironmentCoordLexical(_, _) => 0,
AssignmentReferenceKind::EnvironmentCoordNonLexical(_, _) => 0,
AssignmentReferenceKind::Dynamic(_) => 1,
AssignmentReferenceKind::Prop(_) => 1,
AssignmentReferenceKind::Elem => 2,
@ -49,6 +54,7 @@ enum DeclarationReferenceKind {
GlobalVar(GCThingIndex),
GlobalLexical(GCThingIndex),
FrameSlot(FrameSlot),
EnvironmentCoord(EnvironmentHops, EnvironmentSlot),
}
// See DeclarationReferenceEmitter.
@ -76,7 +82,7 @@ enum ValueIsOnStack {
Yes,
}
fn check_temporary_dead_zone(
fn check_frame_temporary_dead_zone(
emitter: &mut AstEmitter,
slot: FrameSlot,
is_on_stack: ValueIsOnStack,
@ -102,6 +108,33 @@ fn check_temporary_dead_zone(
// [stack] VAL?
}
fn check_env_temporary_dead_zone(
emitter: &mut AstEmitter,
hops: EnvironmentHops,
slot: EnvironmentSlot,
is_on_stack: ValueIsOnStack,
) {
// FIXME: Use cache to avoid emitting check_lexical twice or more.
// FIXME: Support aliased lexical.
// [stack] VAL?
if is_on_stack == ValueIsOnStack::No {
emitter.emit.get_aliased_var(hops.into(), slot.into());
// [stack] VAL
}
emitter.emit.check_aliased_lexical(hops.into(), slot.into());
// [stack] VAL
if is_on_stack == ValueIsOnStack::No {
emitter.emit.pop();
// [stack]
}
// [stack] VAL?
}
// See *ReferenceEmitter.
// This uses struct to hide the details from the consumer.
#[derive(Debug)]
@ -140,7 +173,15 @@ impl GetNameEmitter {
// [stack] VAL
if kind == BindingKind::Let || kind == BindingKind::Const {
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
// [stack] VAL
}
}
NameLocation::EnvironmentCoord(hops, slot, kind) => {
emitter.emit.get_aliased_var(hops.into(), slot.into());
if kind == BindingKind::Let || kind == BindingKind::Const {
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::Yes);
// [stack] VAL
}
}
@ -317,7 +358,19 @@ impl NameReferenceEmitter {
// [stack] CALLEE
if kind == BindingKind::Let || kind == BindingKind::Const {
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
// [stack] CALLEE
}
emitter.emit.undefined();
// [stack] CALLEE THIS
}
NameLocation::EnvironmentCoord(hops, slot, kind) => {
emitter.emit.get_aliased_var(hops.into(), slot.into());
// [stack] CALLEE
if kind == BindingKind::Let || kind == BindingKind::Const {
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::Yes);
// [stack] CALLEE
}
@ -361,6 +414,17 @@ impl NameReferenceEmitter {
AssignmentReference::new(AssignmentReferenceKind::FrameSlotNonLexical(slot))
}
}
NameLocation::EnvironmentCoord(hops, slot, kind) => {
if kind == BindingKind::Let || kind == BindingKind::Const {
AssignmentReference::new(AssignmentReferenceKind::EnvironmentCoordLexical(
hops, slot,
))
} else {
AssignmentReference::new(AssignmentReferenceKind::EnvironmentCoordNonLexical(
hops, slot,
))
}
}
}
}
@ -387,6 +451,10 @@ impl NameReferenceEmitter {
NameLocation::FrameSlot(slot, _kind) => {
DeclarationReference::new(DeclarationReferenceKind::FrameSlot(slot))
}
NameLocation::EnvironmentCoord(hops, slot, _kind) => {
// FIXME: does this happen????
DeclarationReference::new(DeclarationReferenceKind::EnvironmentCoord(hops, slot))
}
}
}
}
@ -636,7 +704,7 @@ where
AssignmentReferenceKind::FrameSlotLexical(slot) => {
// [stack] VAL
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::No);
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::No);
// [stack] VAL
emitter.emit.set_local(slot.into());
@ -648,6 +716,21 @@ where
emitter.emit.set_local(slot.into());
// [stack] VAL
}
AssignmentReferenceKind::EnvironmentCoordLexical(hops, slot) => {
// [stack] VAL
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::No);
// [stack] VAL
emitter.emit.set_aliased_var(hops.into(), slot.into());
// [stack] VAL
}
AssignmentReferenceKind::EnvironmentCoordNonLexical(hops, slot) => {
// [stack] VAL
emitter.emit.set_aliased_var(hops.into(), slot.into());
// [stack] VAL
}
AssignmentReferenceKind::Prop(key_index) => {
// [stack] OBJ VAL
@ -708,6 +791,12 @@ where
emitter.emit.init_lexical(slot.into());
// [stack] VAL
}
DeclarationReferenceKind::EnvironmentCoord(hops, slot) => {
// [stack] VAL
emitter.emit.init_aliased_lexical(hops.into(), slot.into());
// [stack] VAL
}
}
Ok(())

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"553be3c198fe555913bbeb7473b24e0e1fff12e48890a2e399b311df8a97c814","src/ast_builder.rs":"8b10743ebbc3390d1158cb44ff5c87fbb653d62521f3e1274565d0061eebe095","src/context_stack.rs":"29331d03cd4c8ee9283cb426ebe893b7ba6ad6d8a69016399c4d92a81cb1363b","src/declaration_kind.rs":"fdfda2fe408cce1c637d17fee0813160619450472c6de9befc36ebeed892cc3c","src/early_error_checker.rs":"150a106a8f0901b72ae40581f0c12f785983514cbc9042404ed6cf4315693d60","src/early_errors.rs":"8674454af7ac5efe51eb6a8e2abe088aad5560e0a0bd88a3eae66c90f1527149","src/error.rs":"507e4dd9c66720f3da2db135c3024392d8aaac5ccdb90c7f7463ccb2eff7efa8","src/lib.rs":"a40b11e1dda1afcccef5fc86a2030c326d38feb31e24596e602930dcad28f1ec","src/parser_tables_generated.rs":"2dc9609189992d135583ad0a7ca3b1b261bf3cc86d4ae73df1ce3f822bef54de","src/stack_value_generated.rs":"d8696a671368e2565d589922e3a46d20667ed3e17e29953e69b970470e9639ee","src/token.rs":"479f4cb97d2e6bc654a70634f3809817cc73eaf749c845643beb3556b9ead383","src/traits/mod.rs":"bcc2fa63444ba4c763dc996f410a6871f2cdc3bde54e1924ca8cc25cba92674a"},"package":null}
{"files":{"Cargo.toml":"553be3c198fe555913bbeb7473b24e0e1fff12e48890a2e399b311df8a97c814","src/ast_builder.rs":"8b10743ebbc3390d1158cb44ff5c87fbb653d62521f3e1274565d0061eebe095","src/context_stack.rs":"29331d03cd4c8ee9283cb426ebe893b7ba6ad6d8a69016399c4d92a81cb1363b","src/declaration_kind.rs":"fdfda2fe408cce1c637d17fee0813160619450472c6de9befc36ebeed892cc3c","src/early_error_checker.rs":"150a106a8f0901b72ae40581f0c12f785983514cbc9042404ed6cf4315693d60","src/early_errors.rs":"8674454af7ac5efe51eb6a8e2abe088aad5560e0a0bd88a3eae66c90f1527149","src/error.rs":"507e4dd9c66720f3da2db135c3024392d8aaac5ccdb90c7f7463ccb2eff7efa8","src/lib.rs":"a40b11e1dda1afcccef5fc86a2030c326d38feb31e24596e602930dcad28f1ec","src/parser_tables_generated.rs":"f929ecaa8e8ffdbac8a0ae5ebb96b115f72b21116890952e04af75cca5a37718","src/stack_value_generated.rs":"d8696a671368e2565d589922e3a46d20667ed3e17e29953e69b970470e9639ee","src/token.rs":"479f4cb97d2e6bc654a70634f3809817cc73eaf749c845643beb3556b9ead383","src/traits/mod.rs":"bcc2fa63444ba4c763dc996f410a6871f2cdc3bde54e1924ca8cc25cba92674a"},"package":null}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"500dc18629fd32dd7019a7967535d6fc53bf94dc7e6c305be46f4040d47cac9e","src/builder.rs":"a6c3a2192f8b55901fd41e80913fcc9f498f0b08d4097133821596803ebdce9b","src/free_name_tracker.rs":"94df3881bd8f5b0e67e2723cc3a2848461d7145dabb001f359fe124e54ed23bc","src/lib.rs":"9ac4537eb4423a48ddeb41bd0cfdcf04e3d4dcb1db1e53f49df5313dcd1fddf4","src/pass.rs":"dcd77a5de29a63ca8460846883681132325eb7c0ee97b8e9994599ac874fd355"},"package":null}
{"files":{"Cargo.toml":"500dc18629fd32dd7019a7967535d6fc53bf94dc7e6c305be46f4040d47cac9e","src/builder.rs":"09e6c547da4098920aaf067d0fc97e00a41500afc52c4dbff4c96eb650b9ac55","src/data.rs":"baebda52ab0d962a0fc13c5db3dcd1173b701e55f248da466da6bcaf0890784e","src/free_name_tracker.rs":"94df3881bd8f5b0e67e2723cc3a2848461d7145dabb001f359fe124e54ed23bc","src/lib.rs":"16b1fe6659f977a547df15922b2864b81c4d452ad198409db4374e88c6df68bc","src/pass.rs":"121a2a63dfec1ad8658587de3932859428c6a04e175e5e6c3d0a8938e411e931"},"package":null}

Просмотреть файл

@ -33,13 +33,15 @@
//!
//! [1]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
use crate::data::FunctionDeclarationPropertyMap;
use crate::free_name_tracker::FreeNameTracker;
use ast::associated_data::{AssociatedData, Key as AssociatedDataKey};
use ast::associated_data::AssociatedData;
use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
use ast::source_location_accessor::SourceLocationAccessor;
use ast::type_id::NodeTypeIdAccessor;
use indexmap::set::IndexSet;
use std::collections::HashSet;
use std::collections::hash_map::Keys;
use std::collections::{HashMap, HashSet};
use stencil::function::{
FunctionFlags, FunctionStencil, FunctionStencilIndex, FunctionStencilList, FunctionSyntaxKind,
SourceExtent,
@ -318,6 +320,109 @@ enum ScopeKind {
BlockStatementList,
}
/// Index into BaseScopeData.bindings.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BindingIndex {
index: usize,
}
impl BindingIndex {
fn new(index: usize) -> Self {
Self { index }
}
pub fn next(&self) -> Self {
Self {
index: self.index + 1,
}
}
}
impl From<BindingIndex> for usize {
fn from(index: BindingIndex) -> usize {
index.index
}
}
#[derive(Debug)]
struct PossiblyAnnexBFunction {
name: SourceAtomSetIndex,
owner_scope_index: ScopeIndex,
binding_index: BindingIndex,
stencil_index: FunctionStencilIndex,
}
#[derive(Debug)]
struct PossiblyAnnexBFunctionList {
functions: HashMap<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>>,
}
impl PossiblyAnnexBFunctionList {
fn new() -> Self {
Self {
functions: HashMap::new(),
}
}
fn push(
&mut self,
name: SourceAtomSetIndex,
owner_scope_index: ScopeIndex,
binding_index: BindingIndex,
stencil_index: FunctionStencilIndex,
) {
if let Some(functions) = self.functions.get_mut(&name) {
functions.push(PossiblyAnnexBFunction {
name,
owner_scope_index,
binding_index,
stencil_index,
});
return;
}
let mut functions = Vec::with_capacity(1);
functions.push(PossiblyAnnexBFunction {
name,
owner_scope_index,
binding_index,
stencil_index,
});
self.functions.insert(name, functions);
}
fn remove_if_exists(&mut self, name: SourceAtomSetIndex) {
self.functions.remove(&name);
}
fn mark_annex_b(
&self,
scopes: &mut ScopeDataList,
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
) {
for functions in &mut self.functions.values() {
for fun in functions {
let scope = scopes.get_mut(fun.owner_scope_index);
match scope {
ScopeData::Lexical(data) => {
data.mark_annex_b_function(fun.name, fun.binding_index.into());
}
_ => panic!("unexpected scope pointed by Annex B function"),
}
function_declaration_properties.mark_annex_b(fun.stencil_index);
}
}
}
fn names(&self) -> Keys<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>> {
self.functions.keys()
}
fn clear(&mut self) {
self.functions.clear();
}
}
/// Variables declared/used in GlobalDeclarationInstantiation.
#[derive(Debug)]
struct GlobalScopeBuilder {
@ -325,7 +430,7 @@ struct GlobalScopeBuilder {
/// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
///
/// Step 8. Let functionsToInitialize be a new empty List.
functions_to_initialize: Vec<AssociatedDataKey>,
functions_to_initialize: Vec<FunctionStencilIndex>,
/// Step 9. Let declaredFunctionNames be a new empty List.
declared_function_names: IndexSet<SourceAtomSetIndex>,
@ -402,10 +507,7 @@ impl GlobalScopeBuilder {
self.const_names.push(name);
}
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
where
T: SourceLocationAccessor + NodeTypeIdAccessor,
{
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
//
@ -439,8 +541,7 @@ impl GlobalScopeBuilder {
// Step 10.a.iv.4. Insert d as the first element of
// functionsToInitialize.
self.functions_to_initialize
.push(AssociatedDataKey::new(fun));
self.functions_to_initialize.push(fun_index);
}
fn remove_function_names_from_var_names(&mut self) {
@ -456,7 +557,117 @@ impl GlobalScopeBuilder {
}
}
fn into_scope_data(self) -> ScopeData {
fn perform_annex_b(
&mut self,
scopes: &mut ScopeDataList,
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
) {
// Annex B
// Changes to GlobalDeclarationInstantiation
// https://tc39.es/ecma262/#sec-web-compat-globaldeclarationinstantiation
//
// Step 1. Let strict be IsStrict of script.
//
// FIXME: Once directives are supported, reflect it here.
let strict = false;
// Step 2. If strict is false, then
if strict {
return;
}
// Step 2.a. Let declaredFunctionOrVarNames be a new empty List.
// Step 2.b. Append to declaredFunctionOrVarNames the elements of
// declaredFunctionNames.
// Step 2.c. Append to declaredFunctionOrVarNames the elements of
// declaredVarNames.
//
// NOTE: Use `self.declared_var_names` to avoid duplication against
// `declaredVarNames`.
// And duplication against `declaredFunctionNames` will be
// removed in `remove_function_names_from_var_names`.
// Step 2.d. For each FunctionDeclaration f that is directly contained
// in the StatementList of a Block, CaseClause, or
// DefaultClause Contained within script, do
//
// NOTE: `possibly_annex_b_functions` contains all of them.
// Step 2.d.i. Let F be StringValue of the BindingIdentifier of f.
// Step 2.d.ii. If replacing the FunctionDeclaration f with a
// VariableStatement that has F as a BindingIdentifier
// would not produce any Early Errors for script, then
//
// NOTE: Early Errors happen if any of top-level lexical has
// the same name. Filter out those functions here.
for n in &self.let_names {
possibly_annex_b_functions.remove_if_exists(*n);
}
for n in &self.const_names {
possibly_annex_b_functions.remove_if_exists(*n);
}
// Step 2.d.ii.1. If env.HasLexicalDeclaration(F) is false, then
// Step 2.d.ii.1.a. Let fnDefinable be ? env.CanDeclareGlobalVar(F).
// Step 2.d.ii.1.b. If fnDefinable is true, then
//
// FIXME: Are these steps performed by any implementation?
// https://github.com/tc39/ecma262/issues/2019
// Step 2.d.ii.1.b.i. NOTE: A var binding for F is only instantiated
// here if it is neither a VarDeclaredName nor
// the name of another FunctionDeclaration.
// Step 2.d.ii.1.b.ii. If declaredFunctionOrVarNames does not
// contain F, then
// Step 2.d.ii.1.b.ii.1. Perform
// ?env.CreateGlobalVarBinding(F, false).
// Step 2.d.ii.1.b.ii.2. Append F to declaredFunctionOrVarNames.
for n in possibly_annex_b_functions.names() {
self.declared_var_names.insert(*n);
}
// Step 2.d.ii.1.b.iii. When the FunctionDeclaration f is evaluated,
// perform the following steps in place of the
// FunctionDeclaration Evaluation algorithm
// provided in
// https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation :
// Step 2.d.ii.1.b.iii.1. Let genv be the running execution
// context's VariableEnvironment.
// Step 2.d.ii.1.b.iii.2. Let benv be the running execution
// context's LexicalEnvironment.
// Step 2.d.ii.1.b.iii.3. Let fobj be
// ! benv.GetBindingValue(F, false).
// Step 2.d.ii.1.b.iii.4. Perform
// ? genv.SetMutableBinding(F, fobj, false).
// Step 2.d.ii.1.b.iii.5. Return NormalCompletion(empty).
possibly_annex_b_functions.mark_annex_b(scopes, function_declaration_properties);
}
fn into_scope_data(
mut self,
scopes: &mut ScopeDataList,
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
) -> ScopeData {
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
//
// NOTE: Steps are reordered to match the order of binding in runtime.
// Step 13. NOTE: Annex B adds additional steps at this point.
//
// NOTE: Reordered here to reflect the change to
// self.declared_var_names.
self.perform_annex_b(
scopes,
function_declaration_properties,
possibly_annex_b_functions,
);
// Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
self.remove_function_names_from_var_names();
let mut data = GlobalScopeData::new(
self.declared_var_names.len() + self.declared_function_names.len(),
self.let_names.len(),
@ -464,16 +675,13 @@ impl GlobalScopeBuilder {
self.functions_to_initialize,
);
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
//
// NOTE: Steps are reordered to match the order of binding in runtime.
//
// Step 18. For each String vn in declaredVarNames, in list order, do
for n in &self.declared_var_names {
// 18.a. Perform ? envRec.CreateGlobalVarBinding(vn, false).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over))
}
// Step 17. For each Parse Node f in functionsToInitialize, do
@ -483,10 +691,9 @@ impl GlobalScopeBuilder {
// argument env.
// Step 17.c. Perform
// ? envRec.CreateGlobalFunctionBinding(fn, fo, false).
//
// FIXME: for Annex B functions, use `new`.
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings
data.base
.bindings
.push(BindingName::new_top_level_function(*n, is_closed_over));
}
@ -498,19 +705,29 @@ impl GlobalScopeBuilder {
// Step 16.b.ii. Else,
// Step 16.b.ii.1. Perform ? envRec.CreateMutableBinding(dn, false).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over))
}
for n in &self.const_names {
// Step 16.b.i. If IsConstantDeclaration of d is true, then
// Step 16.b.i.1. Perform ? envRec.CreateImmutableBinding(dn, true).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over))
}
ScopeData::Global(data)
}
}
#[derive(Debug)]
struct FunctionNameAndStencilIndex {
name: SourceAtomSetIndex,
stencil: FunctionStencilIndex,
}
/// Variables declared/used in BlockDeclarationInstantiation
#[derive(Debug)]
struct BlockScopeBuilder {
@ -519,7 +736,6 @@ struct BlockScopeBuilder {
///
/// Step 3. Let declarations be the LexicallyScopedDeclarations of code.
let_names: Vec<SourceAtomSetIndex>,
fun_names: Vec<SourceAtomSetIndex>,
const_names: Vec<SourceAtomSetIndex>,
/// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
@ -528,9 +744,7 @@ struct BlockScopeBuilder {
/// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
/// AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
/// then
///
/// FIXME: Support Annex B.
functions: Vec<AssociatedDataKey>,
functions: Vec<FunctionNameAndStencilIndex>,
/// Scope associated to this builder.
scope_index: ScopeIndex,
@ -541,7 +755,6 @@ impl BlockScopeBuilder {
fn new(scope_index: ScopeIndex) -> Self {
Self {
let_names: Vec::new(),
fun_names: Vec::new(),
const_names: Vec::new(),
functions: Vec::new(),
scope_index,
@ -565,34 +778,31 @@ impl BlockScopeBuilder {
self.const_names.push(name);
}
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
where
T: SourceLocationAccessor + NodeTypeIdAccessor,
{
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
//
// Step 3. Let declarations be the LexicallyScopedDeclarations of code.
self.fun_names.push(name);
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
//
// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
// AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
// then
self.functions.push(AssociatedDataKey::new(fun));
self.functions.push(FunctionNameAndStencilIndex {
name,
stencil: fun_index,
});
}
fn into_scope_data(self, enclosing: ScopeIndex) -> ScopeData {
// FIXME: Before this, perform Annex B for functions.
fn into_scope_data(
self,
enclosing: ScopeIndex,
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
) -> ScopeData {
let mut data = LexicalScopeData::new_block(
self.let_names.len() + self.fun_names.len(),
self.let_names.len() + self.functions.len(),
self.const_names.len(),
enclosing,
self.functions,
self.functions.iter().map(|n| n.stencil).collect(),
);
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
@ -608,9 +818,11 @@ impl BlockScopeBuilder {
// Step 4.a.ii. Else,
// Step 4.a.ii.1. Perform ! envRec.CreateMutableBinding(dn, false).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over));
}
for n in &self.fun_names {
for n in &self.functions {
// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration,
// an AsyncFunctionDeclaration,
// or an AsyncGeneratorDeclaration, then
@ -618,14 +830,21 @@ impl BlockScopeBuilder {
// Step 4.b.ii. Let fo be InstantiateFunctionObject of d with
// argument env.
// Step 4.b.iii. Perform envRec.InitializeBinding(fn, fo).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
let is_closed_over = self.name_tracker.is_closed_over_def(&n.name);
let binding_index = BindingIndex::new(data.base.bindings.len());
data.base
.bindings
.push(BindingName::new(n.name, is_closed_over));
possibly_annex_b_functions.push(n.name, self.scope_index, binding_index, n.stencil);
}
for n in &self.const_names {
// Step 4.a.i. If IsConstantDeclaration of d is true, then
// Step 4.a.i.1. Perform ! envRec.CreateImmutableBinding(dn, true).
let is_closed_over = self.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over));
}
ScopeData::Lexical(data)
@ -679,7 +898,9 @@ impl FunctionExpressionScopeBuilder {
// Step 4. Let name be StringValue of BindingIdentifier .
// Step 5. Perform envRec.CreateImmutableBinding(name, false).
let is_closed_over = self.name_tracker.is_closed_over_def(name);
data.bindings.push(BindingName::new(*name, is_closed_over));
data.base
.bindings
.push(BindingName::new(*name, is_closed_over));
ScopeData::Lexical(data)
}
@ -976,10 +1197,84 @@ impl FunctionParametersScopeBuilder {
}
}
fn perform_annex_b(
&mut self,
scopes: &mut ScopeDataList,
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
body_scope_builder: &mut FunctionBodyScopeBuilder,
) {
// Annex B
// Changes to FunctionDeclarationInstantiation
// https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
//
// Step 1. If strict is false, then
//
// FIXME: Once directives are supported, reflect it here.
let strict = false;
if strict {
return;
}
// Step 1.a. For each FunctionDeclaration f that is directly contained
// in the StatementList of a Block, CaseClause, or
// DefaultClause, do
//
// NOTE: `possibly_annex_b_functions` contains all of them.
// Step 1.a.i. Let F be StringValue of the BindingIdentifier of f.
// Step 1.a.ii. If replacing the FunctionDeclaration f with a
// VariableStatement that has F as a BindingIdentifier
// would not produce any Early Errors for func and F is
// not an element of parameterNames, then
//
// NOTE: Early Errors happen if any of top-level lexical has
// the same name. Filter out those functions here.
for n in &body_scope_builder.let_names {
possibly_annex_b_functions.remove_if_exists(*n);
}
for n in &body_scope_builder.const_names {
possibly_annex_b_functions.remove_if_exists(*n);
}
// Step 1.a.ii.1. NOTE: A var binding for F is only instantiated here
// if it is neither a VarDeclaredName, the name of a
// formal parameter, or another FunctionDeclaration.
//
// NOTE: The binding is merged into the list of other var names.
// Step 1.a.ii.2. If initializedBindings does not contain F and F is
// not "arguments", then
possibly_annex_b_functions.remove_if_exists(CommonSourceAtomSetIndices::arguments());
// Step 1.a.ii.2.a. Perform ! varEnv.CreateMutableBinding(F, false).
// Step 1.a.ii.2.b. Perform varEnv.InitializeBinding(F, undefined).
// Step 1.a.ii.2.c. Append F to instantiatedVarNames.
for n in possibly_annex_b_functions.names() {
body_scope_builder.var_names.insert(*n);
}
// Step 1.a.ii.3. When the FunctionDeclaration f is evaluated, perform
// the following steps in place of the
// FunctionDeclaration Evaluation algorithm provided in
// https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation
// Step 1.a.ii.3.a. Let fenv be the running execution context's
// VariableEnvironment.
// Step 1.a.ii.3.b. Let benv be the running execution context's
// LexicalEnvironment.
// Step 1.a.ii.3.c. Let fobj be ! benv.GetBindingValue(F, false).
// Step 1.a.ii.3.d. Perform ! fenv.SetMutableBinding(F, fobj, false).
// Step 1.a.ii.3.e. Return NormalCompletion(empty).
possibly_annex_b_functions.mark_annex_b(scopes, function_declaration_properties);
}
fn into_scope_data_set(
self,
mut self,
scopes: &mut ScopeDataList,
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
enclosing: ScopeIndex,
body_scope_builder: FunctionBodyScopeBuilder,
mut body_scope_builder: FunctionBodyScopeBuilder,
) -> FunctionScopeDataSet {
// FunctionDeclarationInstantiation ( func, argumentsList )
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
@ -1037,6 +1332,17 @@ impl FunctionParametersScopeBuilder {
// Step 20.f. Set the LexicalEnvironment of calleeContext to env.
}
// Step 29. NOTE: Annex B adds additional steps at this point.
//
// NOTE: Reordered here to reflect the change to
// body_scope_builder.var_names.
self.perform_annex_b(
scopes,
function_declaration_properties,
possibly_annex_b_functions,
&mut body_scope_builder,
);
let has_extra_body_var_scope = self.has_parameter_expressions;
let function_var_names_count = if has_extra_body_var_scope {
0
@ -1052,6 +1358,9 @@ impl FunctionParametersScopeBuilder {
enclosing,
);
// FunctionDeclarationInstantiation ( func, argumentsList )
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
//
// Step 21. For each String paramName in parameterNames, do
// Step 21.a. Let alreadyDeclared be envRec.HasBinding(paramName).
// Step 21.b. NOTE: Early errors ensure that duplicate parameter names
@ -1071,10 +1380,11 @@ impl FunctionParametersScopeBuilder {
|| (!has_extra_body_var_scope
&& body_scope_builder.name_tracker.is_closed_over_def(n));
function_scope_data
.base
.bindings
.push(Some(BindingName::new(*n, is_closed_over)))
}
None => function_scope_data.bindings.push(None),
None => function_scope_data.base.bindings.push(None),
}
}
for n in &self.non_positional_parameter_names {
@ -1082,6 +1392,7 @@ impl FunctionParametersScopeBuilder {
|| (!has_extra_body_var_scope
&& body_scope_builder.name_tracker.is_closed_over_def(n));
function_scope_data
.base
.bindings
.push(Some(BindingName::new(*n, is_closed_over)))
}
@ -1144,6 +1455,7 @@ impl FunctionParametersScopeBuilder {
// ! envRec.CreateMutableBinding(n, false).
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
function_scope_data
.base
.bindings
.push(Some(BindingName::new(*n, is_closed_over)));
@ -1185,7 +1497,9 @@ impl FunctionParametersScopeBuilder {
// Step 28.f.i.2. Perform
// ! varEnvRec.CreateMutableBinding(n, false).
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over));
data.base
.bindings
.push(BindingName::new(*n, is_closed_over));
// Step 28.f.i.3. If n is not an element of parameterBindings or if
// n is an element of functionNames, let
@ -1204,9 +1518,6 @@ impl FunctionParametersScopeBuilder {
ScopeData::Var(data)
};
// Step 29. NOTE: Annex B.3.3.1 adds additional steps at this point.
// FIXME
// Step 30. If strict is false, then
// Step 30.a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
// Step 30.b. NOTE: Non-strict functions use a separate lexical
@ -1246,14 +1557,18 @@ impl FunctionParametersScopeBuilder {
// Step 35.b.ii.1. Perform
// ! lexEnvRec.CreateMutableBinding(dn, false).
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over))
}
for n in &body_scope_builder.const_names {
// Step 35.b.i. If IsConstantDeclaration of d is true, then
// Step 35.b.i.1. Perform
// ! lexEnvRec.CreateImmutableBinding(dn, true).
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
data.bindings.push(BindingName::new(*n, is_closed_over))
data.base
.bindings
.push(BindingName::new(*n, is_closed_over))
}
ScopeData::Lexical(data)
@ -1286,7 +1601,7 @@ struct FunctionBodyScopeBuilder {
const_names: Vec<SourceAtomSetIndex>,
/// Step 13. Let functionsToInitialize be a new empty List.
functions_to_initialize: Vec<AssociatedDataKey>,
functions_to_initialize: Vec<FunctionStencilIndex>,
/// Step 18. Else if hasParameterExpressions is false, then
/// Step 18.a. If "arguments" is an element of functionNames or
@ -1352,10 +1667,7 @@ impl FunctionBodyScopeBuilder {
self.check_lexical_or_function_name(name);
}
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
where
T: SourceLocationAccessor + NodeTypeIdAccessor,
{
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
// FunctionDeclarationInstantiation ( func, argumentsList )
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
//
@ -1382,8 +1694,7 @@ impl FunctionBodyScopeBuilder {
// Step 14.a.iii.3. Insert d as the first element of
// functionsToInitialize.
self.functions_to_initialize
.push(AssociatedDataKey::new(fun));
self.functions_to_initialize.push(fun_index);
}
}
@ -1696,7 +2007,7 @@ impl FunctionStencilBuilder {
///
/// This creates `FunctionStencil` for the function, and adds it to
/// enclosing function if exists.
fn enter<T>(&mut self, fun: &T, syntax_kind: FunctionSyntaxKind)
fn enter<T>(&mut self, fun: &T, syntax_kind: FunctionSyntaxKind) -> FunctionStencilIndex
where
T: SourceLocationAccessor + NodeTypeIdAccessor,
{
@ -1731,6 +2042,8 @@ impl FunctionStencilBuilder {
}
self.function_stack.push(index);
index
}
/// Leave a function, setting its source location.
@ -1834,6 +2147,10 @@ pub struct ScopeDataMapBuilder {
non_global: AssociatedData<ScopeIndex>,
function_stencil_builder: FunctionStencilBuilder,
function_declaration_properties: FunctionDeclarationPropertyMap,
possibly_annex_b_functions: PossiblyAnnexBFunctionList,
}
impl ScopeDataMapBuilder {
@ -1845,6 +2162,8 @@ impl ScopeDataMapBuilder {
global: None,
non_global: AssociatedData::new(),
function_stencil_builder: FunctionStencilBuilder::new(),
function_declaration_properties: FunctionDeclarationPropertyMap::new(),
possibly_annex_b_functions: PossiblyAnnexBFunctionList::new(),
}
}
@ -1885,7 +2204,7 @@ impl ScopeDataMapBuilder {
}
pub fn after_script(&mut self) {
let mut builder = self.builder_stack.pop_global();
let builder = self.builder_stack.pop_global();
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
@ -1893,16 +2212,14 @@ impl ScopeDataMapBuilder {
// Steps 3-6.
// (done in runtime)
// Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
builder.remove_function_names_from_var_names();
// Step 14. NOTE: Annex B.3.3.2 adds additional steps at this point.
//
// FIXME: Implement
// Steps 15-18.
self.scopes
.populate(builder.scope_index, builder.into_scope_data());
// Steps 12-18.
let scope_index = builder.scope_index;
let scope = builder.into_scope_data(
&mut self.scopes,
&mut self.function_declaration_properties,
&mut self.possibly_annex_b_functions,
);
self.scopes.populate(scope_index, scope);
}
pub fn before_block_statement<T>(&mut self, block: &T)
@ -1946,8 +2263,10 @@ impl ScopeDataMapBuilder {
//
// Step 3. Perform
// BlockDeclarationInstantiation(StatementList, blockEnv).
self.scopes
.populate(builder.scope_index, builder.into_scope_data(enclosing));
self.scopes.populate(
builder.scope_index,
builder.into_scope_data(enclosing, &mut self.possibly_annex_b_functions),
);
// Step 6. Set the running execution context's LexicalEnvironment to
// oldEnv.
@ -2014,22 +2333,27 @@ impl ScopeDataMapBuilder {
fun: &T,
is_generator: bool,
is_async: bool,
) where
) -> FunctionStencilIndex
where
T: SourceLocationAccessor + NodeTypeIdAccessor,
{
let fun_index = self.function_stencil_builder.enter(
fun,
FunctionSyntaxKind::function_declaration(is_generator, is_async),
);
match self.builder_stack.innermost_lexical() {
ScopeBuilder::Global(ref mut builder) => builder.declare_function(name, fun),
ScopeBuilder::Block(ref mut builder) => builder.declare_function(name, fun),
ScopeBuilder::FunctionBody(ref mut builder) => builder.declare_function(name, fun),
ScopeBuilder::Global(ref mut builder) => builder.declare_function(name, fun_index),
ScopeBuilder::Block(ref mut builder) => builder.declare_function(name, fun_index),
ScopeBuilder::FunctionBody(ref mut builder) => {
builder.declare_function(name, fun_index)
}
_ => panic!("unexpected lexical for FunctionDeclaration"),
}
self.scope_kind_stack.push(ScopeKind::FunctionName);
self.function_stencil_builder.enter(
fun,
FunctionSyntaxKind::function_declaration(is_generator, is_async),
);
fun_index
}
pub fn after_function_declaration<T>(&mut self, fun: &T)
@ -2247,8 +2571,15 @@ impl ScopeDataMapBuilder {
//
// Step 1. Perform ? FunctionDeclarationInstantiation(functionObject,
// argumentsList).
let scope_data_set =
parameter_scope_builder.into_scope_data_set(enclosing, body_scope_builder);
let scope_data_set = parameter_scope_builder.into_scope_data_set(
&mut self.scopes,
&mut self.function_declaration_properties,
&mut self.possibly_annex_b_functions,
enclosing,
body_scope_builder,
);
self.possibly_annex_b_functions.clear();
self.scopes
.populate(function_scope_index, scope_data_set.function);
@ -2262,6 +2593,7 @@ impl ScopeDataMapBuilder {
pub struct ScopeDataMapAndFunctionStencilList {
pub scope_data_map: ScopeDataMap,
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
pub function_declaration_properties: FunctionDeclarationPropertyMap,
pub functions: FunctionStencilList,
}
@ -2274,6 +2606,7 @@ impl From<ScopeDataMapBuilder> for ScopeDataMapAndFunctionStencilList {
builder.non_global,
),
function_stencil_indices: builder.function_stencil_builder.function_stencil_indices,
function_declaration_properties: builder.function_declaration_properties,
functions: builder.function_stencil_builder.functions,
}
}

65
third_party/rust/jsparagus-scope/src/data.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,65 @@
//! Data generated by scope analysis, and consumed only by emitter
use std::collections::HashMap;
use stencil::function::FunctionStencilIndex;
/// Data associated to a function.
#[derive(Debug)]
pub struct FunctionProperty {
is_annex_b: bool,
}
impl FunctionProperty {
fn is_annex_b_default() -> bool {
false
}
pub fn new() -> Self {
Self {
is_annex_b: Self::is_annex_b_default(),
}
}
pub fn mark_annex_b(&mut self) {
self.is_annex_b = true;
}
pub fn is_annex_b(&self) -> bool {
self.is_annex_b
}
}
/// Map from function to associated data.
#[derive(Debug)]
pub struct FunctionDeclarationPropertyMap {
/// This map is populated lazily, only for functions with non-default
/// property.
props: HashMap<FunctionStencilIndex, FunctionProperty>,
}
impl FunctionDeclarationPropertyMap {
pub fn new() -> Self {
Self {
props: HashMap::new(),
}
}
pub fn mark_annex_b(&mut self, index: FunctionStencilIndex) {
if !self.props.contains_key(&index) {
self.props.insert(index, FunctionProperty::new());
}
self.props
.get_mut(&index)
.expect("Should exist")
.mark_annex_b();
}
pub fn is_annex_b(&self, index: FunctionStencilIndex) -> bool {
if !self.props.contains_key(&index) {
return FunctionProperty::is_annex_b_default();
}
self.props.get(&index).expect("Should exist").is_annex_b()
}
}

1
third_party/rust/jsparagus-scope/src/lib.rs поставляемый
Просмотреть файл

@ -10,6 +10,7 @@
//! describing each scope, binding, and function in the AST.
mod builder;
pub mod data;
pub mod free_name_tracker;
mod pass;

20
third_party/rust/jsparagus-scope/src/pass.rs поставляемый
Просмотреть файл

@ -8,17 +8,20 @@
//! no AST is built. So we try to keep AST use separate from the analysis code.
use crate::builder::{ScopeDataMapAndFunctionStencilList, ScopeDataMapBuilder};
use crate::data::FunctionDeclarationPropertyMap;
use ast::arena;
use ast::associated_data::AssociatedData;
use ast::{types::*, visit::Pass};
use std::collections::HashMap;
use stencil::function::{FunctionStencilIndex, FunctionStencilList};
use stencil::scope::ScopeDataMap;
/// The result of scope analysis.
pub struct ScopePassResult<'alloc> {
pub scope_data_map: ScopeDataMap,
pub function_map: AssociatedData<&'alloc Function<'alloc>>,
pub function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
pub function_declaration_properties: FunctionDeclarationPropertyMap,
pub functions: FunctionStencilList,
}
@ -30,14 +33,14 @@ pub struct ScopePassResult<'alloc> {
#[derive(Debug)]
pub struct ScopePass<'alloc> {
builder: ScopeDataMapBuilder,
function_map: AssociatedData<&'alloc Function<'alloc>>,
function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
}
impl<'alloc> ScopePass<'alloc> {
pub fn new() -> Self {
Self {
builder: ScopeDataMapBuilder::new(),
function_map: AssociatedData::new(),
function_declarations: HashMap::new(),
}
}
}
@ -47,12 +50,14 @@ impl<'alloc> From<ScopePass<'alloc>> for ScopePassResult<'alloc> {
let ScopeDataMapAndFunctionStencilList {
scope_data_map,
function_stencil_indices,
function_declaration_properties,
functions,
} = pass.builder.into();
ScopePassResult {
scope_data_map,
function_map: pass.function_map,
function_declarations: pass.function_declarations,
function_stencil_indices,
function_declaration_properties,
functions,
}
}
@ -121,9 +126,10 @@ impl<'alloc> Pass<'alloc> for ScopePass<'alloc> {
} else {
panic!("FunctionDeclaration should have name");
};
self.builder
.before_function_declaration(name, ast, ast.is_generator, ast.is_async);
self.function_map.insert(ast, ast);
let fun_index =
self.builder
.before_function_declaration(name, ast, ast.is_generator, ast.is_async);
self.function_declarations.insert(fun_index, ast);
}
fn leave_enum_statement_variant_function_declaration(&mut self, ast: &'alloc Function<'alloc>) {

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"f5439990185662ab31de12c07ef0c842438e3207bdfecc4fa6a9e4d4bea8a0d3","src/bytecode_offset.rs":"2aa7ba8c3cfbbd832092e65b599ab1c5a28d784ccc65d9e351bba656421b9a69","src/copy/AsyncFunctionResolveKind.h":"3851ecbb4728257595dd6e900749d1d8e02558574c00424a7ff0e3ca007fa6ec","src/copy/BytecodeFormatFlags.h":"7dc2932321cf7cf874cd92b6d8076ebd4139492730f3ee5a3b6ed7fc57a0c685","src/copy/CheckIsObjectKind.h":"8f0e112396d966c9221a743d353f62671e04cdace7dd49a59898d94ba0f621b7","src/copy/FunctionFlags.h":"4376653f70711d916bc36c2096165f0be9a50c487b9d471821da1cad80daa3a3","src/copy/FunctionPrefixKind.h":"f540a5c646a519b2d61aa27e4be865e08a31438def00ad5ba4ba2982ad1f2275","src/copy/GeneratorAndAsyncKind.h":"301668ce705970a51abfa94f89fd5db29ef5f129525110860e9e9bf7586ef187","src/copy/GeneratorResumeKind.h":"9e3cd9dc9c7f50937c6c45d73ec092dbfd92c4b56818ae6d1504bcd77078d0a6","src/copy/Opcodes.h":"72e0faa4eb0ed4e59ee2205d0ed6734fc4e7383552545d605eef2201e69d4c99","src/copy/SourceNotes.h":"1e467f4e63d6f40a428e257fecd210bd14664516adf75a45cb17ab02ccd65fd8","src/copy/StencilEnums.h":"e5a1db4af868fd65591ed97594f7aa9a4cde79194da0cabd62b34e950b3b10b4","src/copy/Symbol.h":"f68b32e1b7add89931a1fa82a6888ebf6d875d03b05872469de426844532bf33","src/copy/ThrowMsgKind.h":"da805756961d81a2b50aeb391a02fd59a0aa39a9e3eb6aae21b423b15875ab30","src/frame_slot.rs":"b20c81d67c572f20d06d493b211cd3eaa0432a8294541583643b82df3af2f813","src/function.rs":"e0e5e1db70b5d22139aab7c01411eada2c28381b9b6298fa0e507462d0869851","src/gcthings.rs":"6237c13fae9a5cfc67037c6fedf489747db67c38952aad95c322a6b7944211b7","src/lib.rs":"731842a46c397bee8dd06543dab435e8f7465a15e51301de5bca9bc67faa7d36","src/opcode.rs":"b9ebb9f03cebbc731b27cddb5799e34f4af12854a1e89aa459e153e0f087bbeb","src/opcode_info.rs":"a27c6d5602f5ecdcc882a0167614bc7a7754d958124941b4c1c0cdc2b0a894f1","src/regexp.rs":"7436cf545b990bec7dcc51ff28d67deaca9d4ce894468fdad0dd44b25c571cf2","src/result.rs":"0244b908bca220114e05291cca64c5e78edd48af2f0982d9587b4eaed5980eaa","src/scope.rs":"71f5acf81a54a92d8ec9ec1531808a92a3a93c81e09af1a6cd27a1fd23f38a30","src/scope_notes.rs":"9947ba5aba3097321c76adcb5648a478e4a67e088fdc1e01511e51c4ad41a9f3","src/script.rs":"a150a209be11380ecb7a4a36c21c3693961625293882c0563a2294a211a82b99"},"package":null}
{"files":{"Cargo.toml":"f5439990185662ab31de12c07ef0c842438e3207bdfecc4fa6a9e4d4bea8a0d3","src/bytecode_offset.rs":"2aa7ba8c3cfbbd832092e65b599ab1c5a28d784ccc65d9e351bba656421b9a69","src/copy/AsyncFunctionResolveKind.h":"3851ecbb4728257595dd6e900749d1d8e02558574c00424a7ff0e3ca007fa6ec","src/copy/BytecodeFormatFlags.h":"7dc2932321cf7cf874cd92b6d8076ebd4139492730f3ee5a3b6ed7fc57a0c685","src/copy/CheckIsObjectKind.h":"8f0e112396d966c9221a743d353f62671e04cdace7dd49a59898d94ba0f621b7","src/copy/FunctionFlags.h":"4376653f70711d916bc36c2096165f0be9a50c487b9d471821da1cad80daa3a3","src/copy/FunctionPrefixKind.h":"f540a5c646a519b2d61aa27e4be865e08a31438def00ad5ba4ba2982ad1f2275","src/copy/GeneratorAndAsyncKind.h":"301668ce705970a51abfa94f89fd5db29ef5f129525110860e9e9bf7586ef187","src/copy/GeneratorResumeKind.h":"9e3cd9dc9c7f50937c6c45d73ec092dbfd92c4b56818ae6d1504bcd77078d0a6","src/copy/Opcodes.h":"72e0faa4eb0ed4e59ee2205d0ed6734fc4e7383552545d605eef2201e69d4c99","src/copy/SourceNotes.h":"1e467f4e63d6f40a428e257fecd210bd14664516adf75a45cb17ab02ccd65fd8","src/copy/StencilEnums.h":"e5a1db4af868fd65591ed97594f7aa9a4cde79194da0cabd62b34e950b3b10b4","src/copy/Symbol.h":"f68b32e1b7add89931a1fa82a6888ebf6d875d03b05872469de426844532bf33","src/copy/ThrowMsgKind.h":"da805756961d81a2b50aeb391a02fd59a0aa39a9e3eb6aae21b423b15875ab30","src/env_coord.rs":"0be36a1bd307f5586affe0f3046d8b2ab2f5382b41b7b7bfb364b97d16a7c410","src/frame_slot.rs":"b20c81d67c572f20d06d493b211cd3eaa0432a8294541583643b82df3af2f813","src/function.rs":"5547de3c00ea1f8b90845da635a05c10d7a32fce941fcb421a91267feb4998d3","src/gcthings.rs":"6237c13fae9a5cfc67037c6fedf489747db67c38952aad95c322a6b7944211b7","src/lib.rs":"b003e085344277d2987ef492dc513048e8ec83217850a22ba7ca06ac01bc9b5c","src/opcode.rs":"b9ebb9f03cebbc731b27cddb5799e34f4af12854a1e89aa459e153e0f087bbeb","src/opcode_info.rs":"a27c6d5602f5ecdcc882a0167614bc7a7754d958124941b4c1c0cdc2b0a894f1","src/regexp.rs":"7436cf545b990bec7dcc51ff28d67deaca9d4ce894468fdad0dd44b25c571cf2","src/result.rs":"0244b908bca220114e05291cca64c5e78edd48af2f0982d9587b4eaed5980eaa","src/scope.rs":"7727839d8175171ce097a41e1288498b6d7f6b0fda9037f6cf34655baf4bc562","src/scope_notes.rs":"9947ba5aba3097321c76adcb5648a478e4a67e088fdc1e01511e51c4ad41a9f3","src/script.rs":"a150a209be11380ecb7a4a36c21c3693961625293882c0563a2294a211a82b99"},"package":null}

50
third_party/rust/jsparagus-stencil/src/env_coord.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,50 @@
//! (EnvironmentSlot,EnvironmentHops) pair represent the reference to a slot in
//! an environment object in the environment chain.
//!
//! See the SMDOC comment in m-c/js/src/vm/EnvironmentObject.h for the details
//! about environment object and environment chain.
/// Slot in the environmentslot object.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct EnvironmentSlot {
slot: u32,
}
impl EnvironmentSlot {
pub fn new(slot: u32) -> Self {
Self { slot }
}
pub fn next(&mut self) {
self.slot += 1;
}
}
impl From<EnvironmentSlot> for u32 {
fn from(slot: EnvironmentSlot) -> u32 {
slot.slot
}
}
/// The number of environment objects to skip (hop) on the environment chain in
/// order to find the associated environment object.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct EnvironmentHops {
hops: u8,
}
impl EnvironmentHops {
pub fn new(hops: u8) -> Self {
Self { hops }
}
pub fn next(&mut self) {
self.hops += 1;
}
}
impl From<EnvironmentHops> for u8 {
fn from(hops: EnvironmentHops) -> u8 {
hops.hops
}
}

Просмотреть файл

@ -320,6 +320,10 @@ impl FunctionStencil {
self.name = Some(name);
}
pub fn name<'a>(&'a self) -> &'a Option<SourceAtomSetIndex> {
&self.name
}
pub fn set_has_rest(&mut self) {
self.lazy_script_mut().set_has_rest();
}
@ -346,7 +350,7 @@ impl FunctionStencil {
}
/// Index into FunctionStencilList.items.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionStencilIndex {
index: usize,
}
@ -380,6 +384,10 @@ impl FunctionStencilList {
FunctionStencilIndex::new(index)
}
pub fn get<'a>(&'a self, index: FunctionStencilIndex) -> &'a FunctionStencil {
&self.items[usize::from(index)]
}
pub fn get_mut<'a>(&'a mut self, index: FunctionStencilIndex) -> &'a mut FunctionStencil {
&mut self.items[usize::from(index)]
}

Просмотреть файл

@ -1,4 +1,5 @@
pub mod bytecode_offset;
pub mod env_coord;
pub mod frame_slot;
pub mod function;
pub mod gcthings;

Просмотреть файл

@ -10,7 +10,8 @@
//! Each scope contains a list of bindings (`BindingName`).
use crate::frame_slot::FrameSlot;
use ast::associated_data::{AssociatedData, Key as AssociatedDataKey};
use crate::function::FunctionStencilIndex;
use ast::associated_data::AssociatedData;
use ast::source_atom_set::SourceAtomSetIndex;
use ast::source_location_accessor::SourceLocationAccessor;
use ast::type_id::NodeTypeIdAccessor;
@ -71,30 +72,102 @@ impl<'a> BindingIterItem<'a> {
self.name.is_top_level_function
}
pub fn is_closed_over(&self) -> bool {
self.name.is_closed_over
}
pub fn kind(&self) -> BindingKind {
self.kind
}
}
/// Accessor for is_closed_over for both BindingName/Option<BindingName>.
pub trait MaybeBindingName {
fn is_closed_over(&self) -> bool;
}
impl MaybeBindingName for BindingName {
fn is_closed_over(&self) -> bool {
self.is_closed_over
}
}
impl MaybeBindingName for Option<BindingName> {
fn is_closed_over(&self) -> bool {
match self {
Some(b) => b.is_closed_over,
None => false,
}
}
}
#[derive(Debug)]
pub struct BaseScopeData<BindingItemT>
where
BindingItemT: MaybeBindingName,
{
/// Corresponds to `*Scope::Data.{length, trailingNames}.`
/// The layout is defined by *ScopeData structs below, that has
/// this struct.
pub bindings: Vec<BindingItemT>,
pub has_eval: bool,
pub has_with: bool,
}
impl<BindingItemT> BaseScopeData<BindingItemT>
where
BindingItemT: MaybeBindingName,
{
pub fn new(bindings_count: usize) -> Self {
Self {
bindings: Vec::with_capacity(bindings_count),
has_eval: false,
has_with: false,
}
}
pub fn is_all_bindings_closed_over(&self) -> bool {
// `with` and direct `eval` can dynamically access any binding in this
// scope.
self.has_eval || self.has_with
}
/// Returns true if this scope needs to be allocated on heap as
/// EnvironmentObject.
pub fn needs_environment_object(&self) -> bool {
// `with` and direct `eval` can dynamically access bindings in this
// scope.
if self.is_all_bindings_closed_over() {
return true;
}
// If a binding in this scope is closed over by inner function,
// it can be accessed when this frame isn't on the stack.
for binding in &self.bindings {
if binding.is_closed_over() {
return true;
}
}
false
}
}
/// Bindings created in global environment.
///
/// Maps to js::GlobalScope::Data in m-c/js/src/vm/Scope.h.
#[derive(Debug)]
pub struct GlobalScopeData {
/// Bindings are sorted by kind:
///
/// * `base.bindings[0..let_start]` - `var`s
/// * `base.bindings[let_start..const_start]` - `let`s
/// * `base.bindings[const_start..]` - `const`s
pub base: BaseScopeData<BindingName>,
pub let_start: usize,
pub const_start: usize,
/// Corresponds to `GlobalScope::Data.{length, trailingNames}.`
///
/// Bindings are sorted by kind:
///
/// * `bindings[0..let_start]` - `var`s
/// * `bindings[let_start..const_start]` - `let`s
/// * `bindings[const_start..]` - `const`s
pub bindings: Vec<BindingName>,
/// The global functions in this script.
pub functions: Vec<AssociatedDataKey>,
pub functions: Vec<FunctionStencilIndex>,
}
impl GlobalScopeData {
@ -102,14 +175,14 @@ impl GlobalScopeData {
var_count: usize,
let_count: usize,
const_count: usize,
functions: Vec<AssociatedDataKey>,
functions: Vec<FunctionStencilIndex>,
) -> Self {
let capacity = var_count + let_count + const_count;
Self {
base: BaseScopeData::new(capacity),
let_start: var_count,
const_start: var_count + let_count,
bindings: Vec::with_capacity(capacity),
functions,
}
}
@ -136,7 +209,7 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
type Item = BindingIterItem<'a>;
fn next(&mut self) -> Option<BindingIterItem<'a>> {
if self.i == self.data.bindings.len() {
if self.i == self.data.base.bindings.len() {
return None;
}
@ -148,7 +221,7 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
BindingKind::Const
};
let name = &self.data.bindings[self.i];
let name = &self.data.base.bindings[self.i];
self.i += 1;
@ -163,8 +236,8 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
/// in m-c/js/src/frontend/Stencil.h
#[derive(Debug)]
pub struct VarScopeData {
/// Corresponds to VarScope::Data.{length, trailingNames}.
pub bindings: Vec<BindingName>,
/// All bindings are `var`.
pub base: BaseScopeData<BindingName>,
/// The first frame slot of this scope.
///
@ -186,7 +259,7 @@ impl VarScopeData {
let capacity = var_count;
Self {
bindings: Vec::with_capacity(capacity),
base: BaseScopeData::new(capacity),
// Set to the correct value in EmitterScopeStack::enter_lexical.
first_frame_slot: FrameSlot::new(0),
enclosing,
@ -201,10 +274,13 @@ impl VarScopeData {
/// in m-c/js/src/frontend/Stencil.h
#[derive(Debug)]
pub struct LexicalScopeData {
pub const_start: usize,
/// Bindings are sorted by kind:
///
/// * `base.bindings[0..const_start]` - `let`s
/// * `base.bindings[const_start..]` - `const`s
pub base: BaseScopeData<BindingName>,
/// Corresponds to LexicalScope::Data.{length, trailingNames}.
pub bindings: Vec<BindingName>,
pub const_start: usize,
/// The first frame slot of this scope.
///
@ -221,7 +297,7 @@ pub struct LexicalScopeData {
pub enclosing: ScopeIndex,
/// Functions in this scope.
pub functions: Vec<AssociatedDataKey>,
pub functions: Vec<FunctionStencilIndex>,
}
impl LexicalScopeData {
@ -229,13 +305,13 @@ impl LexicalScopeData {
let_count: usize,
const_count: usize,
enclosing: ScopeIndex,
functions: Vec<AssociatedDataKey>,
functions: Vec<FunctionStencilIndex>,
) -> Self {
let capacity = let_count + const_count;
Self {
base: BaseScopeData::new(capacity),
const_start: let_count,
bindings: Vec::with_capacity(capacity),
// Set to the correct value in EmitterScopeStack::enter_lexical.
first_frame_slot: FrameSlot::new(0),
enclosing,
@ -247,7 +323,7 @@ impl LexicalScopeData {
let_count: usize,
const_count: usize,
enclosing: ScopeIndex,
functions: Vec<AssociatedDataKey>,
functions: Vec<FunctionStencilIndex>,
) -> Self {
Self::new(let_count, const_count, enclosing, functions)
}
@ -267,6 +343,49 @@ impl LexicalScopeData {
pub fn iter<'a>(&'a self) -> LexicalBindingIter<'a> {
LexicalBindingIter::new(self)
}
/// Mark a `name` binding originally at `original_binding_index`
/// Annex B function.
///
/// The binding at `original_binding_index` can be different thing
/// if any binding before it is already removed.
pub fn mark_annex_b_function(
&mut self,
name: SourceAtomSetIndex,
original_binding_index: usize,
) {
let binding_index = self.find_binding(name, original_binding_index);
// Lexical function becomes mutable binding.
debug_assert!(binding_index < self.const_start);
self.const_start -= 1;
self.base.bindings.remove(binding_index);
}
/// Find the binding `name`, originally stored at `original_binding_index`.
/// If the binding at `original_binding_index` isn't `name`, look for
/// `name`.
/// Panics if the binding with given `name` doesn't exist.
fn find_binding(&self, name: SourceAtomSetIndex, original_binding_index: usize) -> usize {
if original_binding_index < self.base.bindings.len() {
let binding = &self.base.bindings[original_binding_index];
if binding.name == name {
return original_binding_index;
}
}
// TODO: Search from `original_binding_index` to 0,
// instead of iterating all items.
for (i, binding) in self.base.bindings.iter().enumerate() {
if binding.name == name {
return i;
}
}
panic!("The binding should exist");
}
}
/// Corresponds to the iteration part of js::BindingIter
@ -286,7 +405,7 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
type Item = BindingIterItem<'a>;
fn next(&mut self) -> Option<BindingIterItem<'a>> {
if self.i == self.data.bindings.len() {
if self.i == self.data.base.bindings.len() {
return None;
}
@ -296,7 +415,7 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
BindingKind::Const
};
let name = &self.data.bindings[self.i];
let name = &self.data.base.bindings[self.i];
self.i += 1;
@ -311,15 +430,26 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
/// in m-c/js/src/frontend/Stencil.h
#[derive(Debug)]
pub struct FunctionScopeData {
has_parameter_exprs: bool,
non_positional_formal_start: usize,
var_start: usize,
/// Corresponds to FunctionScope::Data.{length, trailingNames}.
/// Bindings are sorted by kind:
///
/// * `base.bindings[0..non_positional_formal_start]` -
/// positional foparameters:
/// - single binding parameter with/without default
/// - single binding rest parameter
/// * `base.bindings[non_positional_formal_start..var_start]` -
/// non positional parameters:
/// - destructuring parameter
/// - destructuring rest parameter
/// * `base.bindings[var_start..]` - `var`s
///
/// Given positional parameters range can have null slot for destructuring,
/// this is Vec of Option<BindingName>, instead of BindingName like others.
pub bindings: Vec<Option<BindingName>>,
/// use Vec of Option<BindingName>, instead of BindingName like others.
pub base: BaseScopeData<Option<BindingName>>,
has_parameter_exprs: bool,
non_positional_formal_start: usize,
var_start: usize,
/// The first frame slot of this scope.
///
@ -347,10 +477,10 @@ impl FunctionScopeData {
let capacity = positional_parameter_count + non_positional_formal_start + var_count;
Self {
base: BaseScopeData::new(capacity),
has_parameter_exprs,
non_positional_formal_start: positional_parameter_count,
var_start: positional_parameter_count + non_positional_formal_start,
bindings: Vec::with_capacity(capacity),
// Set to the correct value in EmitterScopeStack::enter_function.
first_frame_slot: FrameSlot::new(0),
enclosing,
@ -439,7 +569,7 @@ impl ScopeDataList {
.expect("Should be populated")
}
fn get_mut(&mut self, index: ScopeIndex) -> &mut ScopeData {
pub fn get_mut(&mut self, index: ScopeIndex) -> &mut ScopeData {
self.scopes[usize::from(index)]
.as_mut()
.expect("Should be populated")
@ -500,6 +630,13 @@ impl ScopeDataMap {
.clone()
}
pub fn get_lexical_at(&self, index: ScopeIndex) -> &LexicalScopeData {
match self.scopes.get(index) {
ScopeData::Lexical(scope) => scope,
_ => panic!("Unexpected scope data for lexical"),
}
}
pub fn get_lexical_at_mut(&mut self, index: ScopeIndex) -> &mut LexicalScopeData {
match self.scopes.get_mut(index) {
ScopeData::Lexical(scope) => scope,

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -546,7 +546,7 @@ def generate_emit_methods(out_f, opcodes, types):
assert len(params) == 1
assert params[0][0] == 'u32'
params[0] = ('GCThingIndex', params[0][1])
elif 'JOF_OBJECT' in opcode.format_:
elif 'JOF_OBJECT' in opcode.format_ or 'JOF_SCOPE' in opcode.format_:
assert len(params) == 1
assert params[0][0] == 'u32'
params[0] = ('GCThingIndex', params[0][1])