| OLD | NEW |
| (Empty) |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <stdlib.h> | |
| 6 | |
| 7 #include "src/objects/scope-info.h" | |
| 8 | |
| 9 #include "src/ast/context-slot-cache.h" | |
| 10 #include "src/ast/scopes.h" | |
| 11 #include "src/ast/variables.h" | |
| 12 #include "src/bootstrapper.h" | |
| 13 #include "src/objects-inl.h" | |
| 14 | |
| 15 namespace v8 { | |
| 16 namespace internal { | |
| 17 | |
| 18 // An entry in ModuleVariableEntries consists of several slots: | |
| 19 enum ModuleVariableEntryOffset { | |
| 20 kModuleVariableNameOffset, | |
| 21 kModuleVariableIndexOffset, | |
| 22 kModuleVariablePropertiesOffset, | |
| 23 kModuleVariableEntryLength // Sentinel value. | |
| 24 }; | |
| 25 | |
| 26 #ifdef DEBUG | |
| 27 bool ScopeInfo::Equals(ScopeInfo* other) const { | |
| 28 if (length() != other->length()) return false; | |
| 29 for (int index = 0; index < length(); ++index) { | |
| 30 Object* entry = get(index); | |
| 31 Object* other_entry = other->get(index); | |
| 32 if (entry->IsSmi()) { | |
| 33 if (entry != other_entry) return false; | |
| 34 } else { | |
| 35 if (HeapObject::cast(entry)->map()->instance_type() != | |
| 36 HeapObject::cast(other_entry)->map()->instance_type()) { | |
| 37 return false; | |
| 38 } | |
| 39 if (entry->IsString()) { | |
| 40 if (!String::cast(entry)->Equals(String::cast(other_entry))) { | |
| 41 return false; | |
| 42 } | |
| 43 } else if (entry->IsScopeInfo()) { | |
| 44 if (!ScopeInfo::cast(entry)->Equals(ScopeInfo::cast(other_entry))) { | |
| 45 return false; | |
| 46 } | |
| 47 } else if (entry->IsModuleInfo()) { | |
| 48 if (!ModuleInfo::cast(entry)->Equals(ModuleInfo::cast(other_entry))) { | |
| 49 return false; | |
| 50 } | |
| 51 } else { | |
| 52 UNREACHABLE(); | |
| 53 return false; | |
| 54 } | |
| 55 } | |
| 56 } | |
| 57 return true; | |
| 58 } | |
| 59 #endif | |
| 60 | |
| 61 Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, | |
| 62 MaybeHandle<ScopeInfo> outer_scope) { | |
| 63 // Collect variables. | |
| 64 int stack_local_count = 0; | |
| 65 int context_local_count = 0; | |
| 66 int module_vars_count = 0; | |
| 67 // Stack allocated block scope variables are allocated in the parent | |
| 68 // declaration scope, but are recorded in the block scope's scope info. First | |
| 69 // slot index indicates at which offset a particular scope starts in the | |
| 70 // parent declaration scope. | |
| 71 int first_slot_index = 0; | |
| 72 for (Variable* var : *scope->locals()) { | |
| 73 switch (var->location()) { | |
| 74 case VariableLocation::LOCAL: | |
| 75 if (stack_local_count == 0) first_slot_index = var->index(); | |
| 76 stack_local_count++; | |
| 77 break; | |
| 78 case VariableLocation::CONTEXT: | |
| 79 context_local_count++; | |
| 80 break; | |
| 81 case VariableLocation::MODULE: | |
| 82 module_vars_count++; | |
| 83 break; | |
| 84 default: | |
| 85 break; | |
| 86 } | |
| 87 } | |
| 88 DCHECK(module_vars_count == 0 || scope->is_module_scope()); | |
| 89 | |
| 90 // Make sure we allocate the correct amount. | |
| 91 DCHECK_EQ(scope->ContextLocalCount(), context_local_count); | |
| 92 | |
| 93 // Determine use and location of the "this" binding if it is present. | |
| 94 VariableAllocationInfo receiver_info; | |
| 95 if (scope->is_declaration_scope() && | |
| 96 scope->AsDeclarationScope()->has_this_declaration()) { | |
| 97 Variable* var = scope->AsDeclarationScope()->receiver(); | |
| 98 if (!var->is_used()) { | |
| 99 receiver_info = UNUSED; | |
| 100 } else if (var->IsContextSlot()) { | |
| 101 receiver_info = CONTEXT; | |
| 102 } else { | |
| 103 DCHECK(var->IsParameter()); | |
| 104 receiver_info = STACK; | |
| 105 } | |
| 106 } else { | |
| 107 receiver_info = NONE; | |
| 108 } | |
| 109 | |
| 110 bool has_new_target = | |
| 111 scope->is_declaration_scope() && | |
| 112 scope->AsDeclarationScope()->new_target_var() != nullptr; | |
| 113 | |
| 114 // Determine use and location of the function variable if it is present. | |
| 115 VariableAllocationInfo function_name_info; | |
| 116 if (scope->is_function_scope() && | |
| 117 scope->AsDeclarationScope()->function_var() != nullptr) { | |
| 118 Variable* var = scope->AsDeclarationScope()->function_var(); | |
| 119 if (!var->is_used()) { | |
| 120 function_name_info = UNUSED; | |
| 121 } else if (var->IsContextSlot()) { | |
| 122 function_name_info = CONTEXT; | |
| 123 } else { | |
| 124 DCHECK(var->IsStackLocal()); | |
| 125 function_name_info = STACK; | |
| 126 } | |
| 127 } else { | |
| 128 function_name_info = NONE; | |
| 129 } | |
| 130 | |
| 131 const bool has_function_name = function_name_info != NONE; | |
| 132 const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT; | |
| 133 const int parameter_count = scope->num_parameters(); | |
| 134 const bool has_outer_scope_info = !outer_scope.is_null(); | |
| 135 const int length = kVariablePartIndex + parameter_count + | |
| 136 (1 + stack_local_count) + 2 * context_local_count + | |
| 137 (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) + | |
| 138 (has_outer_scope_info ? 1 : 0) + | |
| 139 (scope->is_module_scope() | |
| 140 ? 2 + kModuleVariableEntryLength * module_vars_count | |
| 141 : 0); | |
| 142 | |
| 143 Factory* factory = isolate->factory(); | |
| 144 Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); | |
| 145 | |
| 146 bool has_simple_parameters = false; | |
| 147 bool asm_module = false; | |
| 148 bool asm_function = false; | |
| 149 if (scope->is_function_scope()) { | |
| 150 DeclarationScope* function_scope = scope->AsDeclarationScope(); | |
| 151 has_simple_parameters = function_scope->has_simple_parameters(); | |
| 152 asm_module = function_scope->asm_module(); | |
| 153 asm_function = function_scope->asm_function(); | |
| 154 } | |
| 155 FunctionKind function_kind = kNormalFunction; | |
| 156 if (scope->is_declaration_scope()) { | |
| 157 function_kind = scope->AsDeclarationScope()->function_kind(); | |
| 158 } | |
| 159 | |
| 160 // Encode the flags. | |
| 161 int flags = | |
| 162 ScopeTypeField::encode(scope->scope_type()) | | |
| 163 CallsEvalField::encode(scope->calls_eval()) | | |
| 164 LanguageModeField::encode(scope->language_mode()) | | |
| 165 DeclarationScopeField::encode(scope->is_declaration_scope()) | | |
| 166 ReceiverVariableField::encode(receiver_info) | | |
| 167 HasNewTargetField::encode(has_new_target) | | |
| 168 FunctionVariableField::encode(function_name_info) | | |
| 169 AsmModuleField::encode(asm_module) | | |
| 170 AsmFunctionField::encode(asm_function) | | |
| 171 HasSimpleParametersField::encode(has_simple_parameters) | | |
| 172 FunctionKindField::encode(function_kind) | | |
| 173 HasOuterScopeInfoField::encode(has_outer_scope_info) | | |
| 174 IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope()); | |
| 175 scope_info->SetFlags(flags); | |
| 176 | |
| 177 scope_info->SetParameterCount(parameter_count); | |
| 178 scope_info->SetStackLocalCount(stack_local_count); | |
| 179 scope_info->SetContextLocalCount(context_local_count); | |
| 180 | |
| 181 int index = kVariablePartIndex; | |
| 182 // Add parameters. | |
| 183 DCHECK_EQ(index, scope_info->ParameterNamesIndex()); | |
| 184 if (scope->is_declaration_scope()) { | |
| 185 for (int i = 0; i < parameter_count; ++i) { | |
| 186 scope_info->set(index++, | |
| 187 *scope->AsDeclarationScope()->parameter(i)->name()); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 // Add stack locals' names, context locals' names and info, module variables' | |
| 192 // names and info. We are assuming that the stack locals' slots are allocated | |
| 193 // in increasing order, so we can simply add them to the ScopeInfo object. | |
| 194 // Context locals are added using their index. | |
| 195 DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); | |
| 196 scope_info->set(index++, Smi::FromInt(first_slot_index)); | |
| 197 DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); | |
| 198 | |
| 199 int stack_local_base = index; | |
| 200 int context_local_base = stack_local_base + stack_local_count; | |
| 201 int context_local_info_base = context_local_base + context_local_count; | |
| 202 int module_var_entry = scope_info->ModuleVariablesIndex(); | |
| 203 | |
| 204 for (Variable* var : *scope->locals()) { | |
| 205 switch (var->location()) { | |
| 206 case VariableLocation::LOCAL: { | |
| 207 int local_index = var->index() - first_slot_index; | |
| 208 DCHECK_LE(0, local_index); | |
| 209 DCHECK_LT(local_index, stack_local_count); | |
| 210 scope_info->set(stack_local_base + local_index, *var->name()); | |
| 211 break; | |
| 212 } | |
| 213 case VariableLocation::CONTEXT: { | |
| 214 // Due to duplicate parameters, context locals aren't guaranteed to come | |
| 215 // in order. | |
| 216 int local_index = var->index() - Context::MIN_CONTEXT_SLOTS; | |
| 217 DCHECK_LE(0, local_index); | |
| 218 DCHECK_LT(local_index, context_local_count); | |
| 219 uint32_t info = VariableModeField::encode(var->mode()) | | |
| 220 InitFlagField::encode(var->initialization_flag()) | | |
| 221 MaybeAssignedFlagField::encode(var->maybe_assigned()); | |
| 222 scope_info->set(context_local_base + local_index, *var->name()); | |
| 223 scope_info->set(context_local_info_base + local_index, | |
| 224 Smi::FromInt(info)); | |
| 225 break; | |
| 226 } | |
| 227 case VariableLocation::MODULE: { | |
| 228 scope_info->set(module_var_entry + kModuleVariableNameOffset, | |
| 229 *var->name()); | |
| 230 scope_info->set(module_var_entry + kModuleVariableIndexOffset, | |
| 231 Smi::FromInt(var->index())); | |
| 232 uint32_t properties = | |
| 233 VariableModeField::encode(var->mode()) | | |
| 234 InitFlagField::encode(var->initialization_flag()) | | |
| 235 MaybeAssignedFlagField::encode(var->maybe_assigned()); | |
| 236 scope_info->set(module_var_entry + kModuleVariablePropertiesOffset, | |
| 237 Smi::FromInt(properties)); | |
| 238 module_var_entry += kModuleVariableEntryLength; | |
| 239 break; | |
| 240 } | |
| 241 default: | |
| 242 break; | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 index += stack_local_count + 2 * context_local_count; | |
| 247 | |
| 248 // If the receiver is allocated, add its index. | |
| 249 DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); | |
| 250 if (has_receiver) { | |
| 251 int var_index = scope->AsDeclarationScope()->receiver()->index(); | |
| 252 scope_info->set(index++, Smi::FromInt(var_index)); | |
| 253 // ?? DCHECK(receiver_info != CONTEXT || var_index == | |
| 254 // scope_info->ContextLength() - 1); | |
| 255 } | |
| 256 | |
| 257 // If present, add the function variable name and its index. | |
| 258 DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); | |
| 259 if (has_function_name) { | |
| 260 int var_index = scope->AsDeclarationScope()->function_var()->index(); | |
| 261 scope_info->set(index++, | |
| 262 *scope->AsDeclarationScope()->function_var()->name()); | |
| 263 scope_info->set(index++, Smi::FromInt(var_index)); | |
| 264 DCHECK(function_name_info != CONTEXT || | |
| 265 var_index == scope_info->ContextLength() - 1); | |
| 266 } | |
| 267 | |
| 268 // If present, add the outer scope info. | |
| 269 DCHECK(index == scope_info->OuterScopeInfoIndex()); | |
| 270 if (has_outer_scope_info) { | |
| 271 scope_info->set(index++, *outer_scope.ToHandleChecked()); | |
| 272 } | |
| 273 | |
| 274 // Module-specific information (only for module scopes). | |
| 275 if (scope->is_module_scope()) { | |
| 276 Handle<ModuleInfo> module_info = | |
| 277 ModuleInfo::New(isolate, zone, scope->AsModuleScope()->module()); | |
| 278 DCHECK_EQ(index, scope_info->ModuleInfoIndex()); | |
| 279 scope_info->set(index++, *module_info); | |
| 280 DCHECK_EQ(index, scope_info->ModuleVariableCountIndex()); | |
| 281 scope_info->set(index++, Smi::FromInt(module_vars_count)); | |
| 282 DCHECK_EQ(index, scope_info->ModuleVariablesIndex()); | |
| 283 // The variable entries themselves have already been written above. | |
| 284 index += kModuleVariableEntryLength * module_vars_count; | |
| 285 } | |
| 286 | |
| 287 DCHECK_EQ(index, scope_info->length()); | |
| 288 DCHECK_EQ(scope->num_parameters(), scope_info->ParameterCount()); | |
| 289 DCHECK_EQ(scope->num_heap_slots(), scope_info->ContextLength()); | |
| 290 return scope_info; | |
| 291 } | |
| 292 | |
| 293 Handle<ScopeInfo> ScopeInfo::CreateForWithScope( | |
| 294 Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) { | |
| 295 const bool has_outer_scope_info = !outer_scope.is_null(); | |
| 296 const int length = kVariablePartIndex + 1 + (has_outer_scope_info ? 1 : 0); | |
| 297 | |
| 298 Factory* factory = isolate->factory(); | |
| 299 Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); | |
| 300 | |
| 301 // Encode the flags. | |
| 302 int flags = | |
| 303 ScopeTypeField::encode(WITH_SCOPE) | CallsEvalField::encode(false) | | |
| 304 LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(false) | | |
| 305 ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) | | |
| 306 FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) | | |
| 307 AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) | | |
| 308 FunctionKindField::encode(kNormalFunction) | | |
| 309 HasOuterScopeInfoField::encode(has_outer_scope_info) | | |
| 310 IsDebugEvaluateScopeField::encode(false); | |
| 311 scope_info->SetFlags(flags); | |
| 312 | |
| 313 scope_info->SetParameterCount(0); | |
| 314 scope_info->SetStackLocalCount(0); | |
| 315 scope_info->SetContextLocalCount(0); | |
| 316 | |
| 317 int index = kVariablePartIndex; | |
| 318 DCHECK_EQ(index, scope_info->ParameterNamesIndex()); | |
| 319 DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); | |
| 320 scope_info->set(index++, Smi::kZero); | |
| 321 DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); | |
| 322 DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); | |
| 323 DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); | |
| 324 DCHECK(index == scope_info->OuterScopeInfoIndex()); | |
| 325 if (has_outer_scope_info) { | |
| 326 scope_info->set(index++, *outer_scope.ToHandleChecked()); | |
| 327 } | |
| 328 DCHECK_EQ(index, scope_info->length()); | |
| 329 DCHECK_EQ(0, scope_info->ParameterCount()); | |
| 330 DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope_info->ContextLength()); | |
| 331 return scope_info; | |
| 332 } | |
| 333 | |
| 334 Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) { | |
| 335 DCHECK(isolate->bootstrapper()->IsActive()); | |
| 336 | |
| 337 const int stack_local_count = 0; | |
| 338 const int context_local_count = 1; | |
| 339 const bool has_simple_parameters = true; | |
| 340 const VariableAllocationInfo receiver_info = CONTEXT; | |
| 341 const VariableAllocationInfo function_name_info = NONE; | |
| 342 const bool has_function_name = false; | |
| 343 const bool has_receiver = true; | |
| 344 const bool has_outer_scope_info = false; | |
| 345 const int parameter_count = 0; | |
| 346 const int length = kVariablePartIndex + parameter_count + | |
| 347 (1 + stack_local_count) + 2 * context_local_count + | |
| 348 (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) + | |
| 349 (has_outer_scope_info ? 1 : 0); | |
| 350 | |
| 351 Factory* factory = isolate->factory(); | |
| 352 Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); | |
| 353 | |
| 354 // Encode the flags. | |
| 355 int flags = | |
| 356 ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) | | |
| 357 LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) | | |
| 358 ReceiverVariableField::encode(receiver_info) | | |
| 359 FunctionVariableField::encode(function_name_info) | | |
| 360 AsmModuleField::encode(false) | AsmFunctionField::encode(false) | | |
| 361 HasSimpleParametersField::encode(has_simple_parameters) | | |
| 362 FunctionKindField::encode(FunctionKind::kNormalFunction) | | |
| 363 HasOuterScopeInfoField::encode(has_outer_scope_info) | | |
| 364 IsDebugEvaluateScopeField::encode(false); | |
| 365 scope_info->SetFlags(flags); | |
| 366 scope_info->SetParameterCount(parameter_count); | |
| 367 scope_info->SetStackLocalCount(stack_local_count); | |
| 368 scope_info->SetContextLocalCount(context_local_count); | |
| 369 | |
| 370 int index = kVariablePartIndex; | |
| 371 const int first_slot_index = 0; | |
| 372 DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); | |
| 373 scope_info->set(index++, Smi::FromInt(first_slot_index)); | |
| 374 DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); | |
| 375 | |
| 376 // Here we add info for context-allocated "this". | |
| 377 DCHECK_EQ(index, scope_info->ContextLocalNamesIndex()); | |
| 378 scope_info->set(index++, isolate->heap()->this_string()); | |
| 379 DCHECK_EQ(index, scope_info->ContextLocalInfosIndex()); | |
| 380 const uint32_t value = VariableModeField::encode(CONST) | | |
| 381 InitFlagField::encode(kCreatedInitialized) | | |
| 382 MaybeAssignedFlagField::encode(kNotAssigned); | |
| 383 scope_info->set(index++, Smi::FromInt(value)); | |
| 384 | |
| 385 // And here we record that this scopeinfo binds a receiver. | |
| 386 DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); | |
| 387 const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0; | |
| 388 scope_info->set(index++, Smi::FromInt(receiver_index)); | |
| 389 | |
| 390 DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); | |
| 391 DCHECK_EQ(index, scope_info->OuterScopeInfoIndex()); | |
| 392 DCHECK_EQ(index, scope_info->length()); | |
| 393 DCHECK_EQ(scope_info->ParameterCount(), 0); | |
| 394 DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1); | |
| 395 | |
| 396 return scope_info; | |
| 397 } | |
| 398 | |
| 399 | |
| 400 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { | |
| 401 return isolate->heap()->empty_scope_info(); | |
| 402 } | |
| 403 | |
| 404 | |
| 405 ScopeType ScopeInfo::scope_type() { | |
| 406 DCHECK_LT(0, length()); | |
| 407 return ScopeTypeField::decode(Flags()); | |
| 408 } | |
| 409 | |
| 410 | |
| 411 bool ScopeInfo::CallsEval() { | |
| 412 return length() > 0 && CallsEvalField::decode(Flags()); | |
| 413 } | |
| 414 | |
| 415 | |
| 416 LanguageMode ScopeInfo::language_mode() { | |
| 417 return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY; | |
| 418 } | |
| 419 | |
| 420 | |
| 421 bool ScopeInfo::is_declaration_scope() { | |
| 422 return DeclarationScopeField::decode(Flags()); | |
| 423 } | |
| 424 | |
| 425 | |
| 426 int ScopeInfo::LocalCount() { | |
| 427 return StackLocalCount() + ContextLocalCount(); | |
| 428 } | |
| 429 | |
| 430 | |
| 431 int ScopeInfo::StackSlotCount() { | |
| 432 if (length() > 0) { | |
| 433 bool function_name_stack_slot = | |
| 434 FunctionVariableField::decode(Flags()) == STACK; | |
| 435 return StackLocalCount() + (function_name_stack_slot ? 1 : 0); | |
| 436 } | |
| 437 return 0; | |
| 438 } | |
| 439 | |
| 440 | |
| 441 int ScopeInfo::ContextLength() { | |
| 442 if (length() > 0) { | |
| 443 int context_locals = ContextLocalCount(); | |
| 444 bool function_name_context_slot = | |
| 445 FunctionVariableField::decode(Flags()) == CONTEXT; | |
| 446 bool has_context = context_locals > 0 || function_name_context_slot || | |
| 447 scope_type() == WITH_SCOPE || | |
| 448 (scope_type() == BLOCK_SCOPE && CallsSloppyEval() && | |
| 449 is_declaration_scope()) || | |
| 450 (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) || | |
| 451 (scope_type() == FUNCTION_SCOPE && IsAsmModule()) || | |
| 452 scope_type() == MODULE_SCOPE; | |
| 453 | |
| 454 if (has_context) { | |
| 455 return Context::MIN_CONTEXT_SLOTS + context_locals + | |
| 456 (function_name_context_slot ? 1 : 0); | |
| 457 } | |
| 458 } | |
| 459 return 0; | |
| 460 } | |
| 461 | |
| 462 | |
| 463 bool ScopeInfo::HasReceiver() { | |
| 464 if (length() > 0) { | |
| 465 return NONE != ReceiverVariableField::decode(Flags()); | |
| 466 } else { | |
| 467 return false; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 | |
| 472 bool ScopeInfo::HasAllocatedReceiver() { | |
| 473 if (length() > 0) { | |
| 474 VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags()); | |
| 475 return allocation == STACK || allocation == CONTEXT; | |
| 476 } else { | |
| 477 return false; | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 | |
| 482 bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); } | |
| 483 | |
| 484 | |
| 485 bool ScopeInfo::HasFunctionName() { | |
| 486 if (length() > 0) { | |
| 487 return NONE != FunctionVariableField::decode(Flags()); | |
| 488 } else { | |
| 489 return false; | |
| 490 } | |
| 491 } | |
| 492 | |
| 493 bool ScopeInfo::HasOuterScopeInfo() { | |
| 494 if (length() > 0) { | |
| 495 return HasOuterScopeInfoField::decode(Flags()); | |
| 496 } else { | |
| 497 return false; | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 bool ScopeInfo::IsDebugEvaluateScope() { | |
| 502 if (length() > 0) { | |
| 503 return IsDebugEvaluateScopeField::decode(Flags()); | |
| 504 } else { | |
| 505 return false; | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 void ScopeInfo::SetIsDebugEvaluateScope() { | |
| 510 if (length() > 0) { | |
| 511 DCHECK_EQ(scope_type(), WITH_SCOPE); | |
| 512 SetFlags(Flags() | IsDebugEvaluateScopeField::encode(true)); | |
| 513 } else { | |
| 514 UNREACHABLE(); | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 bool ScopeInfo::HasHeapAllocatedLocals() { | |
| 519 if (length() > 0) { | |
| 520 return ContextLocalCount() > 0; | |
| 521 } else { | |
| 522 return false; | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 | |
| 527 bool ScopeInfo::HasContext() { | |
| 528 return ContextLength() > 0; | |
| 529 } | |
| 530 | |
| 531 | |
| 532 String* ScopeInfo::FunctionName() { | |
| 533 DCHECK(HasFunctionName()); | |
| 534 return String::cast(get(FunctionNameInfoIndex())); | |
| 535 } | |
| 536 | |
| 537 ScopeInfo* ScopeInfo::OuterScopeInfo() { | |
| 538 DCHECK(HasOuterScopeInfo()); | |
| 539 return ScopeInfo::cast(get(OuterScopeInfoIndex())); | |
| 540 } | |
| 541 | |
| 542 ModuleInfo* ScopeInfo::ModuleDescriptorInfo() { | |
| 543 DCHECK(scope_type() == MODULE_SCOPE); | |
| 544 return ModuleInfo::cast(get(ModuleInfoIndex())); | |
| 545 } | |
| 546 | |
| 547 String* ScopeInfo::ParameterName(int var) { | |
| 548 DCHECK_LE(0, var); | |
| 549 DCHECK_LT(var, ParameterCount()); | |
| 550 int info_index = ParameterNamesIndex() + var; | |
| 551 return String::cast(get(info_index)); | |
| 552 } | |
| 553 | |
| 554 | |
| 555 String* ScopeInfo::LocalName(int var) { | |
| 556 DCHECK_LE(0, var); | |
| 557 DCHECK_LT(var, LocalCount()); | |
| 558 DCHECK(StackLocalNamesIndex() + StackLocalCount() == | |
| 559 ContextLocalNamesIndex()); | |
| 560 int info_index = StackLocalNamesIndex() + var; | |
| 561 return String::cast(get(info_index)); | |
| 562 } | |
| 563 | |
| 564 | |
| 565 String* ScopeInfo::StackLocalName(int var) { | |
| 566 DCHECK_LE(0, var); | |
| 567 DCHECK_LT(var, StackLocalCount()); | |
| 568 int info_index = StackLocalNamesIndex() + var; | |
| 569 return String::cast(get(info_index)); | |
| 570 } | |
| 571 | |
| 572 | |
| 573 int ScopeInfo::StackLocalIndex(int var) { | |
| 574 DCHECK_LE(0, var); | |
| 575 DCHECK_LT(var, StackLocalCount()); | |
| 576 int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); | |
| 577 return first_slot_index + var; | |
| 578 } | |
| 579 | |
| 580 | |
| 581 String* ScopeInfo::ContextLocalName(int var) { | |
| 582 DCHECK_LE(0, var); | |
| 583 DCHECK_LT(var, ContextLocalCount()); | |
| 584 int info_index = ContextLocalNamesIndex() + var; | |
| 585 return String::cast(get(info_index)); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 VariableMode ScopeInfo::ContextLocalMode(int var) { | |
| 590 DCHECK_LE(0, var); | |
| 591 DCHECK_LT(var, ContextLocalCount()); | |
| 592 int info_index = ContextLocalInfosIndex() + var; | |
| 593 int value = Smi::cast(get(info_index))->value(); | |
| 594 return VariableModeField::decode(value); | |
| 595 } | |
| 596 | |
| 597 | |
| 598 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) { | |
| 599 DCHECK_LE(0, var); | |
| 600 DCHECK_LT(var, ContextLocalCount()); | |
| 601 int info_index = ContextLocalInfosIndex() + var; | |
| 602 int value = Smi::cast(get(info_index))->value(); | |
| 603 return InitFlagField::decode(value); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) { | |
| 608 DCHECK_LE(0, var); | |
| 609 DCHECK_LT(var, ContextLocalCount()); | |
| 610 int info_index = ContextLocalInfosIndex() + var; | |
| 611 int value = Smi::cast(get(info_index))->value(); | |
| 612 return MaybeAssignedFlagField::decode(value); | |
| 613 } | |
| 614 | |
| 615 bool ScopeInfo::VariableIsSynthetic(String* name) { | |
| 616 // There's currently no flag stored on the ScopeInfo to indicate that a | |
| 617 // variable is a compiler-introduced temporary. However, to avoid conflict | |
| 618 // with user declarations, the current temporaries like .generator_object and | |
| 619 // .result start with a dot, so we can use that as a flag. It's a hack! | |
| 620 return name->length() == 0 || name->Get(0) == '.' || | |
| 621 name->Equals(name->GetHeap()->this_string()); | |
| 622 } | |
| 623 | |
| 624 | |
| 625 int ScopeInfo::StackSlotIndex(String* name) { | |
| 626 DCHECK(name->IsInternalizedString()); | |
| 627 if (length() > 0) { | |
| 628 int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); | |
| 629 int start = StackLocalNamesIndex(); | |
| 630 int end = start + StackLocalCount(); | |
| 631 for (int i = start; i < end; ++i) { | |
| 632 if (name == get(i)) { | |
| 633 return i - start + first_slot_index; | |
| 634 } | |
| 635 } | |
| 636 } | |
| 637 return -1; | |
| 638 } | |
| 639 | |
| 640 int ScopeInfo::ModuleIndex(Handle<String> name, VariableMode* mode, | |
| 641 InitializationFlag* init_flag, | |
| 642 MaybeAssignedFlag* maybe_assigned_flag) { | |
| 643 DCHECK_EQ(scope_type(), MODULE_SCOPE); | |
| 644 DCHECK(name->IsInternalizedString()); | |
| 645 DCHECK_NOT_NULL(mode); | |
| 646 DCHECK_NOT_NULL(init_flag); | |
| 647 DCHECK_NOT_NULL(maybe_assigned_flag); | |
| 648 | |
| 649 int module_vars_count = Smi::cast(get(ModuleVariableCountIndex()))->value(); | |
| 650 int entry = ModuleVariablesIndex(); | |
| 651 for (int i = 0; i < module_vars_count; ++i) { | |
| 652 if (*name == get(entry + kModuleVariableNameOffset)) { | |
| 653 int index; | |
| 654 ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag); | |
| 655 return index; | |
| 656 } | |
| 657 entry += kModuleVariableEntryLength; | |
| 658 } | |
| 659 | |
| 660 return 0; | |
| 661 } | |
| 662 | |
| 663 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info, | |
| 664 Handle<String> name, VariableMode* mode, | |
| 665 InitializationFlag* init_flag, | |
| 666 MaybeAssignedFlag* maybe_assigned_flag) { | |
| 667 DCHECK(name->IsInternalizedString()); | |
| 668 DCHECK_NOT_NULL(mode); | |
| 669 DCHECK_NOT_NULL(init_flag); | |
| 670 DCHECK_NOT_NULL(maybe_assigned_flag); | |
| 671 | |
| 672 if (scope_info->length() > 0) { | |
| 673 ContextSlotCache* context_slot_cache = | |
| 674 scope_info->GetIsolate()->context_slot_cache(); | |
| 675 int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag, | |
| 676 maybe_assigned_flag); | |
| 677 if (result != ContextSlotCache::kNotFound) { | |
| 678 DCHECK_LT(result, scope_info->ContextLength()); | |
| 679 return result; | |
| 680 } | |
| 681 | |
| 682 int start = scope_info->ContextLocalNamesIndex(); | |
| 683 int end = start + scope_info->ContextLocalCount(); | |
| 684 for (int i = start; i < end; ++i) { | |
| 685 if (*name == scope_info->get(i)) { | |
| 686 int var = i - start; | |
| 687 *mode = scope_info->ContextLocalMode(var); | |
| 688 *init_flag = scope_info->ContextLocalInitFlag(var); | |
| 689 *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var); | |
| 690 result = Context::MIN_CONTEXT_SLOTS + var; | |
| 691 | |
| 692 context_slot_cache->Update(scope_info, name, *mode, *init_flag, | |
| 693 *maybe_assigned_flag, result); | |
| 694 DCHECK_LT(result, scope_info->ContextLength()); | |
| 695 return result; | |
| 696 } | |
| 697 } | |
| 698 // Cache as not found. Mode, init flag and maybe assigned flag don't matter. | |
| 699 context_slot_cache->Update(scope_info, name, TEMPORARY, | |
| 700 kNeedsInitialization, kNotAssigned, -1); | |
| 701 } | |
| 702 | |
| 703 return -1; | |
| 704 } | |
| 705 | |
| 706 String* ScopeInfo::ContextSlotName(int slot_index) { | |
| 707 int const var = slot_index - Context::MIN_CONTEXT_SLOTS; | |
| 708 DCHECK_LE(0, var); | |
| 709 DCHECK_LT(var, ContextLocalCount()); | |
| 710 return ContextLocalName(var); | |
| 711 } | |
| 712 | |
| 713 | |
| 714 int ScopeInfo::ParameterIndex(String* name) { | |
| 715 DCHECK(name->IsInternalizedString()); | |
| 716 if (length() > 0) { | |
| 717 // We must read parameters from the end since for | |
| 718 // multiply declared parameters the value of the | |
| 719 // last declaration of that parameter is used | |
| 720 // inside a function (and thus we need to look | |
| 721 // at the last index). Was bug# 1110337. | |
| 722 int start = ParameterNamesIndex(); | |
| 723 int end = start + ParameterCount(); | |
| 724 for (int i = end - 1; i >= start; --i) { | |
| 725 if (name == get(i)) { | |
| 726 return i - start; | |
| 727 } | |
| 728 } | |
| 729 } | |
| 730 return -1; | |
| 731 } | |
| 732 | |
| 733 | |
| 734 int ScopeInfo::ReceiverContextSlotIndex() { | |
| 735 if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT) | |
| 736 return Smi::cast(get(ReceiverInfoIndex()))->value(); | |
| 737 return -1; | |
| 738 } | |
| 739 | |
| 740 int ScopeInfo::FunctionContextSlotIndex(String* name) { | |
| 741 DCHECK(name->IsInternalizedString()); | |
| 742 if (length() > 0) { | |
| 743 if (FunctionVariableField::decode(Flags()) == CONTEXT && | |
| 744 FunctionName() == name) { | |
| 745 return Smi::cast(get(FunctionNameInfoIndex() + 1))->value(); | |
| 746 } | |
| 747 } | |
| 748 return -1; | |
| 749 } | |
| 750 | |
| 751 | |
| 752 FunctionKind ScopeInfo::function_kind() { | |
| 753 return FunctionKindField::decode(Flags()); | |
| 754 } | |
| 755 | |
| 756 int ScopeInfo::ParameterNamesIndex() { | |
| 757 DCHECK_LT(0, length()); | |
| 758 return kVariablePartIndex; | |
| 759 } | |
| 760 | |
| 761 | |
| 762 int ScopeInfo::StackLocalFirstSlotIndex() { | |
| 763 return ParameterNamesIndex() + ParameterCount(); | |
| 764 } | |
| 765 | |
| 766 int ScopeInfo::StackLocalNamesIndex() { return StackLocalFirstSlotIndex() + 1; } | |
| 767 | |
| 768 int ScopeInfo::ContextLocalNamesIndex() { | |
| 769 return StackLocalNamesIndex() + StackLocalCount(); | |
| 770 } | |
| 771 | |
| 772 int ScopeInfo::ContextLocalInfosIndex() { | |
| 773 return ContextLocalNamesIndex() + ContextLocalCount(); | |
| 774 } | |
| 775 | |
| 776 int ScopeInfo::ReceiverInfoIndex() { | |
| 777 return ContextLocalInfosIndex() + ContextLocalCount(); | |
| 778 } | |
| 779 | |
| 780 int ScopeInfo::FunctionNameInfoIndex() { | |
| 781 return ReceiverInfoIndex() + (HasAllocatedReceiver() ? 1 : 0); | |
| 782 } | |
| 783 | |
| 784 int ScopeInfo::OuterScopeInfoIndex() { | |
| 785 return FunctionNameInfoIndex() + (HasFunctionName() ? 2 : 0); | |
| 786 } | |
| 787 | |
| 788 int ScopeInfo::ModuleInfoIndex() { | |
| 789 return OuterScopeInfoIndex() + (HasOuterScopeInfo() ? 1 : 0); | |
| 790 } | |
| 791 | |
| 792 int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoIndex() + 1; } | |
| 793 | |
| 794 int ScopeInfo::ModuleVariablesIndex() { return ModuleVariableCountIndex() + 1; } | |
| 795 | |
| 796 void ScopeInfo::ModuleVariable(int i, String** name, int* index, | |
| 797 VariableMode* mode, | |
| 798 InitializationFlag* init_flag, | |
| 799 MaybeAssignedFlag* maybe_assigned_flag) { | |
| 800 DCHECK_LE(0, i); | |
| 801 DCHECK_LT(i, Smi::cast(get(ModuleVariableCountIndex()))->value()); | |
| 802 | |
| 803 int entry = ModuleVariablesIndex() + i * kModuleVariableEntryLength; | |
| 804 int properties = | |
| 805 Smi::cast(get(entry + kModuleVariablePropertiesOffset))->value(); | |
| 806 | |
| 807 if (name != nullptr) { | |
| 808 *name = String::cast(get(entry + kModuleVariableNameOffset)); | |
| 809 } | |
| 810 if (index != nullptr) { | |
| 811 *index = Smi::cast(get(entry + kModuleVariableIndexOffset))->value(); | |
| 812 DCHECK_NE(*index, 0); | |
| 813 } | |
| 814 if (mode != nullptr) { | |
| 815 *mode = VariableModeField::decode(properties); | |
| 816 } | |
| 817 if (init_flag != nullptr) { | |
| 818 *init_flag = InitFlagField::decode(properties); | |
| 819 } | |
| 820 if (maybe_assigned_flag != nullptr) { | |
| 821 *maybe_assigned_flag = MaybeAssignedFlagField::decode(properties); | |
| 822 } | |
| 823 } | |
| 824 | |
| 825 #ifdef DEBUG | |
| 826 | |
| 827 static void PrintList(const char* list_name, | |
| 828 int nof_internal_slots, | |
| 829 int start, | |
| 830 int end, | |
| 831 ScopeInfo* scope_info) { | |
| 832 if (start < end) { | |
| 833 PrintF("\n // %s\n", list_name); | |
| 834 if (nof_internal_slots > 0) { | |
| 835 PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); | |
| 836 } | |
| 837 for (int i = nof_internal_slots; start < end; ++i, ++start) { | |
| 838 PrintF(" %2d ", i); | |
| 839 String::cast(scope_info->get(start))->ShortPrint(); | |
| 840 PrintF("\n"); | |
| 841 } | |
| 842 } | |
| 843 } | |
| 844 | |
| 845 | |
| 846 void ScopeInfo::Print() { | |
| 847 PrintF("ScopeInfo "); | |
| 848 if (HasFunctionName()) { | |
| 849 FunctionName()->ShortPrint(); | |
| 850 } else { | |
| 851 PrintF("/* no function name */"); | |
| 852 } | |
| 853 PrintF("{"); | |
| 854 | |
| 855 if (length() > 0) { | |
| 856 PrintList("parameters", 0, ParameterNamesIndex(), | |
| 857 ParameterNamesIndex() + ParameterCount(), this); | |
| 858 PrintList("stack slots", 0, StackLocalNamesIndex(), | |
| 859 StackLocalNamesIndex() + StackLocalCount(), this); | |
| 860 PrintList("context slots", Context::MIN_CONTEXT_SLOTS, | |
| 861 ContextLocalNamesIndex(), | |
| 862 ContextLocalNamesIndex() + ContextLocalCount(), this); | |
| 863 // TODO(neis): Print module stuff if present. | |
| 864 } | |
| 865 | |
| 866 PrintF("}\n"); | |
| 867 } | |
| 868 #endif // DEBUG | |
| 869 | |
| 870 Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate, | |
| 871 Handle<Object> export_name, | |
| 872 Handle<Object> local_name, | |
| 873 Handle<Object> import_name, | |
| 874 int module_request, int cell_index, | |
| 875 int beg_pos, int end_pos) { | |
| 876 Handle<ModuleInfoEntry> result = Handle<ModuleInfoEntry>::cast( | |
| 877 isolate->factory()->NewStruct(MODULE_INFO_ENTRY_TYPE)); | |
| 878 result->set_export_name(*export_name); | |
| 879 result->set_local_name(*local_name); | |
| 880 result->set_import_name(*import_name); | |
| 881 result->set_module_request(module_request); | |
| 882 result->set_cell_index(cell_index); | |
| 883 result->set_beg_pos(beg_pos); | |
| 884 result->set_end_pos(end_pos); | |
| 885 return result; | |
| 886 } | |
| 887 | |
| 888 Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, | |
| 889 ModuleDescriptor* descr) { | |
| 890 // Serialize module requests. | |
| 891 Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray( | |
| 892 static_cast<int>(descr->module_requests().size())); | |
| 893 for (const auto& elem : descr->module_requests()) { | |
| 894 module_requests->set(elem.second, *elem.first->string()); | |
| 895 } | |
| 896 | |
| 897 // Serialize special exports. | |
| 898 Handle<FixedArray> special_exports = | |
| 899 isolate->factory()->NewFixedArray(descr->special_exports().length()); | |
| 900 { | |
| 901 int i = 0; | |
| 902 for (auto entry : descr->special_exports()) { | |
| 903 Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); | |
| 904 special_exports->set(i++, *serialized_entry); | |
| 905 } | |
| 906 } | |
| 907 | |
| 908 // Serialize namespace imports. | |
| 909 Handle<FixedArray> namespace_imports = | |
| 910 isolate->factory()->NewFixedArray(descr->namespace_imports().length()); | |
| 911 { | |
| 912 int i = 0; | |
| 913 for (auto entry : descr->namespace_imports()) { | |
| 914 Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); | |
| 915 namespace_imports->set(i++, *serialized_entry); | |
| 916 } | |
| 917 } | |
| 918 | |
| 919 // Serialize regular exports. | |
| 920 Handle<FixedArray> regular_exports = | |
| 921 descr->SerializeRegularExports(isolate, zone); | |
| 922 | |
| 923 // Serialize regular imports. | |
| 924 Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray( | |
| 925 static_cast<int>(descr->regular_imports().size())); | |
| 926 { | |
| 927 int i = 0; | |
| 928 for (const auto& elem : descr->regular_imports()) { | |
| 929 Handle<ModuleInfoEntry> serialized_entry = | |
| 930 elem.second->Serialize(isolate); | |
| 931 regular_imports->set(i++, *serialized_entry); | |
| 932 } | |
| 933 } | |
| 934 | |
| 935 Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo(); | |
| 936 result->set(kModuleRequestsIndex, *module_requests); | |
| 937 result->set(kSpecialExportsIndex, *special_exports); | |
| 938 result->set(kRegularExportsIndex, *regular_exports); | |
| 939 result->set(kNamespaceImportsIndex, *namespace_imports); | |
| 940 result->set(kRegularImportsIndex, *regular_imports); | |
| 941 return result; | |
| 942 } | |
| 943 | |
| 944 int ModuleInfo::RegularExportCount() const { | |
| 945 DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0); | |
| 946 return regular_exports()->length() / kRegularExportLength; | |
| 947 } | |
| 948 | |
| 949 String* ModuleInfo::RegularExportLocalName(int i) const { | |
| 950 return String::cast(regular_exports()->get(i * kRegularExportLength + | |
| 951 kRegularExportLocalNameOffset)); | |
| 952 } | |
| 953 | |
| 954 int ModuleInfo::RegularExportCellIndex(int i) const { | |
| 955 return Smi::cast(regular_exports()->get(i * kRegularExportLength + | |
| 956 kRegularExportCellIndexOffset)) | |
| 957 ->value(); | |
| 958 } | |
| 959 | |
| 960 FixedArray* ModuleInfo::RegularExportExportNames(int i) const { | |
| 961 return FixedArray::cast(regular_exports()->get( | |
| 962 i * kRegularExportLength + kRegularExportExportNamesOffset)); | |
| 963 } | |
| 964 | |
| 965 Handle<ModuleInfoEntry> ModuleInfo::LookupRegularImport( | |
| 966 Handle<ModuleInfo> info, Handle<String> local_name) { | |
| 967 Isolate* isolate = info->GetIsolate(); | |
| 968 Handle<FixedArray> regular_imports(info->regular_imports(), isolate); | |
| 969 for (int i = 0, n = regular_imports->length(); i < n; ++i) { | |
| 970 Handle<ModuleInfoEntry> entry( | |
| 971 ModuleInfoEntry::cast(regular_imports->get(i)), isolate); | |
| 972 if (String::cast(entry->local_name())->Equals(*local_name)) { | |
| 973 return entry; | |
| 974 } | |
| 975 } | |
| 976 UNREACHABLE(); | |
| 977 return Handle<ModuleInfoEntry>(); | |
| 978 } | |
| 979 | |
| 980 } // namespace internal | |
| 981 } // namespace v8 | |
| OLD | NEW |