blob: 64647912f393327ac931f368b4ba8532948cb4aa [file]
// 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.
// Start of top-level scopes.
SCRIPT_SCOPE,
REPL_MODE_SCOPE,
EVAL_SCOPE,
MODULE_SCOPE,
// End of top-level scopes.
CLASS_SCOPE,
FUNCTION_SCOPE,
CATCH_SCOPE,
BLOCK_SCOPE,
WITH_SCOPE,
SHADOW_REALM_SCOPE
}
extern enum VariableAllocationInfo extends uint32 {
NONE,
STACK,
CONTEXT,
UNUSED
}
extern enum VariableMode extends int32 {
kLet,
kConst,
kUsing,
kAwaitUsing,
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.
@cppScope('ScopeInfo')
bitfield struct ScopeFlags extends uint32 {
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;
allocates_arguments: 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;
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;
// Indicates that the context has a context extension slot.
has_context_extension_slot: bool: 1 bit;
// Indicates that there are contexts with a context extension (meaningful
// only for contexts with "sloppy_eval_can_extend_vars" flag set).
some_context_has_extension: bool: 1 bit;
is_hidden: bool: 1 bit;
is_wrapped_function: bool: 1 bit;
has_context_cells: bool: 1 bit;
is_hoisted_in_context: bool: 1 bit;
}
struct PositionInfo {
start: Smi;
end: Smi;
}
// LINT.IfChange(ScopeInfoStructs)
struct FunctionVariableInfo {
name: String|Zero;
context_or_stack_slot_index: Smi;
}
@cppScope('ScopeInfo')
bitfield struct VariableProperties extends uint31 {
variable_mode: VariableMode: 4 bit;
init_flag: InitializationFlag: 1 bit;
maybe_assigned_flag: MaybeAssignedFlag: 1 bit;
is_parameter: bool: 1 bit;
parameter_number_or_position: uint32: 16 bit;
is_static_flag: IsStaticFlag: 1 bit;
}
struct ModuleVariable {
name: String;
index: Smi;
properties: SmiTagged<VariableProperties>;
}
// LINT.ThenChange(src/objects/scope-info.h)
const kMaxInlinedLocalNamesSize:
constexpr int32 generates 'kScopeInfoMaxInlinedLocalNamesSize';
@cppObjectLayoutDefinition
extern class ScopeInfo extends HeapObject {
@cppRelaxedLoad @cppRelaxedStore const flags: ScopeFlags;
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
// 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 two slots with a) the startPosition and b) the endPosition.
position_info: PositionInfo;
// 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 name of the class variable or the slot index if locals are inlined.
saved_class_variable_info?[flags.has_saved_class_variable]: Smi|Name;
// 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;
outer_scope_info?[flags.has_outer_scope_info]: ScopeInfo;
// 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;
// Maps a module variable's name to its index in module_variables. Only
// present when a module scope has enough module variables that a linear
// scan in ModuleIndex() would be costly (same threshold as the context
// local names hashtable).
module_variables_hashtable?
[flags.scope_type == ScopeType::MODULE_SCOPE ?
kMaxInlinedLocalNamesSize <= Convert<intptr>(module_variable_count) :
false]: NameToIndexHashTable;
// EmptyContextExtension-dependent code objects.
dependent_code?[flags.sloppy_eval_can_extend_vars]: DependentCode;
// For the first 31 formal parameters, these bits will be set if they are
// explicitly unused within the body of the function.
const unused_parameter_bits?
[flags.scope_type == ScopeType::FUNCTION_SCOPE]: Smi;
}
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;
}
}
@export
macro GetFunctionContextSlotInitialValue(
scopeInfo: ScopeInfo, index: intptr): Object {
dcheck(index < Convert<intptr>(scopeInfo.context_local_count));
const info = scopeInfo.context_local_infos[index];
if (info.maybe_assigned_flag != MaybeAssignedFlag::kNotAssigned) {
return UndefinedContextCellConstant();
}
return Undefined;
}