// 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/ast/scopeinfo.h" #include <stdlib.h> #include "src/ast/scopes.h" #include "src/bootstrapper.h" namespace v8 { namespace internal { Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope) { // Collect stack and context locals. ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone); ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone); ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone); ZoneList<Variable*> strong_mode_free_variables(0, zone); scope->CollectStackAndContextLocals(&stack_locals, &context_locals, &context_globals, &strong_mode_free_variables); const int stack_local_count = stack_locals.length(); const int context_local_count = context_locals.length(); const int context_global_count = context_globals.length(); const int strong_mode_free_variable_count = strong_mode_free_variables.length(); // Make sure we allocate the correct amount. DCHECK_EQ(scope->ContextLocalCount(), context_local_count); DCHECK_EQ(scope->ContextGlobalCount(), context_global_count); // Determine use and location of the "this" binding if it is present. VariableAllocationInfo receiver_info; if (scope->has_this_declaration()) { Variable* var = scope->receiver(); if (!var->is_used()) { receiver_info = UNUSED; } else if (var->IsContextSlot()) { receiver_info = CONTEXT; } else { DCHECK(var->IsParameter()); receiver_info = STACK; } } else { receiver_info = NONE; } bool has_new_target = scope->new_target_var() != nullptr; // Determine use and location of the function variable if it is present. VariableAllocationInfo function_name_info; VariableMode function_variable_mode; if (scope->is_function_scope() && scope->function() != NULL) { Variable* var = scope->function()->proxy()->var(); if (!var->is_used()) { function_name_info = UNUSED; } else if (var->IsContextSlot()) { function_name_info = CONTEXT; } else { DCHECK(var->IsStackLocal()); function_name_info = STACK; } function_variable_mode = var->mode(); } else { function_name_info = NONE; function_variable_mode = VAR; } DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE); const bool has_function_name = function_name_info != NONE; const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT; const int parameter_count = scope->num_parameters(); const int length = kVariablePartIndex + parameter_count + (1 + stack_local_count) + 2 * context_local_count + 2 * context_global_count + 3 * strong_mode_free_variable_count + (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0); Factory* factory = isolate->factory(); Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); bool has_simple_parameters = scope->is_function_scope() && scope->has_simple_parameters(); // Encode the flags. int flags = ScopeTypeField::encode(scope->scope_type()) | CallsEvalField::encode(scope->calls_eval()) | LanguageModeField::encode(scope->language_mode()) | DeclarationScopeField::encode(scope->is_declaration_scope()) | ReceiverVariableField::encode(receiver_info) | HasNewTargetField::encode(has_new_target) | FunctionVariableField::encode(function_name_info) | FunctionVariableMode::encode(function_variable_mode) | AsmModuleField::encode(scope->asm_module()) | AsmFunctionField::encode(scope->asm_function()) | HasSimpleParametersField::encode(has_simple_parameters) | FunctionKindField::encode(scope->function_kind()); scope_info->SetFlags(flags); scope_info->SetParameterCount(parameter_count); scope_info->SetStackLocalCount(stack_local_count); scope_info->SetContextLocalCount(context_local_count); scope_info->SetContextGlobalCount(context_global_count); scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count); int index = kVariablePartIndex; // Add parameters. DCHECK(index == scope_info->ParameterEntriesIndex()); for (int i = 0; i < parameter_count; ++i) { scope_info->set(index++, *scope->parameter(i)->name()); } // Add stack locals' names. We are assuming that the stack locals' // slots are allocated in increasing order, so we can simply add // them to the ScopeInfo object. int first_slot_index; if (stack_local_count > 0) { first_slot_index = stack_locals[0]->index(); } else { first_slot_index = 0; } DCHECK(index == scope_info->StackLocalFirstSlotIndex()); scope_info->set(index++, Smi::FromInt(first_slot_index)); DCHECK(index == scope_info->StackLocalEntriesIndex()); for (int i = 0; i < stack_local_count; ++i) { DCHECK(stack_locals[i]->index() == first_slot_index + i); scope_info->set(index++, *stack_locals[i]->name()); } // Due to usage analysis, context-allocated locals are not necessarily in // increasing order: Some of them may be parameters which are allocated before // the non-parameter locals. When the non-parameter locals are sorted // according to usage, the allocated slot indices may not be in increasing // order with the variable list anymore. Thus, we first need to sort them by // context slot index before adding them to the ScopeInfo object. context_locals.Sort(&Variable::CompareIndex); // Add context locals' names. DCHECK(index == scope_info->ContextLocalNameEntriesIndex()); for (int i = 0; i < context_local_count; ++i) { scope_info->set(index++, *context_locals[i]->name()); } // Add context globals' names. DCHECK(index == scope_info->ContextGlobalNameEntriesIndex()); for (int i = 0; i < context_global_count; ++i) { scope_info->set(index++, *context_globals[i]->name()); } // Add context locals' info. DCHECK(index == scope_info->ContextLocalInfoEntriesIndex()); for (int i = 0; i < context_local_count; ++i) { Variable* var = context_locals[i]; uint32_t value = ContextLocalMode::encode(var->mode()) | ContextLocalInitFlag::encode(var->initialization_flag()) | ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned()); scope_info->set(index++, Smi::FromInt(value)); } // Add context globals' info. DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex()); for (int i = 0; i < context_global_count; ++i) { Variable* var = context_globals[i]; // TODO(ishell): do we need this kind of info for globals here? uint32_t value = ContextLocalMode::encode(var->mode()) | ContextLocalInitFlag::encode(var->initialization_flag()) | ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned()); scope_info->set(index++, Smi::FromInt(value)); } DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex()); for (int i = 0; i < strong_mode_free_variable_count; ++i) { scope_info->set(index++, *strong_mode_free_variables[i]->name()); } DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex()); for (int i = 0; i < strong_mode_free_variable_count; ++i) { // Unfortunately, the source code positions are stored as int even though // int32_t would be enough (given the maximum source code length). Handle<Object> start_position = factory->NewNumberFromInt( static_cast<int32_t>(strong_mode_free_variables[i] ->strong_mode_reference_start_position())); scope_info->set(index++, *start_position); Handle<Object> end_position = factory->NewNumberFromInt( static_cast<int32_t>(strong_mode_free_variables[i] ->strong_mode_reference_end_position())); scope_info->set(index++, *end_position); } // If the receiver is allocated, add its index. DCHECK(index == scope_info->ReceiverEntryIndex()); if (has_receiver) { int var_index = scope->receiver()->index(); scope_info->set(index++, Smi::FromInt(var_index)); // ?? DCHECK(receiver_info != CONTEXT || var_index == // scope_info->ContextLength() - 1); } // If present, add the function variable name and its index. DCHECK(index == scope_info->FunctionNameEntryIndex()); if (has_function_name) { int var_index = scope->function()->proxy()->var()->index(); scope_info->set(index++, *scope->function()->proxy()->name()); scope_info->set(index++, Smi::FromInt(var_index)); DCHECK(function_name_info != CONTEXT || var_index == scope_info->ContextLength() - 1); } DCHECK(index == scope_info->length()); DCHECK(scope->num_parameters() == scope_info->ParameterCount()); DCHECK(scope->num_heap_slots() == scope_info->ContextLength() || (scope->num_heap_slots() == kVariablePartIndex && scope_info->ContextLength() == 0)); return scope_info; } Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) { DCHECK(isolate->bootstrapper()->IsActive()); const int stack_local_count = 0; const int context_local_count = 1; const int context_global_count = 0; const int strong_mode_free_variable_count = 0; const bool has_simple_parameters = true; const VariableAllocationInfo receiver_info = CONTEXT; const VariableAllocationInfo function_name_info = NONE; const VariableMode function_variable_mode = VAR; const bool has_function_name = false; const bool has_receiver = true; const int parameter_count = 0; const int length = kVariablePartIndex + parameter_count + (1 + stack_local_count) + 2 * context_local_count + 2 * context_global_count + 3 * strong_mode_free_variable_count + (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0); Factory* factory = isolate->factory(); Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); // Encode the flags. int flags = ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) | LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) | ReceiverVariableField::encode(receiver_info) | FunctionVariableField::encode(function_name_info) | FunctionVariableMode::encode(function_variable_mode) | AsmModuleField::encode(false) | AsmFunctionField::encode(false) | HasSimpleParametersField::encode(has_simple_parameters) | FunctionKindField::encode(FunctionKind::kNormalFunction); scope_info->SetFlags(flags); scope_info->SetParameterCount(parameter_count); scope_info->SetStackLocalCount(stack_local_count); scope_info->SetContextLocalCount(context_local_count); scope_info->SetContextGlobalCount(context_global_count); scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count); int index = kVariablePartIndex; const int first_slot_index = 0; DCHECK(index == scope_info->StackLocalFirstSlotIndex()); scope_info->set(index++, Smi::FromInt(first_slot_index)); DCHECK(index == scope_info->StackLocalEntriesIndex()); // Here we add info for context-allocated "this". DCHECK(index == scope_info->ContextLocalNameEntriesIndex()); scope_info->set(index++, *isolate->factory()->this_string()); DCHECK(index == scope_info->ContextLocalInfoEntriesIndex()); const uint32_t value = ContextLocalMode::encode(CONST) | ContextLocalInitFlag::encode(kCreatedInitialized) | ContextLocalMaybeAssignedFlag::encode(kNotAssigned); scope_info->set(index++, Smi::FromInt(value)); DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex()); DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex()); // And here we record that this scopeinfo binds a receiver. DCHECK(index == scope_info->ReceiverEntryIndex()); const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0; scope_info->set(index++, Smi::FromInt(receiver_index)); DCHECK(index == scope_info->FunctionNameEntryIndex()); DCHECK_EQ(index, scope_info->length()); DCHECK_EQ(scope_info->ParameterCount(), 0); DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1); return scope_info; } ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array()); } ScopeType ScopeInfo::scope_type() { DCHECK(length() > 0); return ScopeTypeField::decode(Flags()); } bool ScopeInfo::CallsEval() { return length() > 0 && CallsEvalField::decode(Flags()); } LanguageMode ScopeInfo::language_mode() { return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY; } bool ScopeInfo::is_declaration_scope() { return DeclarationScopeField::decode(Flags()); } int ScopeInfo::LocalCount() { return StackLocalCount() + ContextLocalCount(); } int ScopeInfo::StackSlotCount() { if (length() > 0) { bool function_name_stack_slot = FunctionVariableField::decode(Flags()) == STACK; return StackLocalCount() + (function_name_stack_slot ? 1 : 0); } return 0; } int ScopeInfo::ContextLength() { if (length() > 0) { int context_locals = ContextLocalCount(); int context_globals = ContextGlobalCount(); bool function_name_context_slot = FunctionVariableField::decode(Flags()) == CONTEXT; bool has_context = context_locals > 0 || context_globals > 0 || function_name_context_slot || scope_type() == WITH_SCOPE || (scope_type() == BLOCK_SCOPE && CallsSloppyEval() && is_declaration_scope()) || (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) || scope_type() == MODULE_SCOPE; if (has_context) { return Context::MIN_CONTEXT_SLOTS + context_locals + context_globals + (function_name_context_slot ? 1 : 0); } } return 0; } bool ScopeInfo::HasReceiver() { if (length() > 0) { return NONE != ReceiverVariableField::decode(Flags()); } else { return false; } } bool ScopeInfo::HasAllocatedReceiver() { if (length() > 0) { VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags()); return allocation == STACK || allocation == CONTEXT; } else { return false; } } bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); } bool ScopeInfo::HasFunctionName() { if (length() > 0) { return NONE != FunctionVariableField::decode(Flags()); } else { return false; } } bool ScopeInfo::HasHeapAllocatedLocals() { if (length() > 0) { return ContextLocalCount() > 0; } else { return false; } } bool ScopeInfo::HasContext() { return ContextLength() > 0; } String* ScopeInfo::FunctionName() { DCHECK(HasFunctionName()); return String::cast(get(FunctionNameEntryIndex())); } String* ScopeInfo::ParameterName(int var) { DCHECK(0 <= var && var < ParameterCount()); int info_index = ParameterEntriesIndex() + var; return String::cast(get(info_index)); } String* ScopeInfo::LocalName(int var) { DCHECK(0 <= var && var < LocalCount()); DCHECK(StackLocalEntriesIndex() + StackLocalCount() == ContextLocalNameEntriesIndex()); int info_index = StackLocalEntriesIndex() + var; return String::cast(get(info_index)); } String* ScopeInfo::StackLocalName(int var) { DCHECK(0 <= var && var < StackLocalCount()); int info_index = StackLocalEntriesIndex() + var; return String::cast(get(info_index)); } int ScopeInfo::StackLocalIndex(int var) { DCHECK(0 <= var && var < StackLocalCount()); int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); return first_slot_index + var; } String* ScopeInfo::ContextLocalName(int var) { DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount()); int info_index = ContextLocalNameEntriesIndex() + var; return String::cast(get(info_index)); } VariableMode ScopeInfo::ContextLocalMode(int var) { DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount()); int info_index = ContextLocalInfoEntriesIndex() + var; int value = Smi::cast(get(info_index))->value(); return ContextLocalMode::decode(value); } InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) { DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount()); int info_index = ContextLocalInfoEntriesIndex() + var; int value = Smi::cast(get(info_index))->value(); return ContextLocalInitFlag::decode(value); } MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) { DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount()); int info_index = ContextLocalInfoEntriesIndex() + var; int value = Smi::cast(get(info_index))->value(); return ContextLocalMaybeAssignedFlag::decode(value); } bool ScopeInfo::LocalIsSynthetic(int var) { DCHECK(0 <= var && var < LocalCount()); // 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! Handle<String> name(LocalName(var)); return (name->length() > 0 && name->Get(0) == '.') || name->Equals(*GetIsolate()->factory()->this_string()); } String* ScopeInfo::StrongModeFreeVariableName(int var) { DCHECK(0 <= var && var < StrongModeFreeVariableCount()); int info_index = StrongModeFreeVariableNameEntriesIndex() + var; return String::cast(get(info_index)); } int ScopeInfo::StrongModeFreeVariableStartPosition(int var) { DCHECK(0 <= var && var < StrongModeFreeVariableCount()); int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2; int32_t value = 0; bool ok = get(info_index)->ToInt32(&value); USE(ok); DCHECK(ok); return value; } int ScopeInfo::StrongModeFreeVariableEndPosition(int var) { DCHECK(0 <= var && var < StrongModeFreeVariableCount()); int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2 + 1; int32_t value = 0; bool ok = get(info_index)->ToInt32(&value); USE(ok); DCHECK(ok); return value; } int ScopeInfo::StackSlotIndex(String* name) { DCHECK(name->IsInternalizedString()); if (length() > 0) { int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); int start = StackLocalEntriesIndex(); int end = StackLocalEntriesIndex() + StackLocalCount(); for (int i = start; i < end; ++i) { if (name == get(i)) { return i - start + first_slot_index; } } } return -1; } int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info, Handle<String> name, VariableMode* mode, InitializationFlag* init_flag, MaybeAssignedFlag* maybe_assigned_flag) { DCHECK(name->IsInternalizedString()); DCHECK(mode != NULL); DCHECK(init_flag != NULL); if (scope_info->length() > 0) { ContextSlotCache* context_slot_cache = scope_info->GetIsolate()->context_slot_cache(); int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag, maybe_assigned_flag); if (result != ContextSlotCache::kNotFound) { DCHECK(result < scope_info->ContextLength()); return result; } int start = scope_info->ContextLocalNameEntriesIndex(); int end = scope_info->ContextLocalNameEntriesIndex() + scope_info->ContextLocalCount(); for (int i = start; i < end; ++i) { if (*name == scope_info->get(i)) { int var = i - start; *mode = scope_info->ContextLocalMode(var); *init_flag = scope_info->ContextLocalInitFlag(var); *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var); result = Context::MIN_CONTEXT_SLOTS + var; context_slot_cache->Update(scope_info, name, *mode, *init_flag, *maybe_assigned_flag, result); DCHECK(result < scope_info->ContextLength()); return result; } } // Cache as not found. Mode, init flag and maybe assigned flag don't matter. context_slot_cache->Update(scope_info, name, TEMPORARY, kNeedsInitialization, kNotAssigned, -1); } return -1; } int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info, Handle<String> name, VariableMode* mode, InitializationFlag* init_flag, MaybeAssignedFlag* maybe_assigned_flag) { DCHECK(name->IsInternalizedString()); DCHECK(mode != NULL); DCHECK(init_flag != NULL); if (scope_info->length() > 0) { // This is to ensure that ContextLocalMode() and co. queries would work. DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(), scope_info->ContextLocalNameEntriesIndex() + scope_info->ContextLocalCount()); int base = scope_info->ContextLocalNameEntriesIndex(); int start = scope_info->ContextGlobalNameEntriesIndex(); int end = scope_info->ContextGlobalNameEntriesIndex() + scope_info->ContextGlobalCount(); for (int i = start; i < end; ++i) { if (*name == scope_info->get(i)) { int var = i - base; *mode = scope_info->ContextLocalMode(var); *init_flag = scope_info->ContextLocalInitFlag(var); *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var); int result = Context::MIN_CONTEXT_SLOTS + var; DCHECK(result < scope_info->ContextLength()); return result; } } } return -1; } String* ScopeInfo::ContextSlotName(int slot_index) { int const var = slot_index - Context::MIN_CONTEXT_SLOTS; DCHECK_LE(0, var); DCHECK_LT(var, ContextLocalCount() + ContextGlobalCount()); return ContextLocalName(var); } int ScopeInfo::ParameterIndex(String* name) { DCHECK(name->IsInternalizedString()); if (length() > 0) { // We must read parameters from the end since for // multiply declared parameters the value of the // last declaration of that parameter is used // inside a function (and thus we need to look // at the last index). Was bug# 1110337. int start = ParameterEntriesIndex(); int end = ParameterEntriesIndex() + ParameterCount(); for (int i = end - 1; i >= start; --i) { if (name == get(i)) { return i - start; } } } return -1; } int ScopeInfo::ReceiverContextSlotIndex() { if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT) return Smi::cast(get(ReceiverEntryIndex()))->value(); return -1; } int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) { DCHECK(name->IsInternalizedString()); DCHECK(mode != NULL); if (length() > 0) { if (FunctionVariableField::decode(Flags()) == CONTEXT && FunctionName() == name) { *mode = FunctionVariableMode::decode(Flags()); return Smi::cast(get(FunctionNameEntryIndex() + 1))->value(); } } return -1; } FunctionKind ScopeInfo::function_kind() { return FunctionKindField::decode(Flags()); } int ScopeInfo::ParameterEntriesIndex() { DCHECK(length() > 0); return kVariablePartIndex; } int ScopeInfo::StackLocalFirstSlotIndex() { return ParameterEntriesIndex() + ParameterCount(); } int ScopeInfo::StackLocalEntriesIndex() { return StackLocalFirstSlotIndex() + 1; } int ScopeInfo::ContextLocalNameEntriesIndex() { return StackLocalEntriesIndex() + StackLocalCount(); } int ScopeInfo::ContextGlobalNameEntriesIndex() { return ContextLocalNameEntriesIndex() + ContextLocalCount(); } int ScopeInfo::ContextLocalInfoEntriesIndex() { return ContextGlobalNameEntriesIndex() + ContextGlobalCount(); } int ScopeInfo::ContextGlobalInfoEntriesIndex() { return ContextLocalInfoEntriesIndex() + ContextLocalCount(); } int ScopeInfo::StrongModeFreeVariableNameEntriesIndex() { return ContextGlobalInfoEntriesIndex() + ContextGlobalCount(); } int ScopeInfo::StrongModeFreeVariablePositionEntriesIndex() { return StrongModeFreeVariableNameEntriesIndex() + StrongModeFreeVariableCount(); } int ScopeInfo::ReceiverEntryIndex() { return StrongModeFreeVariablePositionEntriesIndex() + 2 * StrongModeFreeVariableCount(); } int ScopeInfo::FunctionNameEntryIndex() { return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0); } int ContextSlotCache::Hash(Object* data, String* name) { // Uses only lower 32 bits if pointers are larger. uintptr_t addr_hash = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2; return static_cast<int>((addr_hash ^ name->Hash()) % kLength); } int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode, InitializationFlag* init_flag, MaybeAssignedFlag* maybe_assigned_flag) { int index = Hash(data, name); Key& key = keys_[index]; if ((key.data == data) && key.name->Equals(name)) { Value result(values_[index]); if (mode != NULL) *mode = result.mode(); if (init_flag != NULL) *init_flag = result.initialization_flag(); if (maybe_assigned_flag != NULL) *maybe_assigned_flag = result.maybe_assigned_flag(); return result.index() + kNotFound; } return kNotFound; } void ContextSlotCache::Update(Handle<Object> data, Handle<String> name, VariableMode mode, InitializationFlag init_flag, MaybeAssignedFlag maybe_assigned_flag, int slot_index) { DisallowHeapAllocation no_gc; Handle<String> internalized_name; DCHECK(slot_index > kNotFound); if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name). ToHandle(&internalized_name)) { int index = Hash(*data, *internalized_name); Key& key = keys_[index]; key.data = *data; key.name = *internalized_name; // Please note value only takes a uint as index. values_[index] = Value(mode, init_flag, maybe_assigned_flag, slot_index - kNotFound).raw(); #ifdef DEBUG ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index); #endif } } void ContextSlotCache::Clear() { for (int index = 0; index < kLength; index++) keys_[index].data = NULL; } #ifdef DEBUG void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name, VariableMode mode, InitializationFlag init_flag, MaybeAssignedFlag maybe_assigned_flag, int slot_index) { DisallowHeapAllocation no_gc; Handle<String> internalized_name; if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name). ToHandle(&internalized_name)) { int index = Hash(*data, *name); Key& key = keys_[index]; DCHECK(key.data == *data); DCHECK(key.name->Equals(*name)); Value result(values_[index]); DCHECK(result.mode() == mode); DCHECK(result.initialization_flag() == init_flag); DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag); DCHECK(result.index() + kNotFound == slot_index); } } static void PrintList(const char* list_name, int nof_internal_slots, int start, int end, ScopeInfo* scope_info) { if (start < end) { PrintF("\n // %s\n", list_name); if (nof_internal_slots > 0) { PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); } for (int i = nof_internal_slots; start < end; ++i, ++start) { PrintF(" %2d ", i); String::cast(scope_info->get(start))->ShortPrint(); PrintF("\n"); } } } void ScopeInfo::Print() { PrintF("ScopeInfo "); if (HasFunctionName()) { FunctionName()->ShortPrint(); } else { PrintF("/* no function name */"); } PrintF("{"); if (length() > 0) { PrintList("parameters", 0, ParameterEntriesIndex(), ParameterEntriesIndex() + ParameterCount(), this); PrintList("stack slots", 0, StackLocalEntriesIndex(), StackLocalEntriesIndex() + StackLocalCount(), this); PrintList("context slots", Context::MIN_CONTEXT_SLOTS, ContextLocalNameEntriesIndex(), ContextLocalNameEntriesIndex() + ContextLocalCount(), this); } PrintF("}\n"); } #endif // DEBUG //--------------------------------------------------------------------------- // ModuleInfo. Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate, ModuleDescriptor* descriptor, Scope* scope) { Handle<ModuleInfo> info = Allocate(isolate, descriptor->Length()); info->set_host_index(descriptor->Index()); int i = 0; for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done(); it.Advance(), ++i) { Variable* var = scope->LookupLocal(it.local_name()); info->set_name(i, *(it.export_name()->string())); info->set_mode(i, var->mode()); DCHECK(var->index() >= 0); info->set_index(i, var->index()); } DCHECK(i == info->length()); return info; } } // namespace internal } // namespace v8