| // Copyright 2019 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| extern macro EmptyScopeInfoConstant(): ScopeInfo; |
| const kEmptyScopeInfo: ScopeInfo = EmptyScopeInfoConstant(); |
| |
| extern enum ScopeType extends uint32 { |
| // The empty scope info for builtins and NativeContexts is allocated |
| // in a way that it gets the first scope type in line, see |
| // Heap::CreateInitialMaps(). It's always guarded with the IsEmpty |
| // bit, so it doesn't matter what scope type it gets. |
| CLASS_SCOPE, |
| EVAL_SCOPE, |
| FUNCTION_SCOPE, |
| MODULE_SCOPE, |
| SCRIPT_SCOPE, |
| CATCH_SCOPE, |
| BLOCK_SCOPE, |
| WITH_SCOPE, |
| SHADOW_REALM_SCOPE |
| } |
| |
| extern enum VariableAllocationInfo extends uint32 { |
| NONE, |
| STACK, |
| CONTEXT, |
| UNUSED |
| } |
| |
| extern enum VariableMode extends uint32 { |
| kLet, |
| kConst, |
| kUsing, |
| kVar, |
| kTemporary, |
| kDynamic, |
| kDynamicGlobal, |
| kDynamicLocal, |
| kPrivateMethod, |
| kPrivateSetterOnly, |
| kPrivateGetterOnly, |
| kPrivateGetterAndSetter |
| } |
| |
| extern enum InitializationFlag extends uint32 { |
| kNeedsInitialization, |
| kCreatedInitialized |
| } |
| |
| extern enum IsStaticFlag extends uint32 { kNotStatic, kStatic } |
| |
| extern enum MaybeAssignedFlag extends uint32 { kNotAssigned, kMaybeAssigned } |
| |
| // Properties of scopes. |
| bitfield struct ScopeFlags extends uint31 { |
| scope_type: ScopeType: 4 bit; |
| sloppy_eval_can_extend_vars: bool: 1 bit; |
| language_mode: LanguageMode: 1 bit; |
| declaration_scope: bool: 1 bit; |
| receiver_variable: VariableAllocationInfo: 2 bit; |
| // In class scope, this indicates whether the class has a private brand. |
| // In constructor scope, this indicates whether the constructor needs |
| // private brand initialization. |
| class_scope_has_private_brand: bool: 1 bit; |
| has_saved_class_variable: bool: 1 bit; |
| has_new_target: bool: 1 bit; |
| // TODO(cbruni): Combine with function variable field when only storing the |
| // function name. |
| function_variable: VariableAllocationInfo: 2 bit; |
| has_inferred_function_name: bool: 1 bit; |
| is_asm_module: bool: 1 bit; |
| has_simple_parameters: bool: 1 bit; |
| function_kind: FunctionKind: 5 bit; |
| has_outer_scope_info: bool: 1 bit; |
| is_debug_evaluate_scope: bool: 1 bit; |
| force_context_allocation: bool: 1 bit; |
| private_name_lookup_skips_outer_class: bool: 1 bit; |
| has_context_extension_slot: bool: 1 bit; |
| is_repl_mode_scope: bool: 1 bit; |
| has_locals_block_list: bool: 1 bit; |
| is_empty: bool: 1 bit; |
| } |
| |
| struct PositionInfo { |
| start: Smi; |
| end: Smi; |
| } |
| |
| struct FunctionVariableInfo { |
| name: String|Zero; |
| context_or_stack_slot_index: Smi; |
| } |
| |
| bitfield struct VariableProperties extends uint31 { |
| variable_mode: VariableMode: 4 bit; |
| init_flag: InitializationFlag: 1 bit; |
| maybe_assigned_flag: MaybeAssignedFlag: 1 bit; |
| parameter_number: uint32: 16 bit; |
| is_static_flag: IsStaticFlag: 1 bit; |
| } |
| |
| struct ModuleVariable { |
| name: String; |
| index: Smi; |
| properties: SmiTagged<VariableProperties>; |
| } |
| |
| const kMaxInlinedLocalNamesSize: |
| constexpr int32 generates 'kScopeInfoMaxInlinedLocalNamesSize'; |
| |
| @generateBodyDescriptor |
| extern class ScopeInfo extends HeapObject { |
| const flags: SmiTagged<ScopeFlags>; |
| |
| // The number of parameters. For non-function scopes this is 0. |
| parameter_count: Smi; |
| |
| // The number of non-parameter and parameter variables allocated in the |
| // context. |
| const context_local_count: Smi; |
| |
| // This value must be before any object values, so that the GC can correctly |
| // determine the size of a partially initialized object during |
| // deserialization. |
| const module_variable_count? |
| [flags.scope_type == ScopeType::MODULE_SCOPE]: Smi; |
| |
| // Contains the names of inlined local variables and parameters that are |
| // allocated in the context. They are stored in increasing order of the |
| // context slot index starting with Context::MIN_CONTEXT_SLOTS. |
| context_local_names[Convert<intptr>(context_local_count) < kMaxInlinedLocalNamesSize ? context_local_count : 0]: |
| String; |
| |
| // Contains a hash_map from local names to context slot index. |
| // This is only used when local names are not inlined in the scope info. |
| context_local_names_hashtable? |
| [kMaxInlinedLocalNamesSize <= Convert<intptr>(context_local_count)]: |
| NameToIndexHashTable; |
| |
| // Contains the variable modes and initialization flags corresponding to |
| // the context locals in ContextLocalNames. |
| context_local_infos[context_local_count]: SmiTagged<VariableProperties>; |
| |
| // If the scope is a class scope and it has static private methods that |
| // may be accessed directly or through eval, one slot is reserved to hold |
| // the offset in the field storage of the hash table (or the slot index if |
| // local names are inlined) for the class variable. |
| saved_class_variable_info?[flags.has_saved_class_variable]: Smi; |
| |
| // If the scope belongs to a named function expression this part contains |
| // information about the function variable. It always occupies two array |
| // slots: a. The name of the function variable. |
| // b. The context or stack slot index for the variable. |
| function_variable_info? |
| [flags.function_variable != |
| FromConstexpr<VariableAllocationInfo>(VariableAllocationInfo::NONE)]: |
| FunctionVariableInfo; |
| |
| inferred_function_name?[flags.has_inferred_function_name]: String|Undefined; |
| |
| // Contains two slots with a) the startPosition and b) the endPosition if |
| // the scope belongs to a function or script. |
| position_info? |
| [flags.scope_type == ScopeType::FUNCTION_SCOPE || |
| flags.scope_type == ScopeType::SCRIPT_SCOPE || |
| flags.scope_type == ScopeType::EVAL_SCOPE || |
| flags.scope_type == ScopeType::MODULE_SCOPE || |
| flags.scope_type == ScopeType::SHADOW_REALM_SCOPE || |
| (flags.is_empty ? false : flags.scope_type == ScopeType::CLASS_SCOPE)]: |
| PositionInfo; |
| |
| outer_scope_info?[flags.has_outer_scope_info]: ScopeInfo|TheHole; |
| |
| // List of stack allocated local variables. Used by debug evaluate to properly |
| // abort variable lookup when a name clashes with a stack allocated local that |
| // can't be materialized. |
| locals_block_list?[flags.has_locals_block_list]: HashTable; |
| |
| // For a module scope, this part contains the SourceTextModuleInfo and the |
| // metadata of module-allocated variables. For non-module scopes it is empty. |
| module_info? |
| [flags.scope_type == ScopeType::MODULE_SCOPE]: SourceTextModuleInfo; |
| module_variables[flags.scope_type == ScopeType::MODULE_SCOPE ? module_variable_count : 0]: |
| ModuleVariable; |
| } |
| |
| extern macro NameToIndexHashTableLookup( |
| NameToIndexHashTable, Name): intptr labels NotFound; |
| |
| macro IndexOfInlinedLocalName( |
| scopeInfo: ScopeInfo, name: Name): intptr labels NotFound { |
| const count: intptr = Convert<intptr>(scopeInfo.context_local_count); |
| for (let i: intptr = 0; i < count; ++i) { |
| if (TaggedEqual(name, scopeInfo.context_local_names[i])) { |
| return i; |
| } |
| } |
| goto NotFound; |
| } |
| |
| // Returns the index of the named local in a ScopeInfo. |
| // Assumes that the given name is internalized; uses pointer comparisons. |
| @export |
| macro IndexOfLocalName( |
| scopeInfo: ScopeInfo, name: Name): intptr labels NotFound { |
| const count: intptr = Convert<intptr>(scopeInfo.context_local_count); |
| if (count < kMaxInlinedLocalNamesSize) { |
| return IndexOfInlinedLocalName(scopeInfo, name) otherwise goto NotFound; |
| } else { |
| return NameToIndexHashTableLookup( |
| scopeInfo.context_local_names_hashtable, name) otherwise goto NotFound; |
| } |
| } |