// 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 } extern enum VariableAllocationInfo extends uint32 { NONE, STACK, CONTEXT, UNUSED } extern enum VariableMode extends uint32 { kLet, kConst, 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; } const kMaxInlinedLocalNamesSize: constexpr int32 generates 'kScopeInfoMaxInlinedLocalNamesSize'; @generateBodyDescriptor extern class ScopeInfo extends HeapObject { const flags: SmiTagged; // 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; // 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(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(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; // 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::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.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, the // number of MODULE-allocated variables, and the metadata of those // variables. For non-module scopes it is empty. module_info? [flags.scope_type == ScopeType::MODULE_SCOPE]: SourceTextModuleInfo; const module_variable_count? [flags.scope_type == ScopeType::MODULE_SCOPE]: Smi; 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(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(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; } }