/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/objects/scope-info.cc
1 391 строка
52 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2011 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. #include "src/objects/scope-info.h" #include <stdlib.h> #include "src/ast/scopes.h" #include "src/ast/variables.h" #include "src/init/bootstrapper.h" #include "src/objects/module-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/scope-info-inl.h" #include "src/objects/string-set-inl.h" #include "src/roots/roots.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { namespace { bool NameToIndexHashTableEquals(Tagged<NameToIndexHashTable> a, Tagged<NameToIndexHashTable> b) { if (a->Capacity() != b->Capacity()) return false; if (a->NumberOfElements() != b->NumberOfElements()) return false; InternalIndex max(a->Capacity()); InternalIndex entry(0); while (entry < max) { Tagged<Object> key_a = a->KeyAt(entry); Tagged<Object> key_b = b->KeyAt(entry); if (key_a != key_b) return false; Tagged<Object> value_a = a->ValueAt(entry); Tagged<Object> value_b = b->ValueAt(entry); if (value_a != value_b) return false; } return true; } } // namespace // TODO(crbug.com/401059828): make it DEBUG only, once investigation is over. bool ScopeInfo::Equals(Tagged<ScopeInfo> other, bool is_live_edit_compare, int* out_last_checked_field) const { if (length() != other->length()) return false; if (Flags() != other->Flags()) return false; for (int index = 0; index < length(); ++index) { if (out_last_checked_field) *out_last_checked_field = index; if (index == kFlags) continue; if (is_live_edit_compare && ((index >= kPositionInfoStart && index <= kPositionInfoEnd) || index == InferredFunctionNameIndex())) { continue; } Tagged<Object> entry = get(index); Tagged<Object> other_entry = other->get(index); if (IsSmi(entry)) { if (entry != other_entry) return false; } else { if (Cast<HeapObject>(entry)->map()->instance_type() != Cast<HeapObject>(other_entry)->map()->instance_type()) { return false; } if (IsString(entry)) { if (!Cast<String>(entry)->Equals(Cast<String>(other_entry))) { return false; } } else if (IsScopeInfo(entry)) { if (!is_live_edit_compare && !Cast<ScopeInfo>(entry)->Equals( Cast<ScopeInfo>(other_entry), false)) { return false; } } else if (IsSourceTextModuleInfo(entry)) { if (!is_live_edit_compare && !Cast<SourceTextModuleInfo>(entry)->Equals( Cast<SourceTextModuleInfo>(other_entry))) { return false; } } else if (IsOddball(entry)) { if (Cast<Oddball>(entry)->kind() != Cast<Oddball>(other_entry)->kind()) { return false; } } else if (IsDependentCode(entry)) { DCHECK(IsDependentCode(other_entry)); // Ignore the dependent code field since all the code have to be // deoptimized anyway in case of a live-edit. } else if (IsNameToIndexHashTable(entry)) { if (!NameToIndexHashTableEquals( Cast<NameToIndexHashTable>(entry), Cast<NameToIndexHashTable>(other_entry))) { return false; } } else { UNREACHABLE(); } } } return true; } // static template <typename IsolateT> Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope, MaybeDirectHandle<ScopeInfo> outer_scope) { // Collect variables. int context_local_count = 0; int module_vars_count = 0; // Stack allocated block scope variables are allocated in the parent // declaration scope, but are recorded in the block scope's scope info. First // slot index indicates at which offset a particular scope starts in the // parent declaration scope. for (Variable* var : *scope->locals()) { switch (var->location()) { case VariableLocation::CONTEXT: case VariableLocation::REPL_GLOBAL: context_local_count++; break; case VariableLocation::MODULE: module_vars_count++; break; default: break; } } // Determine use and location of the "this" binding if it is present. VariableAllocationInfo receiver_info; if (scope->is_declaration_scope() && scope->AsDeclarationScope()->has_this_declaration()) { Variable* var = scope->AsDeclarationScope()->receiver(); if (!var->is_used()) { receiver_info = VariableAllocationInfo::UNUSED; } else if (var->IsContextSlot()) { receiver_info = VariableAllocationInfo::CONTEXT; } else { DCHECK(var->IsParameter()); receiver_info = VariableAllocationInfo::STACK; } } else { receiver_info = VariableAllocationInfo::NONE; } DCHECK(module_vars_count == 0 || scope->is_module_scope()); // Make sure we allocate the correct amount. DCHECK_EQ(scope->ContextLocalCount(), context_local_count); // If the number of locals is small, we inline directly // in the scope info object. bool has_inlined_local_names = context_local_count < kScopeInfoMaxInlinedLocalNamesSize; const bool allocates_arguments = scope->is_function_scope() && scope->AsDeclarationScope()->arguments() != nullptr; // TODO(cbruni): Don't always waste a field for the inferred name. const bool has_inferred_function_name = scope->is_function_scope(); // Determine use and location of the function variable if it is present. VariableAllocationInfo function_name_info; if (scope->is_function_scope()) { if (scope->AsDeclarationScope()->function_var() != nullptr) { Variable* var = scope->AsDeclarationScope()->function_var(); if (!var->is_used()) { function_name_info = VariableAllocationInfo::UNUSED; } else if (var->IsContextSlot()) { function_name_info = VariableAllocationInfo::CONTEXT; } else { DCHECK(var->IsStackLocal()); function_name_info = VariableAllocationInfo::STACK; } } else { // Always reserve space for the debug name in the scope info. function_name_info = VariableAllocationInfo::UNUSED; } } else if (scope->is_module_scope() || scope->is_script_scope() || scope->is_eval_scope()) { // Always reserve space for the debug name in the scope info. function_name_info = VariableAllocationInfo::UNUSED; } else { function_name_info = VariableAllocationInfo::NONE; } const bool has_brand = scope->is_class_scope() ? scope->AsClassScope()->brand() != nullptr : scope->IsConstructorScope() && scope->AsDeclarationScope()->class_scope_has_private_brand(); const bool should_save_class_variable = scope->is_class_scope() ? scope->AsClassScope()->should_save_class_variable() : false; const bool has_function_name = function_name_info != VariableAllocationInfo::NONE; const int parameter_count = scope->is_declaration_scope() ? scope->AsDeclarationScope()->num_parameters() : 0; const bool has_outer_scope_info = !outer_scope.is_null(); DirectHandle<SourceTextModuleInfo> module_info; if (scope->is_module_scope()) { module_info = SourceTextModuleInfo::New(isolate, zone, scope->AsModuleScope()->module()); } // Make sure the Fields enum agrees with Torque-generated offsets. static_assert(OffsetOfElementAt(kFlags) == kFlagsOffset); static_assert(OffsetOfElementAt(kParameterCount) == kParameterCountOffset); static_assert(OffsetOfElementAt(kContextLocalCount) == kContextLocalCountOffset); FunctionKind function_kind = FunctionKind::kNormalFunction; bool sloppy_eval_can_extend_vars = false; if (scope->is_declaration_scope()) { function_kind = scope->AsDeclarationScope()->function_kind(); sloppy_eval_can_extend_vars = scope->AsDeclarationScope()->sloppy_eval_can_extend_vars(); } DCHECK_IMPLIES(sloppy_eval_can_extend_vars, scope->HasContextExtensionSlot()); const int local_names_container_size = has_inlined_local_names ? context_local_count : 1; const int has_dependent_code = sloppy_eval_can_extend_vars; const int length = kVariablePartIndex + local_names_container_size + context_local_count + (should_save_class_variable ? 1 : 0) + (has_function_name ? kFunctionNameEntries : 0) + (has_inferred_function_name ? 1 : 0) + (has_outer_scope_info ? 1 : 0) + (scope->is_module_scope() ? 2 + kModuleVariableEntryLength * module_vars_count : 0) + (has_dependent_code ? 1 : 0) + (scope->is_function_scope() ? 1 : 0); // Create hash table if local names are not inlined. Handle<NameToIndexHashTable> local_names_hashtable; if (!has_inlined_local_names) { local_names_hashtable = NameToIndexHashTable::New( isolate, context_local_count, AllocationType::kOld); } Handle<ScopeInfo> scope_info_handle = isolate->factory()->NewScopeInfo(length); int index = kVariablePartIndex; { DisallowGarbageCollection no_gc; Tagged<ScopeInfo> scope_info = *scope_info_handle; WriteBarrierModeScope mode = scope_info->GetWriteBarrierMode(no_gc); bool has_simple_parameters = false; bool is_asm_module = false; if (scope->is_function_scope()) { DeclarationScope* function_scope = scope->AsDeclarationScope(); has_simple_parameters = function_scope->has_simple_parameters(); #if V8_ENABLE_WEBASSEMBLY is_asm_module = function_scope->is_asm_module(); #endif // V8_ENABLE_WEBASSEMBLY } // Encode the flags. uint32_t flags = ScopeTypeBits::encode(scope->scope_type()) | SloppyEvalCanExtendVarsBit::encode(sloppy_eval_can_extend_vars) | LanguageModeBit::encode(scope->language_mode()) | DeclarationScopeBit::encode(scope->is_declaration_scope()) | ReceiverVariableBits::encode(receiver_info) | ClassScopeHasPrivateBrandBit::encode(has_brand) | HasSavedClassVariableBit::encode(should_save_class_variable) | AllocatesArgumentsBit::encode(allocates_arguments) | FunctionVariableBits::encode(function_name_info) | HasInferredFunctionNameBit::encode(has_inferred_function_name) | IsAsmModuleBit::encode(is_asm_module) | HasSimpleParametersBit::encode(has_simple_parameters) | FunctionKindBits::encode(function_kind) | HasOuterScopeInfoBit::encode(has_outer_scope_info) | IsDebugEvaluateScopeBit::encode(false) | ForceContextAllocationBit::encode( scope->ForceContextForLanguageMode()) | PrivateNameLookupSkipsOuterClassBit::encode( scope->private_name_lookup_skips_outer_class()) | HasContextExtensionSlotBit::encode(scope->HasContextExtensionSlot()) | IsHiddenBit::encode(scope->is_hidden()) | IsWrappedFunctionBit::encode(scope->is_wrapped_function()) | HasContextCellsBit::encode(scope->has_context_cells()); scope_info->set_flags(flags, kRelaxedStore); scope_info->set_parameter_count(parameter_count); scope_info->set_context_local_count(context_local_count); scope_info->set_position_info_start(scope->start_position()); scope_info->set_position_info_end(scope->end_position()); if (scope->is_module_scope()) { scope_info->set_module_variable_count(module_vars_count); ++index; } if (!has_inlined_local_names) { scope_info->set_context_local_names_hashtable(*local_names_hashtable); } // Add context locals' names and info, module variables' names and info. // Context locals are added using their index. int context_local_base = index; int context_local_info_base = context_local_base + local_names_container_size; int module_var_entry = scope_info->ModuleVariablesIndex(); for (Variable* var : *scope->locals()) { switch (var->location()) { case VariableLocation::CONTEXT: case VariableLocation::REPL_GLOBAL: { // Due to duplicate parameters, context locals aren't guaranteed to // come in order. int local_index = var->index() - scope->ContextHeaderLength(); DCHECK_LE(0, local_index); DCHECK_LT(local_index, context_local_count); uint32_t info = VariableModeBits::encode(var->mode()) | InitFlagBit::encode(var->initialization_flag()) | MaybeAssignedFlagBit::encode(var->maybe_assigned()) | ParameterNumberBits::encode(ParameterNumberBits::kMax) | IsStaticFlagBit::encode(var->is_static_flag()); if (has_inlined_local_names) { scope_info->set(context_local_base + local_index, *var->name(), *mode); } else { Handle<NameToIndexHashTable> new_table = NameToIndexHashTable::Add( isolate, local_names_hashtable, var->name(), local_index); DCHECK_EQ(*new_table, *local_names_hashtable); USE(new_table); } scope_info->set(context_local_info_base + local_index, Smi::FromInt(info)); break; } case VariableLocation::MODULE: { scope_info->set( module_var_entry + TorqueGeneratedModuleVariableOffsets::kNameOffset / kTaggedSize, *var->name(), *mode); scope_info->set( module_var_entry + TorqueGeneratedModuleVariableOffsets::kIndexOffset / kTaggedSize, Smi::FromInt(var->index())); uint32_t properties = VariableModeBits::encode(var->mode()) | InitFlagBit::encode(var->initialization_flag()) | MaybeAssignedFlagBit::encode(var->maybe_assigned()) | ParameterNumberBits::encode(ParameterNumberBits::kMax) | IsStaticFlagBit::encode(var->is_static_flag()); scope_info->set( module_var_entry + TorqueGeneratedModuleVariableOffsets::kPropertiesOffset / kTaggedSize, Smi::FromInt(properties)); module_var_entry += kModuleVariableEntryLength; break; } default: break; } } if (scope->is_declaration_scope()) { // Mark contexts slots with the parameter number they represent. We walk // the list of parameters. That can include duplicate entries if a // parameter name is repeated. By walking upwards, we'll automatically // mark the context slot with the highest parameter number that uses this // variable. That will be the parameter number that is represented by the // context slot. All lower parameters will only be available on the stack // through the arguments object. for (int i = 0; i < parameter_count; i++) { Variable* parameter = scope->AsDeclarationScope()->parameter(i); if (parameter->location() != VariableLocation::CONTEXT) continue; int param_index = parameter->index() - scope->ContextHeaderLength(); int info_index = context_local_info_base + param_index; int info = Smi::ToInt(scope_info->get(info_index)); info = ParameterNumberBits::update(info, i); scope_info->set(info_index, Smi::FromInt(info)); } } // Advance past local names and local names info. index += local_names_container_size + context_local_count; DCHECK_EQ(index, scope_info->SavedClassVariableInfoIndex()); // If the scope is a class scope and has used static private methods, // save context slot index if locals are inlined, otherwise save the name. if (should_save_class_variable) { Variable* class_variable = scope->AsClassScope()->class_variable(); DCHECK_EQ(class_variable->location(), VariableLocation::CONTEXT); if (has_inlined_local_names) { scope_info->set(index++, Smi::FromInt(class_variable->index())); } else { scope_info->set(index++, *class_variable->name()); } } // If present, add the function variable name and its index. DCHECK_EQ(index, scope_info->FunctionVariableInfoIndex()); if (has_function_name) { Variable* var = scope->AsDeclarationScope()->function_var(); int var_index = -1; Tagged<Object> name = Smi::zero(); if (var != nullptr) { var_index = var->index(); name = *var->name(); } scope_info->set(index++, name, *mode); scope_info->set(index++, Smi::FromInt(var_index)); DCHECK(function_name_info != VariableAllocationInfo::CONTEXT || var_index == scope_info->ContextLength() - 1); } DCHECK_EQ(index, scope_info->InferredFunctionNameIndex()); if (has_inferred_function_name) { // The inferred function name is taken from the SFI. index++; } // If present, add the outer scope info. DCHECK_EQ(index, scope_info->OuterScopeInfoIndex()); if (has_outer_scope_info) { scope_info->set(index++, *outer_scope.ToHandleChecked(), *mode); } // Module-specific information (only for module scopes). if (scope->is_module_scope()) { DCHECK_EQ(index, scope_info->ModuleInfoIndex()); scope_info->set(index++, *module_info); DCHECK_EQ(index, scope_info->ModuleVariablesIndex()); // The variable entries themselves have already been written above. index += kModuleVariableEntryLength * module_vars_count; } DCHECK_EQ(index, scope_info->DependentCodeIndex()); if (has_dependent_code) { ReadOnlyRoots roots(isolate); scope_info->set(index++, DependentCode::empty_dependent_code(roots)); } DCHECK_EQ(index, scope_info->UnusedParameterBitsIndex()); if (scope->is_function_scope()) { uint32_t unused_parameter_bits = 0; auto func_scope = scope->AsDeclarationScope(); int count = std::min(31, func_scope->num_parameters()); for (int i = 0; i < count; ++i) { bool unused = !func_scope->parameter(i)->is_used(); unused_parameter_bits |= static_cast<uint32_t>(unused) << i; } scope_info->set(index++, Smi::From31BitPattern(unused_parameter_bits)); } } DCHECK_EQ(index, scope_info_handle->length()); DCHECK_EQ(length, scope_info_handle->length()); DCHECK_EQ(parameter_count, scope_info_handle->ParameterCount()); DCHECK_EQ(scope->num_heap_slots(), scope_info_handle->ContextLength()); return scope_info_handle; } template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<ScopeInfo> ScopeInfo::Create( Isolate* isolate, Zone* zone, Scope* scope, MaybeDirectHandle<ScopeInfo> outer_scope); template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<ScopeInfo> ScopeInfo::Create( LocalIsolate* isolate, Zone* zone, Scope* scope, MaybeDirectHandle<ScopeInfo> outer_scope); // static DirectHandle<ScopeInfo> ScopeInfo::CreateForWithScope( Isolate* isolate, MaybeDirectHandle<ScopeInfo> outer_scope) { const bool has_outer_scope_info = !outer_scope.is_null(); const int length = kVariablePartIndex + (has_outer_scope_info ? 1 : 0); Factory* factory = isolate->factory(); DirectHandle<ScopeInfo> scope_info = factory->NewScopeInfo(length); // Encode the flags. uint32_t flags = ScopeTypeBits::encode(WITH_SCOPE) | SloppyEvalCanExtendVarsBit::encode(false) | LanguageModeBit::encode(LanguageMode::kSloppy) | DeclarationScopeBit::encode(false) | ReceiverVariableBits::encode(VariableAllocationInfo::NONE) | ClassScopeHasPrivateBrandBit::encode(false) | HasSavedClassVariableBit::encode(false) | AllocatesArgumentsBit::encode(false) | FunctionVariableBits::encode(VariableAllocationInfo::NONE) | IsAsmModuleBit::encode(false) | HasSimpleParametersBit::encode(true) | FunctionKindBits::encode(FunctionKind::kNormalFunction) | HasOuterScopeInfoBit::encode(has_outer_scope_info) | IsDebugEvaluateScopeBit::encode(false) | ForceContextAllocationBit::encode(false) | PrivateNameLookupSkipsOuterClassBit::encode(false) | HasContextExtensionSlotBit::encode(true) | IsHiddenBit::encode(false) | IsWrappedFunctionBit::encode(false); scope_info->set_flags(flags, kRelaxedStore); scope_info->set_parameter_count(0); scope_info->set_context_local_count(0); scope_info->set_position_info_start(0); scope_info->set_position_info_end(0); int index = kVariablePartIndex; DCHECK_EQ(index, scope_info->FunctionVariableInfoIndex()); DCHECK_EQ(index, scope_info->InferredFunctionNameIndex()); DCHECK_EQ(index, scope_info->OuterScopeInfoIndex()); if (has_outer_scope_info) { Tagged<ScopeInfo> outer = *outer_scope.ToHandleChecked(); scope_info->set(index++, outer); } DCHECK_EQ(index, scope_info->DependentCodeIndex()); DCHECK_EQ(index, scope_info->UnusedParameterBitsIndex()); DCHECK_EQ(index, scope_info->length()); DCHECK_EQ(length, scope_info->length()); DCHECK_EQ(0, scope_info->ParameterCount()); DCHECK_EQ(scope_info->ContextHeaderLength(), scope_info->ContextLength()); return scope_info; } // static DirectHandle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) { return CreateForBootstrapping(isolate, BootstrappingType::kScript); } // static DirectHandle<ScopeInfo> ScopeInfo::CreateForEmptyFunction(Isolate* isolate) { DirectHandle<ScopeInfo> scope_info = CreateForBootstrapping(isolate, BootstrappingType::kFunction); if (v8_flags.function_context_cells) { // An empty function scope will set the has_context_cells_ flag, since it is // set to true for all function scopes with the number of context locals (in // this case zero) below the threshold // v8_flags.function_context_cells_max_size. scope_info->set_flags( scope_info->Flags() | HasContextCellsBit::encode(true), kRelaxedStore); } return scope_info; } // static DirectHandle<ScopeInfo> ScopeInfo::CreateForNativeContext(Isolate* isolate) { return CreateForBootstrapping(isolate, BootstrappingType::kNative); } // static DirectHandle<ScopeInfo> ScopeInfo::CreateForShadowRealmNativeContext( Isolate* isolate) { return CreateForBootstrapping(isolate, BootstrappingType::kShadowRealm); } // static DirectHandle<ScopeInfo> ScopeInfo::CreateForBootstrapping( Isolate* isolate, BootstrappingType type) { const int parameter_count = 0; const bool is_empty_function = type == BootstrappingType::kFunction; const bool is_native_context = (type == BootstrappingType::kNative) || (type == BootstrappingType::kShadowRealm); const bool is_script = type == BootstrappingType::kScript; const bool is_shadow_realm = type == BootstrappingType::kShadowRealm; const int context_local_count = is_empty_function || is_native_context ? 0 : 1; const bool has_inferred_function_name = is_empty_function; // NOTE: Local names are always inlined here, since context_local_count < 2. DCHECK_LT(context_local_count, kScopeInfoMaxInlinedLocalNamesSize); const int length = kVariablePartIndex + 2 * context_local_count + (is_empty_function ? kFunctionNameEntries : 0) + (has_inferred_function_name ? 1 : 0) + (is_empty_function ? 1 : 0); Factory* factory = isolate->factory(); DirectHandle<ScopeInfo> scope_info = factory->NewScopeInfo(length, AllocationType::kReadOnly); DisallowGarbageCollection _nogc; // Encode the flags. DCHECK_IMPLIES(is_shadow_realm || is_script, !is_empty_function); uint32_t flags = ScopeTypeBits::encode( is_empty_function ? FUNCTION_SCOPE : (is_shadow_realm ? SHADOW_REALM_SCOPE : SCRIPT_SCOPE)) | SloppyEvalCanExtendVarsBit::encode(false) | LanguageModeBit::encode(LanguageMode::kSloppy) | DeclarationScopeBit::encode(true) | ReceiverVariableBits::encode(is_script ? VariableAllocationInfo::CONTEXT : VariableAllocationInfo::UNUSED) | ClassScopeHasPrivateBrandBit::encode(false) | HasSavedClassVariableBit::encode(false) | // We don't know the value of this flag, so set defensively. AllocatesArgumentsBit::encode(type == BootstrappingType::kFunction && !is_empty_function) | FunctionVariableBits::encode(is_empty_function ? VariableAllocationInfo::UNUSED : VariableAllocationInfo::NONE) | HasInferredFunctionNameBit::encode(has_inferred_function_name) | IsAsmModuleBit::encode(false) | HasSimpleParametersBit::encode(true) | FunctionKindBits::encode(FunctionKind::kNormalFunction) | HasOuterScopeInfoBit::encode(false) | IsDebugEvaluateScopeBit::encode(false) | ForceContextAllocationBit::encode(false) | PrivateNameLookupSkipsOuterClassBit::encode(false) | HasContextExtensionSlotBit::encode(is_native_context) | IsHiddenBit::encode(false) | IsWrappedFunctionBit::encode(false) | HasContextCellsBit::encode(false); Tagged<ScopeInfo> raw_scope_info = *scope_info; raw_scope_info->set_flags(flags, kRelaxedStore); raw_scope_info->set_parameter_count(parameter_count); raw_scope_info->set_context_local_count(context_local_count); raw_scope_info->set_position_info_start(0); raw_scope_info->set_position_info_end(0); int index = kVariablePartIndex; // Here we add info for context-allocated "this". DCHECK_EQ(index, raw_scope_info->ContextLocalNamesIndex()); ReadOnlyRoots roots(isolate); if (context_local_count) { raw_scope_info->set(index++, roots.this_string()); } DCHECK_EQ(index, raw_scope_info->ContextLocalInfosIndex()); if (context_local_count > 0) { const uint32_t value = VariableModeBits::encode(VariableMode::kConst) | InitFlagBit::encode(kCreatedInitialized) | MaybeAssignedFlagBit::encode(kNotAssigned) | ParameterNumberBits::encode(ParameterNumberBits::kMax) | IsStaticFlagBit::encode(IsStaticFlag::kNotStatic); raw_scope_info->set(index++, Smi::FromInt(value)); } DCHECK_EQ(index, raw_scope_info->FunctionVariableInfoIndex()); if (is_empty_function) { raw_scope_info->set(index++, roots.empty_string()); raw_scope_info->set(index++, Smi::zero()); } DCHECK_EQ(index, raw_scope_info->InferredFunctionNameIndex()); if (has_inferred_function_name) { raw_scope_info->set(index++, roots.empty_string()); } DCHECK_EQ(index, raw_scope_info->OuterScopeInfoIndex()); DCHECK_EQ(index, raw_scope_info->DependentCodeIndex()); DCHECK_EQ(index, scope_info->UnusedParameterBitsIndex()); if (is_empty_function) { // unused parameters raw_scope_info->set(index++, Smi::zero()); } DCHECK_EQ(index, raw_scope_info->length()); DCHECK_EQ(length, raw_scope_info->length()); DCHECK_EQ(raw_scope_info->ParameterCount(), parameter_count); if (is_empty_function || is_native_context) { DCHECK_EQ(raw_scope_info->ContextLength(), 0); } else { DCHECK_EQ(raw_scope_info->ContextLength(), raw_scope_info->ContextHeaderLength() + 1); } return scope_info; } Tagged<Object> ScopeInfo::get(int index) const { PtrComprCageBase cage_base = GetPtrComprCageBase(*this); return get(cage_base, index); } Tagged<Object> ScopeInfo::get(PtrComprCageBase cage_base, int index) const { DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); return TaggedField<Object>::Relaxed_Load(cage_base, *this, OffsetOfElementAt(index)); } void ScopeInfo::set(int index, Tagged<Smi> value) { DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); DCHECK(IsSmi(Tagged<Object>(value))); int offset = OffsetOfElementAt(index); RELAXED_WRITE_FIELD(*this, offset, value); } void ScopeInfo::set(int index, Tagged<Object> value, WriteBarrierMode mode) { DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); int offset = OffsetOfElementAt(index); RELAXED_WRITE_FIELD(*this, offset, value); CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); } void ScopeInfo::CopyElements(Isolate* isolate, int dst_index, Tagged<ScopeInfo> src, int src_index, int len, WriteBarrierMode mode) { if (len == 0) return; DCHECK_LE(src_index + len, src->length()); DisallowGarbageCollection no_gc; ObjectSlot dst_slot(RawFieldOfElementAt(dst_index)); ObjectSlot src_slot(src->RawFieldOfElementAt(src_index)); isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode); } ObjectSlot ScopeInfo::RawFieldOfElementAt(int index) { return RawField(OffsetOfElementAt(index)); } int ScopeInfo::length() const { // AllocatedSize() is generated by Torque and represents the size in bytes of // the object, as computed from flags, context_local_count, and possibly // module_variable_count. Convert that size into a number of slots. return (AllocatedSize() - HeapObject::kHeaderSize) / kTaggedSize; } Tagged<ScopeInfo> ScopeInfo::Empty(Isolate* isolate) { return ReadOnlyRoots(isolate).empty_scope_info(); } bool ScopeInfo::IsEmpty() const { return IsEmptyBit::decode(Flags()); } ScopeType ScopeInfo::scope_type() const { DCHECK(!this->IsEmpty()); return ScopeTypeBits::decode(Flags()); } bool ScopeInfo::is_script_scope() const { return !this->IsEmpty() && (scope_type() == SCRIPT_SCOPE || scope_type() == REPL_MODE_SCOPE); } bool ScopeInfo::SloppyEvalCanExtendVars() const { bool sloppy_eval_can_extend_vars = SloppyEvalCanExtendVarsBit::decode(Flags()); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_sloppy(language_mode())); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_declaration_scope()); return sloppy_eval_can_extend_vars; } LanguageMode ScopeInfo::language_mode() const { return LanguageModeBit::decode(Flags()); } bool ScopeInfo::is_declaration_scope() const { return DeclarationScopeBit::decode(Flags()); } int ScopeInfo::ContextLength() const { if (this->IsEmpty()) return 0; int context_locals = ContextLocalCount(); bool function_name_context_slot = HasContextAllocatedFunctionName(); bool force_context = ForceContextAllocationBit::decode(Flags()); bool has_context = context_locals > 0 || force_context || function_name_context_slot || scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE || (scope_type() == BLOCK_SCOPE && SloppyEvalCanExtendVars() && is_declaration_scope()) || (scope_type() == FUNCTION_SCOPE && SloppyEvalCanExtendVars()) || (scope_type() == FUNCTION_SCOPE && IsAsmModule()) || scope_type() == MODULE_SCOPE; if (!has_context) return 0; return ContextHeaderLength() + context_locals + (function_name_context_slot ? 1 : 0); } // Needs to be kept in sync with Scope::UniqueIdInScript and // SharedFunctionInfo::UniqueIdInScript. int ScopeInfo::UniqueIdInScript() const { // Script scopes start "before" the script to avoid clashing with a scope that // starts on character 0. if (is_script_scope() || scope_type() == EVAL_SCOPE || scope_type() == MODULE_SCOPE) { return -2; } // Wrapped functions start before the function body, but after the script // start, to avoid clashing with a scope starting on character 0. if (IsWrappedFunctionScope()) { return -1; } // Default constructors have the same start position as their parent class // scope. Use the next char position to distinguish this scope. return StartPosition() + IsDefaultConstructor(function_kind()); } bool ScopeInfo::HasContextExtensionSlot() const { return HasContextExtensionSlotBit::decode(Flags()); } bool ScopeInfo::SomeContextHasExtension() const { return SomeContextHasExtensionBit::decode(Flags()); } void ScopeInfo::mark_some_context_has_extension() { set_flags(SomeContextHasExtensionBit::update(Flags(), true), kRelaxedStore); } int ScopeInfo::ContextHeaderLength() const { return HasContextExtensionSlot() ? Context::MIN_CONTEXT_EXTENDED_SLOTS : Context::MIN_CONTEXT_SLOTS; } bool ScopeInfo::HasReceiver() const { return VariableAllocationInfo::NONE != ReceiverVariableBits::decode(Flags()); } bool ScopeInfo::HasAllocatedReceiver() const { // The receiver is allocated and needs to be deserialized during reparsing // when: // 1. During the initial parsing, it's been observed that the inner // scopes are accessing this, so the receiver should be allocated // again. This can be inferred when the receiver variable is // recorded as being allocated on the stack or context. // 2. The scope is created as a debug evaluate scope, so this is not // an actual reparse, we are not sure if the inner scope will access // this, but the receiver should be allocated just in case. VariableAllocationInfo allocation = ReceiverVariableBits::decode(Flags()); return allocation == VariableAllocationInfo::STACK || allocation == VariableAllocationInfo::CONTEXT || IsDebugEvaluateScope(); } bool ScopeInfo::ClassScopeHasPrivateBrand() const { return ClassScopeHasPrivateBrandBit::decode(Flags()); } bool ScopeInfo::HasSavedClassVariable() const { return HasSavedClassVariableBit::decode(Flags()); } bool ScopeInfo::IsSloppyNormalJSFunction() const { return function_kind() == FunctionKind::kNormalFunction && is_sloppy(language_mode()); } bool ScopeInfo::CanOnlyAccessFixedFormalParameters() const { FunctionKind function_kind = this->function_kind(); return // Filter out builtins. !IsEmpty() && // Can't be a SloppyNormalJSFunction. !IsSloppyNormalJSFunction() && // TODO(dcarney): Make this function kind filter exact. It's currently // fine if it's not as this results in conservation // optimizations. (function_kind == FunctionKind::kNormalFunction || function_kind == FunctionKind::kArrowFunction) && // Can't have arguments allocated in the frame for any reason since this // indicates potential reachability. !AllocatesArgumentsBit::decode(Flags()) && // Can't have rest parameters. HasSimpleParameters(); } bool ScopeInfo::HasFunctionName() const { return VariableAllocationInfo::NONE != FunctionVariableBits::decode(Flags()); } bool ScopeInfo::HasContextAllocatedFunctionName() const { return VariableAllocationInfo::CONTEXT == FunctionVariableBits::decode(Flags()); } bool ScopeInfo::HasInferredFunctionName() const { return HasInferredFunctionNameBit::decode(Flags()); } bool ScopeInfo::HasPositionInfo() const { return !this->IsEmpty(); } bool ScopeInfo::HasSharedFunctionName() const { return FunctionName() != SharedFunctionInfo::kNoSharedNameSentinel; } void ScopeInfo::SetFunctionName(Tagged<UnionOf<Smi, String>> name) { DCHECK(HasFunctionName()); DCHECK(IsString(name) || name == SharedFunctionInfo::kNoSharedNameSentinel); DCHECK_IMPLIES(HasContextAllocatedFunctionName(), IsInternalizedString(name)); set_function_variable_info_name(name); } void ScopeInfo::SetInferredFunctionName(Tagged<String> name) { DCHECK(HasInferredFunctionName()); set_inferred_function_name(name); } bool ScopeInfo::HasOuterScopeInfo() const { return HasOuterScopeInfoBit::decode(Flags()); } bool ScopeInfo::IsDebugEvaluateScope() const { return IsDebugEvaluateScopeBit::decode(Flags()); } void ScopeInfo::SetIsDebugEvaluateScope() { CHECK(!this->IsEmpty()); DCHECK_EQ(scope_type(), WITH_SCOPE); set_flags(Flags() | IsDebugEvaluateScopeBit::encode(true), kRelaxedStore); } bool ScopeInfo::PrivateNameLookupSkipsOuterClass() const { return PrivateNameLookupSkipsOuterClassBit::decode(Flags()); } bool ScopeInfo::IsReplModeScope() const { return scope_type() == REPL_MODE_SCOPE; } bool ScopeInfo::IsWrappedFunctionScope() const { DCHECK_IMPLIES(IsWrappedFunctionBit::decode(Flags()), scope_type() == FUNCTION_SCOPE); return IsWrappedFunctionBit::decode(Flags()); } bool ScopeInfo::HasContext() const { return ContextLength() > 0; } Tagged<UnionOf<Smi, String>> ScopeInfo::FunctionName() const { DCHECK(HasFunctionName()); return function_variable_info_name(); } Tagged<Object> ScopeInfo::InferredFunctionName() const { DCHECK(HasInferredFunctionName()); return inferred_function_name(); } Tagged<String> ScopeInfo::FunctionDebugName() const { if (!HasFunctionName()) return GetReadOnlyRoots().empty_string(); Tagged<Object> name = FunctionName(); if (IsString(name) && Cast<String>(name)->length() > 0) { return Cast<String>(name); } if (HasInferredFunctionName()) { name = InferredFunctionName(); if (IsString(name)) return Cast<String>(name); } return GetReadOnlyRoots().empty_string(); } int ScopeInfo::StartPosition() const { DCHECK(HasPositionInfo()); return position_info_start(); } int ScopeInfo::EndPosition() const { DCHECK(HasPositionInfo()); return position_info_end(); } void ScopeInfo::SetPositionInfo(int start, int end) { DCHECK(HasPositionInfo()); DCHECK_LE(start, end); set_position_info_start(start); set_position_info_end(end); } Tagged<ScopeInfo> ScopeInfo::OuterScopeInfo() const { DCHECK(HasOuterScopeInfo()); return Cast<ScopeInfo>(outer_scope_info()); } Tagged<SourceTextModuleInfo> ScopeInfo::ModuleDescriptorInfo() const { DCHECK(scope_type() == MODULE_SCOPE); return Cast<SourceTextModuleInfo>(module_info()); } Tagged<String> ScopeInfo::ContextInlinedLocalName(int var) const { DCHECK(HasInlinedLocalNames()); return context_local_names(var); } Tagged<String> ScopeInfo::ContextInlinedLocalName(PtrComprCageBase cage_base, int var) const { DCHECK(HasInlinedLocalNames()); return context_local_names(cage_base, var); } VariableMode ScopeInfo::ContextLocalMode(int var) const { int value = context_local_infos(var); return VariableModeBits::decode(value); } IsStaticFlag ScopeInfo::ContextLocalIsStaticFlag(int var) const { int value = context_local_infos(var); return IsStaticFlagBit::decode(value); } InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) const { int value = context_local_infos(var); return InitFlagBit::decode(value); } bool ScopeInfo::ContextLocalIsParameter(int var) const { int value = context_local_infos(var); return ParameterNumberBits::decode(value) != ParameterNumberBits::kMax; } uint32_t ScopeInfo::ContextLocalParameterNumber(int var) const { DCHECK(ContextLocalIsParameter(var)); int value = context_local_infos(var); return ParameterNumberBits::decode(value); } MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) const { int value = context_local_infos(var); return MaybeAssignedFlagBit::decode(value); } // static bool ScopeInfo::VariableIsSynthetic(Tagged<String> name) { // There's currently no flag stored on the ScopeInfo to indicate that a // variable is a compiler-introduced temporary. However, to avoid conflict // with user declarations, the current temporaries like .generator_object and // .result start with a dot, so we can use that as a flag. It's a hack! return name->length() == 0 || name->Get(0) == '.' || name->Get(0) == '#' || name->Equals(GetReadOnlyRoots().this_string()); } int ScopeInfo::ModuleVariableCount() const { DCHECK_EQ(scope_type(), MODULE_SCOPE); return module_variable_count(); } int ScopeInfo::ModuleIndex(Tagged<String> name, VariableMode* mode, InitializationFlag* init_flag, MaybeAssignedFlag* maybe_assigned_flag) { DisallowGarbageCollection no_gc; DCHECK(IsInternalizedString(name)); DCHECK_EQ(scope_type(), MODULE_SCOPE); DCHECK_NOT_NULL(mode); DCHECK_NOT_NULL(init_flag); DCHECK_NOT_NULL(maybe_assigned_flag); int module_vars_count = module_variable_count(); for (int i = 0; i < module_vars_count; ++i) { Tagged<String> var_name = module_variables_name(i); if (name->Equals(var_name)) { int index; ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag); return index; } } return 0; } int ScopeInfo::InlinedLocalNamesLookup(Tagged<String> name) { DisallowGarbageCollection no_gc; PtrComprCageBase cage_base = GetPtrComprCageBase(*this); int local_count = context_local_count(); for (int i = 0; i < local_count; ++i) { if (name == ContextInlinedLocalName(cage_base, i)) { return i; } } return -1; } int ScopeInfo::ContextSlotIndex(Tagged<String> name, VariableLookupResult* lookup_result) { DisallowGarbageCollection no_gc; DCHECK(IsInternalizedString(name)); DCHECK_NOT_NULL(lookup_result); if (this->IsEmpty()) return -1; int index = HasInlinedLocalNames() ? InlinedLocalNamesLookup(name) : context_local_names_hashtable()->Lookup(name); if (index != -1) { lookup_result->mode = ContextLocalMode(index); lookup_result->is_static_flag = ContextLocalIsStaticFlag(index); lookup_result->init_flag = ContextLocalInitFlag(index); lookup_result->maybe_assigned_flag = ContextLocalMaybeAssignedFlag(index); lookup_result->is_repl_mode = IsReplModeScope(); int context_slot = ContextHeaderLength() + index; DCHECK_LT(context_slot, ContextLength()); return context_slot; } return -1; } int ScopeInfo::ContextSlotIndex(Tagged<String> name) { VariableLookupResult lookup_result; return ContextSlotIndex(name, &lookup_result); } std::pair<Tagged<String>, int> ScopeInfo::SavedClassVariable() const { DCHECK(HasSavedClassVariableBit::decode(Flags())); auto class_variable_info = saved_class_variable_info(); if (HasInlinedLocalNames()) { // The saved class variable info corresponds to the context slot index. DCHECK(class_variable_info.IsSmi()); int index = class_variable_info.ToSmi().value() - Context::MIN_CONTEXT_SLOTS; DCHECK_GE(index, 0); DCHECK_LT(index, ContextLocalCount()); Tagged<String> name = ContextInlinedLocalName(index); return std::make_pair(name, index); } else { // The saved class variable info corresponds to the name. Tagged<Name> name = Cast<Name>(class_variable_info); Tagged<NameToIndexHashTable> table = context_local_names_hashtable(); int index = table->Lookup(name); DCHECK_GE(index, 0); DCHECK(IsString(name)); return std::make_pair(Cast<String>(name), index); } } int ScopeInfo::ReceiverContextSlotIndex() const { if (ReceiverVariableBits::decode(Flags()) == VariableAllocationInfo::CONTEXT) { return ContextHeaderLength(); } return -1; } int ScopeInfo::ParametersStartIndex() const { if (ReceiverVariableBits::decode(Flags()) == VariableAllocationInfo::CONTEXT) { return ContextHeaderLength() + 1; } return ContextHeaderLength(); } int ScopeInfo::FunctionContextSlotIndex(Tagged<String> name) const { DCHECK(IsInternalizedString(name)); if (HasContextAllocatedFunctionName()) { DCHECK_IMPLIES(HasFunctionName(), IsInternalizedString(FunctionName())); if (FunctionName() == name) { return function_variable_info_context_or_stack_slot_index(); } } return -1; } FunctionKind ScopeInfo::function_kind() const { return FunctionKindBits::decode(Flags()); } int ScopeInfo::ContextLocalNamesIndex() const { return ConvertOffsetToIndex(ContextLocalNamesOffset()); } int ScopeInfo::ContextLocalInfosIndex() const { return ConvertOffsetToIndex(ContextLocalInfosOffset()); } int ScopeInfo::SavedClassVariableInfoIndex() const { return ConvertOffsetToIndex(SavedClassVariableInfoOffset()); } int ScopeInfo::FunctionVariableInfoIndex() const { return ConvertOffsetToIndex(FunctionVariableInfoOffset()); } int ScopeInfo::InferredFunctionNameIndex() const { return ConvertOffsetToIndex(InferredFunctionNameOffset()); } int ScopeInfo::OuterScopeInfoIndex() const { return ConvertOffsetToIndex(OuterScopeInfoOffset()); } int ScopeInfo::ModuleInfoIndex() const { return ConvertOffsetToIndex(ModuleInfoOffset()); } int ScopeInfo::ModuleVariableCountIndex() const { return ConvertOffsetToIndex(kModuleVariableCountOffset); } int ScopeInfo::ModuleVariablesIndex() const { return ConvertOffsetToIndex(ModuleVariablesOffset()); } void ScopeInfo::ModuleVariable(int i, Tagged<String>* name, int* index, VariableMode* mode, InitializationFlag* init_flag, MaybeAssignedFlag* maybe_assigned_flag) { int properties = module_variables_properties(i); if (name != nullptr) { *name = module_variables_name(i); } if (index != nullptr) { *index = module_variables_index(i); DCHECK_NE(*index, 0); } if (mode != nullptr) { *mode = VariableModeBits::decode(properties); } if (init_flag != nullptr) { *init_flag = InitFlagBit::decode(properties); } if (maybe_assigned_flag != nullptr) { *maybe_assigned_flag = MaybeAssignedFlagBit::decode(properties); } } int ScopeInfo::DependentCodeIndex() const { return ConvertOffsetToIndex(DependentCodeOffset()); } int ScopeInfo::UnusedParameterBitsIndex() const { return ConvertOffsetToIndex(UnusedParameterBitsOffset()); } uint32_t ScopeInfo::Hash() { // Hash ScopeInfo based on its start and end position. // Note: Ideally we'd also have the script ID. But since we only use the // hash in a debug-evaluate cache, we don't worry too much about collisions. if (HasPositionInfo()) { return static_cast<uint32_t>(base::hash_combine( flags(kRelaxedLoad), StartPosition(), EndPosition())); } return static_cast<uint32_t>( base::hash_combine(flags(kRelaxedLoad), context_local_count())); } std::ostream& operator<<(std::ostream& os, VariableAllocationInfo var_info) { switch (var_info) { case VariableAllocationInfo::NONE: return os << "NONE"; case VariableAllocationInfo::STACK: return os << "STACK"; case VariableAllocationInfo::CONTEXT: return os << "CONTEXT"; case VariableAllocationInfo::UNUSED: return os << "UNUSED"; } UNREACHABLE(); } template <typename IsolateT> Handle<ModuleRequest> ModuleRequest::New( IsolateT* isolate, DirectHandle<String> specifier, ModuleImportPhase phase, DirectHandle<FixedArray> import_attributes, int position) { auto result = Cast<ModuleRequest>( isolate->factory()->NewStruct(MODULE_REQUEST_TYPE, AllocationType::kOld)); DisallowGarbageCollection no_gc; Tagged<ModuleRequest> raw = *result; raw->set_specifier(*specifier); raw->set_import_attributes(*import_attributes); raw->set_flags(0); raw->set_phase(phase); DCHECK_GE(position, 0); raw->set_position(position); return result; } template Handle<ModuleRequest> ModuleRequest::New( Isolate* isolate, DirectHandle<String> specifier, ModuleImportPhase phase, DirectHandle<FixedArray> import_attributes, int position); template Handle<ModuleRequest> ModuleRequest::New( LocalIsolate* isolate, DirectHandle<String> specifier, ModuleImportPhase phase, DirectHandle<FixedArray> import_attributes, int position); template <typename IsolateT> Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New( IsolateT* isolate, DirectHandle<UnionOf<String, Undefined>> export_name, DirectHandle<UnionOf<String, Undefined>> local_name, DirectHandle<UnionOf<String, Undefined>> import_name, int module_request, int cell_index, int beg_pos, int end_pos) { auto result = Cast<SourceTextModuleInfoEntry>(isolate->factory()->NewStruct( SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, AllocationType::kOld)); DisallowGarbageCollection no_gc; Tagged<SourceTextModuleInfoEntry> raw = *result; raw->set_export_name(*export_name); raw->set_local_name(*local_name); raw->set_import_name(*import_name); raw->set_module_request(module_request); raw->set_cell_index(cell_index); raw->set_beg_pos(beg_pos); raw->set_end_pos(end_pos); return result; } template Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New( Isolate* isolate, DirectHandle<UnionOf<String, Undefined>> export_name, DirectHandle<UnionOf<String, Undefined>> local_name, DirectHandle<UnionOf<String, Undefined>> import_name, int module_request, int cell_index, int beg_pos, int end_pos); template Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New( LocalIsolate* isolate, DirectHandle<UnionOf<String, Undefined>> export_name, DirectHandle<UnionOf<String, Undefined>> local_name, DirectHandle<UnionOf<String, Undefined>> import_name, int module_request, int cell_index, int beg_pos, int end_pos); template <typename IsolateT> DirectHandle<SourceTextModuleInfo> SourceTextModuleInfo::New( IsolateT* isolate, Zone* zone, SourceTextModuleDescriptor* descr) { // Serialize module requests. int size = static_cast<int>(descr->module_requests().size()); DirectHandle<FixedArray> module_requests = isolate->factory()->NewFixedArray(size, AllocationType::kOld); for (const auto& elem : descr->module_requests()) { DirectHandle<ModuleRequest> serialized_module_request = elem->Serialize(isolate); module_requests->set(elem->index(), *serialized_module_request); } // Serialize special exports. DirectHandle<FixedArray> special_exports = isolate->factory()->NewFixedArray( static_cast<int>(descr->special_exports().size()), AllocationType::kOld); { int i = 0; for (auto entry : descr->special_exports()) { DirectHandle<SourceTextModuleInfoEntry> serialized_entry = entry->Serialize(isolate); special_exports->set(i++, *serialized_entry); } } // Serialize namespace imports. DirectHandle<FixedArray> namespace_imports = isolate->factory()->NewFixedArray( static_cast<int>(descr->namespace_imports().size()), AllocationType::kOld); { int i = 0; for (auto entry : descr->namespace_imports()) { DirectHandle<SourceTextModuleInfoEntry> serialized_entry = entry.second->Serialize(isolate); namespace_imports->set(i++, *serialized_entry); } } // Serialize regular exports. DirectHandle<FixedArray> regular_exports = descr->SerializeRegularExports(isolate, zone); // Serialize regular imports. DirectHandle<FixedArray> regular_imports = isolate->factory()->NewFixedArray( static_cast<int>(descr->regular_imports().size()), AllocationType::kOld); { int i = 0; for (const auto& elem : descr->regular_imports()) { DirectHandle<SourceTextModuleInfoEntry> serialized_entry = elem.second->Serialize(isolate); regular_imports->set(i++, *serialized_entry); } } DirectHandle<SourceTextModuleInfo> result = isolate->factory()->NewSourceTextModuleInfo(); result->set(kModuleRequestsIndex, *module_requests); result->set(kSpecialExportsIndex, *special_exports); result->set(kRegularExportsIndex, *regular_exports); result->set(kNamespaceImportsIndex, *namespace_imports); result->set(kRegularImportsIndex, *regular_imports); return result; } template DirectHandle<SourceTextModuleInfo> SourceTextModuleInfo::New( Isolate* isolate, Zone* zone, SourceTextModuleDescriptor* descr); template DirectHandle<SourceTextModuleInfo> SourceTextModuleInfo::New( LocalIsolate* isolate, Zone* zone, SourceTextModuleDescriptor* descr); int SourceTextModuleInfo::RegularExportCount() const { DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0); return regular_exports()->length() / kRegularExportLength; } Tagged<String> SourceTextModuleInfo::RegularExportLocalName(int i) const { return Cast<String>(regular_exports()->get(i * kRegularExportLength + kRegularExportLocalNameOffset)); } int SourceTextModuleInfo::RegularExportCellIndex(int i) const { return Smi::ToInt(regular_exports()->get(i * kRegularExportLength + kRegularExportCellIndexOffset)); } Tagged<FixedArray> SourceTextModuleInfo::RegularExportExportNames(int i) const { return Cast<FixedArray>(regular_exports()->get( i * kRegularExportLength + kRegularExportExportNamesOffset)); } } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h"