scopes.cc 113 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/ast/scopes.h"
6

7 8
#include <set>

9
#include "src/ast/ast.h"
10
#include "src/base/logging.h"
11
#include "src/base/optional.h"
12
#include "src/builtins/accessors.h"
13
#include "src/common/message-template.h"
14
#include "src/heap/local-factory-inl.h"
15
#include "src/init/bootstrapper.h"
16
#include "src/logging/runtime-call-stats-scope.h"
17
#include "src/objects/module-inl.h"
18
#include "src/objects/objects-inl.h"
19
#include "src/objects/scope-info.h"
20
#include "src/objects/string-set-inl.h"
21
#include "src/parsing/parse-info.h"
22
#include "src/parsing/parser.h"
23
#include "src/parsing/preparse-data.h"
24
#include "src/zone/zone-list-inl.h"
25
#include "src/zone/zone.h"
26

27 28
namespace v8 {
namespace internal {
29 30 31 32 33 34 35 36 37 38

// ----------------------------------------------------------------------------
// Implementation of LocalsMap
//
// Note: We are storing the handle locations as key values in the hash map.
//       When inserting a new variable via Declare(), we rely on the fact that
//       the handle location remains alive for the duration of that variable
//       use. Because a Variable holding a handle with the same location exists
//       this is ensured.

39 40 41 42
static_assert(sizeof(VariableMap) == (sizeof(void*) + 2 * sizeof(uint32_t) +
                                      sizeof(ZoneAllocationPolicy)),
              "Empty base optimization didn't kick in for VariableMap");

43
VariableMap::VariableMap(Zone* zone)
44
    : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {}
45

46 47 48
VariableMap::VariableMap(const VariableMap& other, Zone* zone)
    : ZoneHashMap(other, ZoneAllocationPolicy(zone)) {}

verwaest's avatar
verwaest committed
49 50
Variable* VariableMap::Declare(Zone* zone, Scope* scope,
                               const AstRawString* name, VariableMode mode,
51
                               VariableKind kind,
52
                               InitializationFlag initialization_flag,
53
                               MaybeAssignedFlag maybe_assigned_flag,
54
                               IsStaticFlag is_static_flag, bool* was_added) {
55
  DCHECK_EQ(zone, allocator().zone());
56 57 58
  // AstRawStrings are unambiguous, i.e., the same string is always represented
  // by the same AstRawString*.
  // FIXME(marja): fix the type of Lookup.
59 60
  Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
                                         name->Hash());
61 62
  *was_added = p->value == nullptr;
  if (*was_added) {
63
    // The variable has not been declared yet -> insert it.
64
    DCHECK_EQ(name, p->key);
65
    Variable* variable =
66
        zone->New<Variable>(scope, name, mode, kind, initialization_flag,
67
                            maybe_assigned_flag, is_static_flag);
68
    p->value = variable;
69 70 71 72
  }
  return reinterpret_cast<Variable*>(p->value);
}

73 74
void VariableMap::Remove(Variable* var) {
  const AstRawString* name = var->raw_name();
75
  ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->Hash());
76 77
}

78
void VariableMap::Add(Variable* var) {
79
  const AstRawString* name = var->raw_name();
80 81
  Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
                                         name->Hash());
82 83 84 85
  DCHECK_NULL(p->value);
  DCHECK_EQ(name, p->key);
  p->value = var;
}
86

87
Variable* VariableMap::Lookup(const AstRawString* name) {
88
  Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->Hash());
89
  if (p != nullptr) {
90
    DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
91
    DCHECK_NOT_NULL(p->value);
92 93
    return reinterpret_cast<Variable*>(p->value);
  }
94
  return nullptr;
95 96 97 98 99
}

// ----------------------------------------------------------------------------
// Implementation of Scope

100
Scope::Scope(Zone* zone)
101
    : outer_scope_(nullptr), variables_(zone), scope_type_(SCRIPT_SCOPE) {
102 103 104
  SetDefaults();
}

105
Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
106
    : outer_scope_(outer_scope), variables_(zone), scope_type_(scope_type) {
107
  DCHECK_NE(SCRIPT_SCOPE, scope_type);
108
  SetDefaults();
109
  set_language_mode(outer_scope->language_mode());
110 111 112
  private_name_lookup_skips_outer_class_ =
      outer_scope->is_class_scope() &&
      outer_scope->AsClassScope()->IsParsingHeritage();
113
  outer_scope_->AddInnerScope(this);
114 115
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
Variable* Scope::DeclareHomeObjectVariable(AstValueFactory* ast_value_factory) {
  bool was_added;
  Variable* home_object_variable = Declare(
      zone(), ast_value_factory->dot_home_object_string(), VariableMode::kConst,
      NORMAL_VARIABLE, InitializationFlag::kCreatedInitialized,
      MaybeAssignedFlag::kNotAssigned, &was_added);
  DCHECK(was_added);
  home_object_variable->set_is_used();
  home_object_variable->ForceContextAllocation();
  return home_object_variable;
}

Variable* Scope::DeclareStaticHomeObjectVariable(
    AstValueFactory* ast_value_factory) {
  bool was_added;
  Variable* static_home_object_variable =
      Declare(zone(), ast_value_factory->dot_static_home_object_string(),
              VariableMode::kConst, NORMAL_VARIABLE,
              InitializationFlag::kCreatedInitialized,
              MaybeAssignedFlag::kNotAssigned, &was_added);
  DCHECK(was_added);
  static_home_object_variable->set_is_used();
  static_home_object_variable->ForceContextAllocation();
  return static_home_object_variable;
}

142
DeclarationScope::DeclarationScope(Zone* zone,
143 144 145
                                   AstValueFactory* ast_value_factory,
                                   REPLMode repl_mode)
    : Scope(zone),
146 147 148
      function_kind_(repl_mode == REPLMode::kYes
                         ? FunctionKind::kAsyncFunction
                         : FunctionKind::kNormalFunction),
149
      params_(4, zone) {
150
  DCHECK_EQ(scope_type_, SCRIPT_SCOPE);
151
  SetDefaults();
152
  is_repl_mode_scope_ = repl_mode == REPLMode::kYes;
153 154
  receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
                                   THIS_VARIABLE, this);
155 156
}

157 158
DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
                                   ScopeType scope_type,
159
                                   FunctionKind function_kind)
160 161
    : Scope(zone, outer_scope, scope_type),
      function_kind_(function_kind),
162
      params_(4, zone) {
163
  DCHECK_NE(scope_type, SCRIPT_SCOPE);
164
  SetDefaults();
165 166
}

167
ModuleScope::ModuleScope(DeclarationScope* script_scope,
168
                         AstValueFactory* avfactory)
169 170 171 172 173
    : DeclarationScope(avfactory->single_parse_zone(), script_scope,
                       MODULE_SCOPE, FunctionKind::kModule),
      module_descriptor_(
          avfactory->single_parse_zone()->New<SourceTextModuleDescriptor>(
              avfactory->single_parse_zone())) {
174
  set_language_mode(LanguageMode::kStrict);
175
  DeclareThis(avfactory);
176 177
}

178
ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info,
179
                         AstValueFactory* avfactory)
180 181
    : DeclarationScope(avfactory->single_parse_zone(), MODULE_SCOPE, avfactory,
                       scope_info),
182
      module_descriptor_(nullptr) {
183
  set_language_mode(LanguageMode::kStrict);
184 185
}

186
ClassScope::ClassScope(Zone* zone, Scope* outer_scope, bool is_anonymous)
187
    : Scope(zone, outer_scope, CLASS_SCOPE),
188 189
      rare_data_and_is_parsing_heritage_(nullptr),
      is_anonymous_class_(is_anonymous) {
190 191 192
  set_language_mode(LanguageMode::kStrict);
}

193 194
template <typename IsolateT>
ClassScope::ClassScope(IsolateT* isolate, Zone* zone,
195
                       AstValueFactory* ast_value_factory,
196
                       Handle<ScopeInfo> scope_info)
197
    : Scope(zone, CLASS_SCOPE, ast_value_factory, scope_info),
198
      rare_data_and_is_parsing_heritage_(nullptr) {
199
  set_language_mode(LanguageMode::kStrict);
200
  if (scope_info->ClassScopeHasPrivateBrand()) {
201 202 203 204 205
    Variable* brand =
        LookupInScopeInfo(ast_value_factory->dot_brand_string(), this);
    DCHECK_NOT_NULL(brand);
    EnsureRareData()->brand = brand;
  }
206 207 208

  // If the class variable is context-allocated and its index is
  // saved for deserialization, deserialize it.
209 210 211 212
  if (scope_info->HasSavedClassVariable()) {
    String name;
    int index;
    std::tie(name, index) = scope_info->SavedClassVariable();
213 214 215 216 217 218
    DCHECK_EQ(scope_info->ContextLocalMode(index), VariableMode::kConst);
    DCHECK_EQ(scope_info->ContextLocalInitFlag(index),
              InitializationFlag::kNeedsInitialization);
    DCHECK_EQ(scope_info->ContextLocalMaybeAssignedFlag(index),
              MaybeAssignedFlag::kMaybeAssigned);
    Variable* var = DeclareClassVariable(
219 220 221
        ast_value_factory,
        ast_value_factory->GetString(name,
                                     SharedStringAccessGuardIfNeeded(isolate)),
222 223 224 225
        kNoSourcePosition);
    var->AllocateTo(VariableLocation::CONTEXT,
                    Context::MIN_CONTEXT_SLOTS + index);
  }
226 227 228 229

  DCHECK(scope_info->HasPositionInfo());
  set_start_position(scope_info->StartPosition());
  set_end_position(scope_info->EndPosition());
230
}
231 232 233 234 235 236
template ClassScope::ClassScope(Isolate* isolate, Zone* zone,
                                AstValueFactory* ast_value_factory,
                                Handle<ScopeInfo> scope_info);
template ClassScope::ClassScope(LocalIsolate* isolate, Zone* zone,
                                AstValueFactory* ast_value_factory,
                                Handle<ScopeInfo> scope_info);
237

238 239
Scope::Scope(Zone* zone, ScopeType scope_type,
             AstValueFactory* ast_value_factory, Handle<ScopeInfo> scope_info)
240
    : outer_scope_(nullptr),
241
      variables_(zone),
242
      scope_info_(scope_info),
243
      scope_type_(scope_type) {
244
  DCHECK(!scope_info.is_null());
245
  SetDefaults();
246 247 248
#ifdef DEBUG
  already_resolved_ = true;
#endif
249
  set_language_mode(scope_info->language_mode());
250
  DCHECK_EQ(ContextHeaderLength(), num_heap_slots_);
251 252
  private_name_lookup_skips_outer_class_ =
      scope_info->PrivateNameLookupSkipsOuterClass();
253
  // We don't really need to use the preparsed scope data; this is just to
254
  // shorten the recursion in SetMustUsePreparseData.
255
  must_use_preparsed_scope_data_ = true;
256 257 258 259 260

  if (scope_type == BLOCK_SCOPE) {
    // Set is_block_scope_for_object_literal_ based on the existince of the home
    // object variable (we don't store it explicitly).
    DCHECK_NOT_NULL(ast_value_factory);
261 262
    int home_object_index = scope_info->ContextSlotIndex(
        ast_value_factory->dot_home_object_string()->string());
263 264 265 266 267 268
    DCHECK_IMPLIES(home_object_index >= 0,
                   scope_type == CLASS_SCOPE || scope_type == BLOCK_SCOPE);
    if (home_object_index >= 0) {
      is_block_scope_for_object_literal_ = true;
    }
  }
269 270
}

271
DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type,
272
                                   AstValueFactory* ast_value_factory,
273
                                   Handle<ScopeInfo> scope_info)
274
    : Scope(zone, scope_type, ast_value_factory, scope_info),
275
      function_kind_(scope_info->function_kind()),
276
      params_(0, zone) {
277
  DCHECK_NE(scope_type, SCRIPT_SCOPE);
278
  SetDefaults();
279 280 281 282
  if (scope_info->SloppyEvalCanExtendVars()) {
    DCHECK(!is_eval_scope());
    sloppy_eval_can_extend_vars_ = true;
  }
283 284 285 286
  if (scope_info->ClassScopeHasPrivateBrand()) {
    DCHECK(IsClassConstructor(function_kind()));
    class_scope_has_private_brand_ = true;
  }
287 288
}

289
Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
290
             MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info)
291
    : outer_scope_(nullptr),
292
      variables_(zone),
293
      scope_info_(scope_info),
294
      scope_type_(CATCH_SCOPE) {
295
  SetDefaults();
296 297 298
#ifdef DEBUG
  already_resolved_ = true;
#endif
299 300 301
  // Cache the catch variable, even though it's also available via the
  // scope_info, as the parser expects that a catch scope always has the catch
  // variable as first and only variable.
302
  bool was_added;
303 304
  Variable* variable =
      Declare(zone, catch_variable_name, VariableMode::kVar, NORMAL_VARIABLE,
305 306
              kCreatedInitialized, maybe_assigned, &was_added);
  DCHECK(was_added);
307
  AllocateHeapSlot(variable);
308 309
}

310 311 312
void DeclarationScope::SetDefaults() {
  is_declaration_scope_ = true;
  has_simple_parameters_ = true;
313
#if V8_ENABLE_WEBASSEMBLY
314
  is_asm_module_ = false;
315
#endif  // V8_ENABLE_WEBASSEMBLY
316
  force_eager_compilation_ = false;
317
  has_arguments_parameter_ = false;
318
  uses_super_property_ = false;
319
  has_checked_syntax_ = false;
320 321 322
  has_this_reference_ = false;
  has_this_declaration_ =
      (is_function_scope() && !is_arrow_scope()) || is_module_scope();
323
  needs_private_name_context_chain_recalc_ = false;
324
  has_rest_ = false;
325 326 327 328
  receiver_ = nullptr;
  new_target_ = nullptr;
  function_ = nullptr;
  arguments_ = nullptr;
329
  rare_data_ = nullptr;
330
  should_eager_compile_ = false;
331
  was_lazily_parsed_ = false;
332
  is_skipped_function_ = false;
333
  preparse_data_builder_ = nullptr;
334
  class_scope_has_private_brand_ = false;
335 336 337 338 339 340 341
#ifdef DEBUG
  DeclarationScope* outer_declaration_scope =
      outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr;
  is_being_lazily_parsed_ =
      outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_
                              : false;
#endif
342 343 344 345 346
}

void Scope::SetDefaults() {
#ifdef DEBUG
  scope_name_ = nullptr;
347
  already_resolved_ = false;
348
  needs_migration_ = false;
349 350 351
#endif
  inner_scope_ = nullptr;
  sibling_ = nullptr;
352
  unresolved_list_.Clear();
353 354 355 356

  start_position_ = kNoSourcePosition;
  end_position_ = kNoSourcePosition;

357 358
  calls_eval_ = false;
  sloppy_eval_can_extend_vars_ = false;
359 360
  scope_nonlinear_ = false;
  is_hidden_ = false;
361
  is_debug_evaluate_scope_ = false;
362

363
  inner_scope_calls_eval_ = false;
364
  force_context_allocation_for_parameters_ = false;
365 366

  is_declaration_scope_ = false;
367

368 369
  private_name_lookup_skips_outer_class_ = false;

370
  must_use_preparsed_scope_data_ = false;
Simon Zünd's avatar
Simon Zünd committed
371
  is_repl_mode_scope_ = false;
372

373 374
  deserialized_scope_uses_external_cache_ = false;

375 376 377
  needs_home_object_ = false;
  is_block_scope_for_object_literal_ = false;

378 379 380 381
  num_stack_slots_ = 0;
  num_heap_slots_ = ContextHeaderLength();

  set_language_mode(LanguageMode::kSloppy);
382 383 384 385 386
}

bool Scope::HasSimpleParameters() {
  DeclarationScope* scope = GetClosureScope();
  return !scope->is_function_scope() || scope->has_simple_parameters();
387 388
}

389
void DeclarationScope::set_should_eager_compile() {
390
  should_eager_compile_ = !was_lazily_parsed_;
391 392
}

393
#if V8_ENABLE_WEBASSEMBLY
394
void DeclarationScope::set_is_asm_module() { is_asm_module_ = true; }
395

396
bool Scope::IsAsmModule() const {
397
  return is_function_scope() && AsDeclarationScope()->is_asm_module();
398 399
}

400 401 402 403 404 405 406 407 408 409 410 411 412 413
bool Scope::ContainsAsmModule() const {
  if (IsAsmModule()) return true;

  // Check inner scopes recursively
  for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
    // Don't check inner functions which won't be eagerly compiled.
    if (!scope->is_function_scope() ||
        scope->AsDeclarationScope()->ShouldEagerCompile()) {
      if (scope->ContainsAsmModule()) return true;
    }
  }

  return false;
}
414
#endif  // V8_ENABLE_WEBASSEMBLY
415

416 417
template <typename IsolateT>
Scope* Scope::DeserializeScopeChain(IsolateT* isolate, Zone* zone,
418
                                    ScopeInfo scope_info,
419
                                    DeclarationScope* script_scope,
420 421
                                    AstValueFactory* ast_value_factory,
                                    DeserializationMode deserialization_mode) {
422
  // Reconstruct the outer scope chain from a closure's context chain.
423 424
  Scope* current_scope = nullptr;
  Scope* innermost_scope = nullptr;
425
  Scope* outer_scope = nullptr;
426
  bool cache_scope_found = false;
427
  while (!scope_info.is_null()) {
428 429
    if (scope_info.scope_type() == WITH_SCOPE) {
      if (scope_info.IsDebugEvaluateScope()) {
430 431 432
        outer_scope =
            zone->New<DeclarationScope>(zone, FUNCTION_SCOPE, ast_value_factory,
                                        handle(scope_info, isolate));
433
        outer_scope->set_is_debug_evaluate_scope();
434 435
      } else {
        // For scope analysis, debug-evaluate is equivalent to a with scope.
436 437
        outer_scope = zone->New<Scope>(zone, WITH_SCOPE, ast_value_factory,
                                       handle(scope_info, isolate));
438
      }
439

440
    } else if (scope_info.scope_type() == SCRIPT_SCOPE) {
441 442 443
      // If we reach a script scope, it's the outermost scope. Install the
      // scope info of this script context onto the existing script scope to
      // avoid nesting script scopes.
444
      if (deserialization_mode == DeserializationMode::kIncludingVariables) {
445
        script_scope->SetScriptScopeInfo(handle(scope_info, isolate));
446
      }
Simon Zünd's avatar
Simon Zünd committed
447
      if (scope_info.IsReplModeScope()) script_scope->set_is_repl_mode_scope();
448
      DCHECK(!scope_info.HasOuterScopeInfo());
449
      break;
450
    } else if (scope_info.scope_type() == FUNCTION_SCOPE) {
451 452
      outer_scope = zone->New<DeclarationScope>(
          zone, FUNCTION_SCOPE, ast_value_factory, handle(scope_info, isolate));
453
#if V8_ENABLE_WEBASSEMBLY
454
      if (scope_info.IsAsmModule()) {
455 456
        outer_scope->AsDeclarationScope()->set_is_asm_module();
      }
457
#endif  // V8_ENABLE_WEBASSEMBLY
458
    } else if (scope_info.scope_type() == EVAL_SCOPE) {
459 460
      outer_scope = zone->New<DeclarationScope>(
          zone, EVAL_SCOPE, ast_value_factory, handle(scope_info, isolate));
461
    } else if (scope_info.scope_type() == CLASS_SCOPE) {
462
      outer_scope = zone->New<ClassScope>(isolate, zone, ast_value_factory,
463
                                          handle(scope_info, isolate));
464 465
    } else if (scope_info.scope_type() == BLOCK_SCOPE) {
      if (scope_info.is_declaration_scope()) {
466 467
        outer_scope = zone->New<DeclarationScope>(
            zone, BLOCK_SCOPE, ast_value_factory, handle(scope_info, isolate));
468
      } else {
469 470
        outer_scope = zone->New<Scope>(zone, BLOCK_SCOPE, ast_value_factory,
                                       handle(scope_info, isolate));
471
      }
472
    } else if (scope_info.scope_type() == MODULE_SCOPE) {
473
      outer_scope = zone->New<ModuleScope>(handle(scope_info, isolate),
474
                                           ast_value_factory);
475
    } else {
476 477 478 479
      DCHECK_EQ(scope_info.scope_type(), CATCH_SCOPE);
      DCHECK_EQ(scope_info.ContextLocalCount(), 1);
      DCHECK_EQ(scope_info.ContextLocalMode(0), VariableMode::kVar);
      DCHECK_EQ(scope_info.ContextLocalInitFlag(0), kCreatedInitialized);
480 481
      DCHECK(scope_info.HasInlinedLocalNames());
      String name = scope_info.ContextInlinedLocalName(0);
482
      MaybeAssignedFlag maybe_assigned =
483
          scope_info.ContextLocalMaybeAssignedFlag(0);
484 485 486 487 488
      outer_scope =
          zone->New<Scope>(zone,
                           ast_value_factory->GetString(
                               name, SharedStringAccessGuardIfNeeded(isolate)),
                           maybe_assigned, handle(scope_info, isolate));
489
    }
490 491 492
    if (deserialization_mode == DeserializationMode::kScopesOnly) {
      outer_scope->scope_info_ = Handle<ScopeInfo>::null();
    }
493 494 495 496 497 498 499 500 501

    if (cache_scope_found) {
      outer_scope->set_deserialized_scope_uses_external_cache();
    } else {
      DCHECK(!cache_scope_found);
      cache_scope_found =
          outer_scope->is_declaration_scope() && !outer_scope->is_eval_scope();
    }

502 503
    if (current_scope != nullptr) {
      outer_scope->AddInnerScope(current_scope);
504
    }
505
    current_scope = outer_scope;
506
    if (innermost_scope == nullptr) innermost_scope = current_scope;
507 508
    scope_info = scope_info.HasOuterScopeInfo() ? scope_info.OuterScopeInfo()
                                                : ScopeInfo();
509
  }
510

511 512
  if (deserialization_mode == DeserializationMode::kIncludingVariables) {
    SetScriptScopeInfo(isolate, script_scope);
513 514
  }

515
  if (innermost_scope == nullptr) return script_scope;
516
  script_scope->AddInnerScope(current_scope);
517
  return innermost_scope;
518 519
}

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
template <typename IsolateT>
void Scope::SetScriptScopeInfo(IsolateT* isolate,
                               DeclarationScope* script_scope) {
  if (script_scope->scope_info_.is_null()) {
    script_scope->SetScriptScopeInfo(
        ReadOnlyRoots(isolate).global_this_binding_scope_info_handle());
  }
}

template EXPORT_TEMPLATE_DEFINE(
    V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(Isolate* isolate,
                                                      DeclarationScope*
                                                          script_scope);
template EXPORT_TEMPLATE_DEFINE(
    V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(LocalIsolate* isolate,
                                                      DeclarationScope*
                                                          script_scope);

538 539 540 541 542 543 544 545 546 547 548
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
    Scope* Scope::DeserializeScopeChain(
        Isolate* isolate, Zone* zone, ScopeInfo scope_info,
        DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
        DeserializationMode deserialization_mode);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
    Scope* Scope::DeserializeScopeChain(
        LocalIsolate* isolate, Zone* zone, ScopeInfo scope_info,
        DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
        DeserializationMode deserialization_mode);

549 550 551 552 553 554 555 556 557
#ifdef DEBUG
bool Scope::IsReparsedMemberInitializerScope() const {
  return is_declaration_scope() &&
         IsClassMembersInitializerFunction(
             AsDeclarationScope()->function_kind()) &&
         outer_scope()->AsClassScope()->is_reparsed_class_scope();
}
#endif

558 559 560 561 562 563 564 565 566 567
DeclarationScope* Scope::AsDeclarationScope() {
  DCHECK(is_declaration_scope());
  return static_cast<DeclarationScope*>(this);
}

const DeclarationScope* Scope::AsDeclarationScope() const {
  DCHECK(is_declaration_scope());
  return static_cast<const DeclarationScope*>(this);
}

568 569 570 571 572 573 574 575 576 577
ModuleScope* Scope::AsModuleScope() {
  DCHECK(is_module_scope());
  return static_cast<ModuleScope*>(this);
}

const ModuleScope* Scope::AsModuleScope() const {
  DCHECK(is_module_scope());
  return static_cast<const ModuleScope*>(this);
}

578 579 580 581 582 583 584 585 586 587
ClassScope* Scope::AsClassScope() {
  DCHECK(is_class_scope());
  return static_cast<ClassScope*>(this);
}

const ClassScope* Scope::AsClassScope() const {
  DCHECK(is_class_scope());
  return static_cast<const ClassScope*>(this);
}

588
void DeclarationScope::DeclareSloppyBlockFunction(
589 590
    SloppyBlockFunctionStatement* sloppy_block_function) {
  sloppy_block_functions_.Add(sloppy_block_function);
591 592
}

593
void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
594 595 596
  DCHECK(is_sloppy(language_mode()));
  DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() ||
         (is_block_scope() && outer_scope()->is_function_scope()));
597 598 599
  DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
  DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);

600
  if (sloppy_block_functions_.is_empty()) return;
601

602 603 604 605 606
  // In case of complex parameters the current scope is the body scope and the
  // parameters are stored in the outer scope.
  Scope* parameter_scope = HasSimpleParameters() ? this : outer_scope_;
  DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||
         is_script_scope());
607

608
  DeclarationScope* decl_scope = GetNonEvalDeclarationScope();
609
  Scope* outer_scope = decl_scope->outer_scope();
610

611 612
  // For each variable which is used as a function declaration in a sloppy
  // block,
613 614 615
  for (SloppyBlockFunctionStatement* sloppy_block_function :
       sloppy_block_functions_) {
    const AstRawString* name = sloppy_block_function->name();
616 617 618 619 620

    // If the variable wouldn't conflict with a lexical declaration
    // or parameter,

    // Check if there's a conflict with a parameter.
621 622 623
    Variable* maybe_parameter = parameter_scope->LookupLocal(name);
    if (maybe_parameter != nullptr && maybe_parameter->is_parameter()) {
      continue;
624 625
    }

626 627 628
    // Check if there's a conflict with a lexical declaration
    Scope* query_scope = sloppy_block_function->scope()->outer_scope();
    bool should_hoist = true;
629

630 631 632
    // It is not sufficient to just do a Lookup on query_scope: for
    // example, that does not prevent hoisting of the function in
    // `{ let e; try {} catch (e) { function e(){} } }`
633 634 635
    //
    // Don't use a generic cache scope, as the cache scope would be the outer
    // scope and we terminate the iteration there anyway.
636
    do {
637
      Variable* var = query_scope->LookupInScopeOrScopeInfo(name, query_scope);
638 639
      if (var != nullptr && IsLexicalVariableMode(var->mode())) {
        should_hoist = false;
640
        break;
641
      }
642 643
      query_scope = query_scope->outer_scope();
    } while (query_scope != outer_scope);
644

645
    if (!should_hoist) continue;
646 647 648

    if (factory) {
      DCHECK(!is_being_lazily_parsed_);
649 650
      int pos = sloppy_block_function->position();
      bool ok = true;
651
      bool was_added;
652
      auto declaration = factory->NewVariableDeclaration(pos);
653 654
      // Based on the preceding checks, it doesn't matter what we pass as
      // sloppy_mode_block_scope_function_redefinition.
655 656 657 658
      Variable* var = DeclareVariable(
          declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE,
          Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
          nullptr, &ok);
659
      DCHECK(ok);
660 661 662 663 664 665 666 667
      VariableProxy* source =
          factory->NewVariableProxy(sloppy_block_function->var());
      VariableProxy* target = factory->NewVariableProxy(var);
      Assignment* assignment = factory->NewAssignment(
          sloppy_block_function->init(), target, source, pos);
      assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
      Statement* statement = factory->NewExpressionStatement(assignment, pos);
      sloppy_block_function->set_statement(statement);
668 669
    } else {
      DCHECK(is_being_lazily_parsed_);
670 671
      bool was_added;
      Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
672 673 674
      if (sloppy_block_function->init() == Token::ASSIGN) {
        var->SetMaybeAssigned();
      }
675 676 677 678
    }
  }
}

679
bool DeclarationScope::Analyze(ParseInfo* info) {
680 681 682
  RCS_SCOPE(info->runtime_call_stats(),
            RuntimeCallCounterId::kCompileScopeAnalysis,
            RuntimeCallStats::kThreadSpecific);
683
  DCHECK_NOT_NULL(info->literal());
684
  DeclarationScope* scope = info->literal()->scope();
685

686
  base::Optional<AllowHandleDereference> allow_deref;
687 688
#ifdef DEBUG
  if (scope->outer_scope() && !scope->outer_scope()->scope_info_.is_null()) {
689 690
    allow_deref.emplace();
  }
691
#endif
692

693
  if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) {
694
    AstNodeFactory factory(info->ast_value_factory(), info->zone());
695 696 697
    scope->HoistSloppyBlockFunctions(&factory);
  }

698
  // We are compiling one of four cases:
699 700
  // 1) top-level code,
  // 2) a function/eval/module on the top-level
701 702
  // 4) a class member initializer function scope
  // 3) 4 function/eval in a scope that was already resolved.
703
  DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
704
         scope->IsReparsedMemberInitializerScope() ||
705
         scope->outer_scope()->already_resolved_);
706

707
  // The outer scope is never lazy.
708
  scope->set_should_eager_compile();
709

710 711
  if (scope->must_use_preparsed_scope_data_) {
    DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE);
712
    allow_deref.emplace();
713
    info->consumed_preparse_data()->RestoreScopeAllocationData(
714
        scope, info->ast_value_factory(), info->zone());
715 716
  }

717
  if (!scope->AllocateVariables(info)) return false;
Simon Zünd's avatar
Simon Zünd committed
718
  scope->GetScriptScope()->RewriteReplGlobalVariables();
719

720
#ifdef DEBUG
721
  if (FLAG_print_scopes) {
722
    PrintF("Global scope:\n");
723
    scope->Print();
724
  }
725
  scope->CheckScopePositions();
726
  scope->CheckZones();
727
#endif
728 729

  return true;
730 731
}

732
void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) {
733 734
  DCHECK(has_this_declaration());

735
  bool derived_constructor = IsDerivedConstructor(function_kind_);
736

737 738 739 740 741 742
  receiver_ = zone()->New<Variable>(
      this, ast_value_factory->this_string(),
      derived_constructor ? VariableMode::kConst : VariableMode::kVar,
      THIS_VARIABLE,
      derived_constructor ? kNeedsInitialization : kCreatedInitialized,
      kNotAssigned);
743
  locals_.Add(receiver_);
744
}
745

746
void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) {
747 748
  DCHECK(is_function_scope());
  DCHECK(!is_arrow_scope());
749

750 751 752 753 754 755 756 757 758
  // Because when arguments_ is not nullptr, we already declared
  // "arguments exotic object" to add it into parameters before
  // impl()->InsertShadowingVarBindingInitializers, so here
  // only declare "arguments exotic object" when arguments_
  // is nullptr
  if (arguments_ != nullptr) {
    return;
  }

759 760 761
  // Declare 'arguments' variable which exists in all non arrow functions.  Note
  // that it might never be accessed, in which case it won't be allocated during
  // variable allocation.
762 763
  bool was_added = false;

764 765 766
  arguments_ =
      Declare(zone(), ast_value_factory->arguments_string(), VariableMode::kVar,
              NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
767 768 769 770 771
  // According to ES#sec-functiondeclarationinstantiation step 18
  // we should set argumentsObjectNeeded to false if has lexical
  // declared arguments only when hasParameterExpressions is false
  if (!was_added && IsLexicalVariableMode(arguments_->mode()) &&
      has_simple_parameters_) {
772 773 774
    // Check if there's lexically declared variable named arguments to avoid
    // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
    arguments_ = nullptr;
775 776 777 778 779 780 781
  }
}

void DeclarationScope::DeclareDefaultFunctionVariables(
    AstValueFactory* ast_value_factory) {
  DCHECK(is_function_scope());
  DCHECK(!is_arrow_scope());
782

783
  DeclareThis(ast_value_factory);
784
  bool was_added;
785
  new_target_ = Declare(zone(), ast_value_factory->new_target_string(),
786 787 788
                        VariableMode::kConst, NORMAL_VARIABLE,
                        kCreatedInitialized, kNotAssigned, &was_added);
  DCHECK(was_added);
789 790 791

  if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
      IsAccessorFunction(function_kind_)) {
792 793 794 795
    EnsureRareData()->this_function = Declare(
        zone(), ast_value_factory->this_function_string(), VariableMode::kConst,
        NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
    DCHECK(was_added);
796
  }
797 798
}

799 800
Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
                                               Scope* cache) {
801 802
  DCHECK(is_function_scope());
  DCHECK_NULL(function_);
803
  if (cache == nullptr) cache = this;
804
  DCHECK(this->IsOuterScopeOf(cache));
805
  DCHECK_NULL(cache->variables_.Lookup(name));
806 807
  VariableKind kind = is_sloppy(language_mode()) ? SLOPPY_FUNCTION_NAME_VARIABLE
                                                 : NORMAL_VARIABLE;
808 809
  function_ = zone()->New<Variable>(this, name, VariableMode::kConst, kind,
                                    kCreatedInitialized);
810
  if (sloppy_eval_can_extend_vars()) {
811
    cache->NonLocal(name, VariableMode::kDynamic);
812
  } else {
813
    cache->variables_.Add(function_);
814
  }
815 816
  return function_;
}
817

818 819
Variable* DeclarationScope::DeclareGeneratorObjectVar(
    const AstRawString* name) {
820
  DCHECK(is_function_scope() || is_module_scope() || is_repl_mode_scope());
821 822
  DCHECK_NULL(generator_object_var());

823 824
  Variable* result = EnsureRareData()->generator_object =
      NewTemporary(name, kNotAssigned);
825 826 827 828
  result->set_is_used();
  return result;
}

829
Scope* Scope::FinalizeBlockScope() {
830
  DCHECK(is_block_scope());
831 832 833
#ifdef DEBUG
  DCHECK_NE(sibling_, this);
#endif
834

835
  if (variables_.occupancy() > 0 ||
836 837
      (is_declaration_scope() &&
       AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
838 839
    return this;
  }
840

841 842
  DCHECK(!is_class_scope());

843
  // Remove this scope from outer scope.
844
  outer_scope()->RemoveInnerScope(this);
845 846

  // Reparent inner scopes.
847 848 849 850 851 852 853 854 855 856
  if (inner_scope_ != nullptr) {
    Scope* scope = inner_scope_;
    scope->outer_scope_ = outer_scope();
    while (scope->sibling_ != nullptr) {
      scope = scope->sibling_;
      scope->outer_scope_ = outer_scope();
    }
    scope->sibling_ = outer_scope()->inner_scope_;
    outer_scope()->inner_scope_ = inner_scope_;
    inner_scope_ = nullptr;
857 858 859
  }

  // Move unresolved variables
860 861 862
  if (!unresolved_list_.is_empty()) {
    outer_scope()->unresolved_list_.Prepend(std::move(unresolved_list_));
    unresolved_list_.Clear();
863 864
  }

865 866
  if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true;

867 868 869 870
  // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant
  // to this scope we would have had to bail out at the top.
  DCHECK(!is_declaration_scope() ||
         !AsDeclarationScope()->sloppy_eval_can_extend_vars());
871

872 873
  // This block does not need a context.
  num_heap_slots_ = 0;
874 875

  // Mark scope as removed by making it its own sibling.
876
#ifdef DEBUG
877
  sibling_ = this;
878
#endif
879 880

  return nullptr;
881 882
}

883 884 885 886 887 888 889
void DeclarationScope::AddLocal(Variable* var) {
  DCHECK(!already_resolved_);
  // Temporaries are only placed in ClosureScopes.
  DCHECK_EQ(GetClosureScope(), this);
  locals_.Add(var);
}

890
void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
891
  DCHECK(!IsCleared());
892 893
  DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_);
  DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer());
894
  DCHECK_EQ(new_parent, new_parent->GetClosureScope());
895
  DCHECK_NULL(new_parent->inner_scope_);
896
  DCHECK(new_parent->unresolved_list_.is_empty());
897 898 899 900 901
  Scope* inner_scope = new_parent->sibling_;
  if (inner_scope != top_inner_scope_) {
    for (; inner_scope->sibling() != top_inner_scope_;
         inner_scope = inner_scope->sibling()) {
      inner_scope->outer_scope_ = new_parent;
902 903 904
      if (inner_scope->inner_scope_calls_eval_) {
        new_parent->inner_scope_calls_eval_ = true;
      }
905 906 907
      DCHECK_NE(inner_scope, new_parent);
    }
    inner_scope->outer_scope_ = new_parent;
908 909 910
    if (inner_scope->inner_scope_calls_eval_) {
      new_parent->inner_scope_calls_eval_ = true;
    }
911 912 913 914 915 916 917
    new_parent->inner_scope_ = new_parent->sibling_;
    inner_scope->sibling_ = nullptr;
    // Reset the sibling rather than the inner_scope_ since we
    // want to keep new_parent there.
    new_parent->sibling_ = top_inner_scope_;
  }

918 919
  Scope* outer_scope = outer_scope_and_calls_eval_.GetPointer();
  new_parent->unresolved_list_.MoveTail(&outer_scope->unresolved_list_,
920
                                        top_unresolved_);
921

922
  // Move temporaries allocated for complex parameter initializers.
923
  DeclarationScope* outer_closure = outer_scope->GetClosureScope();
924 925
  for (auto it = top_local_; it != outer_closure->locals()->end(); ++it) {
    Variable* local = *it;
926 927 928 929 930
    DCHECK_EQ(VariableMode::kTemporary, local->mode());
    DCHECK_EQ(local->scope(), local->scope()->GetClosureScope());
    DCHECK_NE(local->scope(), new_parent);
    local->set_scope(new_parent);
  }
931
  new_parent->locals_.MoveTail(outer_closure->locals(), top_local_);
932 933
  outer_closure->locals_.Rewind(top_local_);

934
  // Move eval calls since Snapshot's creation into new_parent.
935 936
  if (outer_scope_and_calls_eval_->calls_eval_) {
    new_parent->RecordDeclarationScopeEvalCall();
937
    new_parent->inner_scope_calls_eval_ = true;
938
  }
939

940 941 942 943
  // We are in the arrow function case. The calls eval we may have recorded
  // is intended for the inner scope and we should simply restore the
  // original "calls eval" flag of the outer scope.
  RestoreEvalFlag();
944
  Clear();
945
}
946

947 948
void Scope::ReplaceOuterScope(Scope* outer) {
  DCHECK_NOT_NULL(outer);
949
  DCHECK_NOT_NULL(outer_scope_);
950
  DCHECK(!already_resolved_);
951
  outer_scope_->RemoveInnerScope(this);
952 953 954 955
  outer->AddInnerScope(this);
  outer_scope_ = outer;
}

956
Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
957
  DCHECK(!scope_info_.is_null());
958 959 960 961 962 963 964
  DCHECK(this->IsOuterScopeOf(cache));
  DCHECK(!cache->deserialized_scope_uses_external_cache());
  // The case where where the cache can be another scope is when the cache scope
  // is the last scope that doesn't use an external cache.
  DCHECK_IMPLIES(
      cache != this,
      cache->outer_scope()->deserialized_scope_uses_external_cache());
965
  DCHECK_NULL(cache->variables_.Lookup(name));
966
  DisallowGarbageCollection no_gc;
967

968 969
  String name_handle = *name->string();
  ScopeInfo scope_info = *scope_info_;
970 971 972
  // The Scope is backed up by ScopeInfo. This means it cannot operate in a
  // heap-independent mode, and all strings must be internalized immediately. So
  // it's ok to get the Handle<String> here.
973 974 975 976
  bool found = false;

  VariableLocation location;
  int index;
977
  VariableLookupResult lookup_result;
978

979 980
  {
    location = VariableLocation::CONTEXT;
981
    index = scope_info.ContextSlotIndex(name->string(), &lookup_result);
982 983 984
    found = index >= 0;
  }

985
  if (!found && is_module_scope()) {
986
    location = VariableLocation::MODULE;
987 988 989
    index = scope_info.ModuleIndex(name_handle, &lookup_result.mode,
                                   &lookup_result.init_flag,
                                   &lookup_result.maybe_assigned_flag);
990
    found = index != 0;
991
  }
992

993
  if (!found) {
994
    index = scope_info.FunctionContextSlotIndex(name_handle);
995
    if (index < 0) return nullptr;  // Nowhere found.
996
    Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache);
997
    DCHECK_EQ(VariableMode::kConst, var->mode());
998
    var->AllocateTo(VariableLocation::CONTEXT, index);
999
    return cache->variables_.Lookup(name);
1000
  }
1001

1002
  if (!is_module_scope()) {
1003
    DCHECK_NE(index, scope_info.ReceiverContextSlotIndex());
1004 1005
  }

1006
  bool was_added;
1007
  Variable* var = cache->variables_.Declare(
1008 1009
      zone(), this, name, lookup_result.mode, NORMAL_VARIABLE,
      lookup_result.init_flag, lookup_result.maybe_assigned_flag,
1010
      IsStaticFlag::kNotStatic, &was_added);
1011
  DCHECK(was_added);
1012 1013 1014 1015
  var->AllocateTo(location, index);
  return var;
}

1016 1017 1018 1019 1020
Variable* DeclarationScope::DeclareParameter(const AstRawString* name,
                                             VariableMode mode,
                                             bool is_optional, bool is_rest,
                                             AstValueFactory* ast_value_factory,
                                             int position) {
1021
  DCHECK(!already_resolved_);
1022
  DCHECK(is_function_scope() || is_module_scope());
1023
  DCHECK(!has_rest_);
1024
  DCHECK(!is_optional || !is_rest);
1025 1026
  DCHECK(!is_being_lazily_parsed_);
  DCHECK(!was_lazily_parsed_);
1027
  Variable* var;
1028
  if (mode == VariableMode::kTemporary) {
1029 1030
    var = NewTemporary(name);
  } else {
1031
    var = LookupLocal(name);
1032
    DCHECK_EQ(mode, VariableMode::kVar);
1033
    DCHECK(var->is_parameter());
1034
  }
1035
  has_rest_ = is_rest;
1036
  var->set_initializer_position(position);
1037
  params_.Add(var, zone());
1038
  if (!is_rest) ++num_parameters_;
1039 1040 1041
  if (name == ast_value_factory->arguments_string()) {
    has_arguments_parameter_ = true;
  }
1042 1043 1044 1045 1046
  // Params are automatically marked as used to make sure that the debugger and
  // function.arguments sees them.
  // TODO(verwaest): Reevaluate whether we always need to do this, since
  // strict-mode function.arguments does not make the arguments available.
  var->set_is_used();
1047
  return var;
1048 1049
}

1050
void DeclarationScope::RecordParameter(bool is_rest) {
1051 1052 1053
  DCHECK(!already_resolved_);
  DCHECK(is_function_scope() || is_module_scope());
  DCHECK(is_being_lazily_parsed_);
1054
  DCHECK(!has_rest_);
1055
  has_rest_ = is_rest;
1056 1057 1058
  if (!is_rest) ++num_parameters_;
}

1059
Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
1060 1061
                              VariableKind kind, bool* was_added,
                              InitializationFlag init_flag) {
1062
  DCHECK(!already_resolved_);
1063 1064
  // Private methods should be declared with ClassScope::DeclarePrivateName()
  DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
1065 1066 1067 1068
  // This function handles VariableMode::kVar, VariableMode::kLet, and
  // VariableMode::kConst modes.  VariableMode::kDynamic variables are
  // introduced during variable allocation, and VariableMode::kTemporary
  // variables are allocated via NewTemporary().
1069
  DCHECK(IsDeclaredVariableMode(mode));
1070
  DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
1071 1072
                 mode == VariableMode::kVar || mode == VariableMode::kLet ||
                     mode == VariableMode::kConst);
1073
  DCHECK(!GetDeclarationScope()->was_lazily_parsed());
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
  Variable* var =
      Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);

  // Pessimistically assume that top-level variables will be assigned and used.
  //
  // Top-level variables in a script can be accessed by other scripts or even
  // become global properties. While this does not apply to top-level variables
  // in a module (assuming they are not exported), we must still mark these as
  // assigned because they might be accessed by a lazily parsed top-level
  // function, which, for efficiency, we preparse without variable tracking.
  if (is_script_scope() || is_module_scope()) {
1085
    if (mode != VariableMode::kConst) var->SetMaybeAssigned();
1086 1087 1088 1089
    var->set_is_used();
  }

  return var;
1090 1091
}

1092
Variable* Scope::DeclareVariable(
1093 1094 1095 1096
    Declaration* declaration, const AstRawString* name, int pos,
    VariableMode mode, VariableKind kind, InitializationFlag init,
    bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
    bool* ok) {
1097 1098
  // Private methods should be declared with ClassScope::DeclarePrivateName()
  DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
1099
  DCHECK(IsDeclaredVariableMode(mode));
marja's avatar
marja committed
1100
  DCHECK(!already_resolved_);
1101 1102
  DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
  DCHECK(!GetDeclarationScope()->was_lazily_parsed());
marja's avatar
marja committed
1103

1104
  if (mode == VariableMode::kVar && !is_declaration_scope()) {
marja's avatar
marja committed
1105
    return GetDeclarationScope()->DeclareVariable(
1106
        declaration, name, pos, mode, kind, init, was_added,
1107
        sloppy_mode_block_scope_function_redefinition, ok);
marja's avatar
marja committed
1108 1109 1110 1111 1112 1113
  }
  DCHECK(!is_catch_scope());
  DCHECK(!is_with_scope());
  DCHECK(is_declaration_scope() ||
         (IsLexicalVariableMode(mode) && is_block_scope()));

1114
  DCHECK_NOT_NULL(name);
1115

1116 1117
  Variable* var = LookupLocal(name);
  // Declare the variable in the declaration scope.
1118 1119
  *was_added = var == nullptr;
  if (V8_LIKELY(*was_added)) {
1120 1121 1122 1123 1124 1125
    if (V8_UNLIKELY(is_eval_scope() && is_sloppy(language_mode()) &&
                    mode == VariableMode::kVar)) {
      // In a var binding in a sloppy direct eval, pollute the enclosing scope
      // with this new binding by doing the following:
      // The proxy is bound to a lookup variable to force a dynamic declaration
      // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
1126
      DCHECK_EQ(NORMAL_VARIABLE, kind);
1127 1128 1129
      var = NonLocal(name, VariableMode::kDynamic);
      // Mark the var as used in case anyone outside the eval wants to use it.
      var->set_is_used();
1130
    } else {
marja's avatar
marja committed
1131
      // Declare the name.
1132 1133
      var = DeclareLocal(name, mode, kind, was_added, init);
      DCHECK(*was_added);
1134 1135
    }
  } else {
1136
    var->SetMaybeAssigned();
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
    if (V8_UNLIKELY(IsLexicalVariableMode(mode) ||
                    IsLexicalVariableMode(var->mode()))) {
      // The name was declared in this scope before; check for conflicting
      // re-declarations. We have a conflict if either of the declarations is
      // not a var (in script scope, we also have to ignore legacy const for
      // compatibility). There is similar code in runtime.cc in the Declare
      // functions. The function CheckConflictingVarDeclarations checks for
      // var and let bindings from different scopes whereas this is a check
      // for conflicting declarations within the same scope. This check also
      // covers the special case
      //
      // function () { let x; { var x; } }
      //
      // because the var declaration is hoisted to the function scope where
      // 'x' is already bound.
      //
      // In harmony we treat re-declarations as early errors. See ES5 16 for a
      // definition of early errors.
      //
1156 1157 1158
      // Allow duplicate function decls for web compat, see bug 4693.
      *ok = var->is_sloppy_block_function() &&
            kind == SLOPPY_BLOCK_FUNCTION_VARIABLE;
1159
      *sloppy_mode_block_scope_function_redefinition = *ok;
marja's avatar
marja committed
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
    }
  }
  DCHECK_NOT_NULL(var);

  // We add a declaration node for every declaration. The compiler
  // will only generate code if necessary. In particular, declarations
  // for inner local variables that do not represent functions won't
  // result in any generated code.
  //
  // This will lead to multiple declaration nodes for the
  // same variable if it is declared several times. This is not a
  // semantic issue, but it may be a performance issue since it may
  // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
1173
  decls_.Add(declaration);
1174
  declaration->set_var(var);
1175
  return var;
marja's avatar
marja committed
1176 1177
}

1178
Variable* Scope::DeclareVariableName(const AstRawString* name,
1179 1180
                                     VariableMode mode, bool* was_added,
                                     VariableKind kind) {
1181 1182 1183
  DCHECK(IsDeclaredVariableMode(mode));
  DCHECK(!already_resolved_);
  DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
1184 1185
  // Private methods should be declared with ClassScope::DeclarePrivateName()
  DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
1186
  if (mode == VariableMode::kVar && !is_declaration_scope()) {
1187 1188
    return GetDeclarationScope()->DeclareVariableName(name, mode, was_added,
                                                      kind);
1189 1190 1191
  }
  DCHECK(!is_with_scope());
  DCHECK(!is_eval_scope());
1192
  DCHECK(is_declaration_scope() || IsLexicalVariableMode(mode));
1193
  DCHECK(scope_info_.is_null());
1194 1195

  // Declare the variable in the declaration scope.
1196 1197 1198
  Variable* var = DeclareLocal(name, mode, kind, was_added);
  if (!*was_added) {
    if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
1199 1200 1201 1202 1203 1204 1205 1206
      if (!var->is_sloppy_block_function() ||
          kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) {
        // Duplicate functions are allowed in the sloppy mode, but if this is
        // not a function declaration, it's an error. This is an error PreParser
        // hasn't previously detected.
        return nullptr;
      }
      // Sloppy block function redefinition.
1207
    }
1208
    var->SetMaybeAssigned();
1209 1210 1211
  }
  var->set_is_used();
  return var;
1212 1213
}

1214
Variable* Scope::DeclareCatchVariableName(const AstRawString* name) {
1215 1216 1217 1218
  DCHECK(!already_resolved_);
  DCHECK(is_catch_scope());
  DCHECK(scope_info_.is_null());

1219 1220 1221 1222 1223
  bool was_added;
  Variable* result = Declare(zone(), name, VariableMode::kVar, NORMAL_VARIABLE,
                             kCreatedInitialized, kNotAssigned, &was_added);
  DCHECK(was_added);
  return result;
1224 1225
}

1226 1227 1228
void Scope::AddUnresolved(VariableProxy* proxy) {
  DCHECK(!already_resolved_);
  DCHECK(!proxy->is_resolved());
1229
  unresolved_list_.Add(proxy);
1230 1231
}

1232
Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
1233 1234
                                                 VariableKind kind,
                                                 Scope* cache) {
1235
  DCHECK(is_script_scope());
1236 1237 1238
  bool was_added;
  return cache->variables_.Declare(
      zone(), this, name, VariableMode::kDynamicGlobal, kind,
1239
      kCreatedInitialized, kNotAssigned, IsStaticFlag::kNotStatic, &was_added);
1240
  // TODO(neis): Mark variable as maybe-assigned?
1241 1242
}

1243
bool Scope::RemoveUnresolved(VariableProxy* var) {
1244
  return unresolved_list_.Remove(var);
1245 1246
}

1247 1248 1249 1250 1251
void Scope::DeleteUnresolved(VariableProxy* var) {
  DCHECK(unresolved_list_.Contains(var));
  var->mark_removed_from_unresolved();
}

1252
Variable* Scope::NewTemporary(const AstRawString* name) {
1253 1254 1255 1256 1257
  return NewTemporary(name, kMaybeAssigned);
}

Variable* Scope::NewTemporary(const AstRawString* name,
                              MaybeAssignedFlag maybe_assigned) {
1258
  DeclarationScope* scope = GetClosureScope();
1259
  Variable* var = zone()->New<Variable>(scope, name, VariableMode::kTemporary,
1260
                                        NORMAL_VARIABLE, kCreatedInitialized);
1261
  scope->AddLocal(var);
1262
  if (maybe_assigned == kMaybeAssigned) var->SetMaybeAssigned();
1263
  return var;
1264 1265
}

1266 1267
Declaration* DeclarationScope::CheckConflictingVarDeclarations(
    bool* allowed_catch_binding_var_redeclaration) {
1268
  if (has_checked_syntax_) return nullptr;
1269
  for (Declaration* decl : decls_) {
1270 1271
    // Lexical vs lexical conflicts within the same scope have already been
    // captured in Parser::Declare. The only conflicts we still need to check
1272
    // are lexical vs nested var.
1273 1274
    if (decl->IsVariableDeclaration() &&
        decl->AsVariableDeclaration()->AsNested() != nullptr) {
1275 1276 1277 1278 1279 1280
      Scope* current = decl->AsVariableDeclaration()->AsNested()->scope();
      DCHECK(decl->var()->mode() == VariableMode::kVar ||
             decl->var()->mode() == VariableMode::kDynamic);
      // Iterate through all scopes until the declaration scope.
      do {
        // There is a conflict if there exists a non-VAR binding.
1281
        Variable* other_var = current->LookupLocal(decl->var()->raw_name());
1282
        if (current->is_catch_scope()) {
1283
          *allowed_catch_binding_var_redeclaration |= other_var != nullptr;
1284 1285 1286 1287 1288 1289 1290 1291 1292
          current = current->outer_scope();
          continue;
        }
        if (other_var != nullptr) {
          DCHECK(IsLexicalVariableMode(other_var->mode()));
          return decl;
        }
        current = current->outer_scope();
      } while (current != this);
1293
    }
1294 1295 1296 1297 1298 1299 1300 1301
  }

  if (V8_LIKELY(!is_eval_scope())) return nullptr;
  if (!is_sloppy(language_mode())) return nullptr;

  // Var declarations in sloppy eval are hoisted to the first non-eval
  // declaration scope. Check for conflicts between the eval scope that
  // declaration scope.
1302
  Scope* end = outer_scope()->GetNonEvalDeclarationScope()->outer_scope();
1303 1304 1305 1306

  for (Declaration* decl : decls_) {
    if (IsLexicalVariableMode(decl->var()->mode())) continue;
    Scope* current = outer_scope_;
1307
    // Iterate through all scopes until and including the declaration scope.
1308
    do {
1309 1310
      // There is a conflict if there exists a non-VAR binding up to the
      // declaration scope in which this sloppy-eval runs.
1311 1312 1313
      //
      // Use the current scope as the cache, since the general cache would be
      // the end scope.
1314
      Variable* other_var =
1315 1316 1317 1318 1319 1320
          current->LookupInScopeOrScopeInfo(decl->var()->raw_name(), current);
      if (other_var != nullptr && !current->is_catch_scope()) {
        // If this is a VAR, then we know that it doesn't conflict with
        // anything, so we can't conflict with anything either. The one
        // exception is the binding variable in catch scopes, which is handled
        // by the if above.
1321
        if (!IsLexicalVariableMode(other_var->mode())) break;
1322 1323 1324
        return decl;
      }
      current = current->outer_scope();
1325
    } while (current != end);
1326
  }
1327
  return nullptr;
1328 1329
}

1330 1331
const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope,
                                                  VariableMode mode_limit) {
1332 1333 1334 1335 1336
  const VariableMap& variables = scope->variables_;
  for (ZoneHashMap::Entry* p = variables.Start(); p != nullptr;
       p = variables.Next(p)) {
    const AstRawString* name = static_cast<const AstRawString*>(p->key);
    Variable* var = LookupLocal(name);
1337
    if (var != nullptr && var->mode() <= mode_limit) return name;
1338 1339 1340
  }
  return nullptr;
}
1341

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) {
  if (is_script_scope()) {
    DCHECK_NOT_NULL(receiver_);
    return;
  }
  DCHECK(has_this_declaration());
  DeclareThis(ast_value_factory);
  if (is_debug_evaluate_scope()) {
    receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
  } else {
    receiver_->AllocateTo(VariableLocation::CONTEXT,
1353
                          scope_info_->ReceiverContextSlotIndex());
1354 1355 1356
  }
}

1357
bool DeclarationScope::AllocateVariables(ParseInfo* info) {
1358
  // Module variables must be allocated before variable resolution
1359
  // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1360 1361
  if (is_module_scope()) AsModuleScope()->AllocateModuleVariables();

1362 1363 1364
  PrivateNameScopeIterator private_name_scope_iter(this);
  if (!private_name_scope_iter.Done() &&
      !private_name_scope_iter.GetScope()->ResolvePrivateNames(info)) {
1365 1366 1367 1368
    DCHECK(info->pending_error_handler()->has_pending_error());
    return false;
  }

1369
  if (!ResolveVariablesRecursively(info->scope())) {
1370 1371 1372
    DCHECK(info->pending_error_handler()->has_pending_error());
    return false;
  }
1373

1374
  // Don't allocate variables of preparsed scopes.
1375
  if (!was_lazily_parsed()) AllocateVariablesRecursively();
1376 1377

  return true;
1378 1379
}

1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
bool Scope::HasThisReference() const {
  if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
    return true;
  }

  for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
    if (!scope->is_declaration_scope() ||
        !scope->AsDeclarationScope()->has_this_declaration()) {
      if (scope->HasThisReference()) return true;
    }
  }

  return false;
}

1395 1396 1397 1398 1399 1400 1401 1402 1403
bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
    const Scope* outer) const {
  // If none of the outer scopes need to decide whether to context allocate
  // specific variables, we can preparse inner functions without unresolved
  // variables. Otherwise we need to find unresolved variables to force context
  // allocation of the matching declarations. We can stop at the outer scope for
  // the parse, since context allocation of those variables is already
  // guaranteed to be correct.
  for (const Scope* s = this; s != outer; s = s->outer_scope_) {
1404 1405 1406 1407
    // Eval forces context allocation on all outer scopes, so we don't need to
    // look at those scopes. Sloppy eval makes top-level non-lexical variables
    // dynamic, whereas strict-mode requires context allocation.
    if (s->is_eval_scope()) return is_sloppy(s->language_mode());
1408 1409 1410 1411
    // Catch scopes force context allocation of all variables.
    if (s->is_catch_scope()) continue;
    // With scopes do not introduce variables that need allocation.
    if (s->is_with_scope()) continue;
1412 1413
    DCHECK(s->is_module_scope() || s->is_block_scope() ||
           s->is_function_scope());
1414
    return false;
1415
  }
1416
  return true;
1417 1418
}

1419
bool DeclarationScope::AllowsLazyCompilation() const {
1420 1421 1422 1423
  // Functions which force eager compilation and class member initializer
  // functions are not lazily compilable.
  return !force_eager_compilation_ &&
         !IsClassMembersInitializerFunction(function_kind());
1424
}
1425

1426
int Scope::ContextChainLength(Scope* scope) const {
1427
  int n = 0;
1428
  for (const Scope* s = this; s != scope; s = s->outer_scope_) {
1429
    DCHECK_NOT_NULL(s);  // scope must be in the scope chain
1430
    if (s->NeedsContext()) n++;
1431 1432 1433 1434
  }
  return n;
}

1435 1436 1437 1438 1439 1440 1441
int Scope::ContextChainLengthUntilOutermostSloppyEval() const {
  int result = 0;
  int length = 0;

  for (const Scope* s = this; s != nullptr; s = s->outer_scope()) {
    if (!s->NeedsContext()) continue;
    length++;
1442
    if (s->is_declaration_scope() &&
1443
        s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1444 1445
      result = length;
    }
1446 1447 1448 1449
  }

  return result;
}
1450

1451
DeclarationScope* Scope::GetDeclarationScope() {
1452
  Scope* scope = this;
1453
  while (!scope->is_declaration_scope()) {
1454 1455
    scope = scope->outer_scope();
  }
1456
  return scope->AsDeclarationScope();
1457 1458
}

1459 1460 1461 1462 1463 1464 1465 1466
DeclarationScope* Scope::GetNonEvalDeclarationScope() {
  Scope* scope = this;
  while (!scope->is_declaration_scope() || scope->is_eval_scope()) {
    scope = scope->outer_scope();
  }
  return scope->AsDeclarationScope();
}

1467 1468 1469 1470 1471 1472 1473 1474
const DeclarationScope* Scope::GetClosureScope() const {
  const Scope* scope = this;
  while (!scope->is_declaration_scope() || scope->is_block_scope()) {
    scope = scope->outer_scope();
  }
  return scope->AsDeclarationScope();
}

1475
DeclarationScope* Scope::GetClosureScope() {
1476 1477 1478 1479
  Scope* scope = this;
  while (!scope->is_declaration_scope() || scope->is_block_scope()) {
    scope = scope->outer_scope();
  }
1480
  return scope->AsDeclarationScope();
1481 1482
}

1483 1484
bool Scope::NeedsScopeInfo() const {
  DCHECK(!already_resolved_);
1485
  DCHECK(GetClosureScope()->ShouldEagerCompile());
1486
  // The debugger expects all functions to have scope infos.
1487
  // TODO(yangguo): Remove this requirement.
1488 1489 1490 1491
  if (is_function_scope()) return true;
  return NeedsContext();
}

1492 1493 1494 1495
bool Scope::ShouldBanArguments() {
  return GetReceiverScope()->should_ban_arguments();
}

1496
DeclarationScope* Scope::GetReceiverScope() {
1497
  Scope* scope = this;
1498 1499 1500
  while (!scope->is_declaration_scope() ||
         (!scope->is_script_scope() &&
          !scope->AsDeclarationScope()->has_this_declaration())) {
1501 1502
    scope = scope->outer_scope();
  }
1503
  return scope->AsDeclarationScope();
1504 1505
}

1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
DeclarationScope* Scope::GetConstructorScope() {
  Scope* scope = this;
  while (scope != nullptr && !scope->IsConstructorScope()) {
    scope = scope->outer_scope();
  }
  if (scope == nullptr) {
    return nullptr;
  }
  DCHECK(scope->IsConstructorScope());
  return scope->AsDeclarationScope();
}

1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
Scope* Scope::GetHomeObjectScope() {
  Scope* scope = this;
  while (scope != nullptr && !scope->is_home_object_scope()) {
    if (scope->is_function_scope()) {
      FunctionKind function_kind = scope->AsDeclarationScope()->function_kind();
      // "super" in arrow functions binds outside the arrow function. But if we
      // find a function which doesn't bind "super" (is not a method etc.) and
      // not an arrow function, we know "super" here doesn't bind anywhere and
      // we can return nullptr.
      if (!IsArrowFunction(function_kind) && !BindsSuper(function_kind)) {
        return nullptr;
      }
    }
    if (scope->private_name_lookup_skips_outer_class()) {
      DCHECK(scope->outer_scope()->is_class_scope());
      scope = scope->outer_scope()->outer_scope();
    } else {
      scope = scope->outer_scope();
    }
  }
  return scope;
}

Simon Zünd's avatar
Simon Zünd committed
1541 1542 1543 1544 1545 1546 1547 1548
DeclarationScope* Scope::GetScriptScope() {
  Scope* scope = this;
  while (!scope->is_script_scope()) {
    scope = scope->outer_scope();
  }
  return scope->AsDeclarationScope();
}

1549 1550 1551 1552 1553 1554 1555 1556
Scope* Scope::GetOuterScopeWithContext() {
  Scope* scope = outer_scope_;
  while (scope && !scope->NeedsContext()) {
    scope = scope->outer_scope();
  }
  return scope;
}

1557 1558 1559 1560 1561
namespace {
bool WasLazilyParsed(Scope* scope) {
  return scope->is_declaration_scope() &&
         scope->AsDeclarationScope()->was_lazily_parsed();
}
1562

1563 1564
}  // namespace

1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
template <typename FunctionType>
void Scope::ForEach(FunctionType callback) {
  Scope* scope = this;
  while (true) {
    Iteration iteration = callback(scope);
    // Try to descend into inner scopes first.
    if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) {
      scope = scope->inner_scope_;
    } else {
      // Find the next outer scope with a sibling.
      while (scope->sibling_ == nullptr) {
        if (scope == this) return;
        scope = scope->outer_scope_;
      }
      if (scope == this) return;
      scope = scope->sibling_;
    }
  }
}

1585 1586 1587 1588 1589
bool Scope::IsConstructorScope() const {
  return is_declaration_scope() &&
         IsClassConstructor(AsDeclarationScope()->function_kind());
}

1590 1591 1592 1593 1594 1595 1596 1597 1598
bool Scope::IsOuterScopeOf(Scope* other) const {
  Scope* scope = other;
  while (scope) {
    if (scope == this) return true;
    scope = scope->outer_scope();
  }
  return false;
}

1599
void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
1600 1601
                             Isolate* isolate, Handle<StringSet>* non_locals) {
  this->ForEach([max_outer_scope, isolate, non_locals](Scope* scope) {
1602 1603 1604 1605
    // Module variables must be allocated before variable resolution
    // to ensure that UpdateNeedsHoleCheck() can detect import variables.
    if (scope->is_module_scope()) {
      scope->AsModuleScope()->AllocateModuleVariables();
1606 1607
    }

1608 1609 1610 1611
    // Lazy parsed declaration scopes are already partially analyzed. If there
    // are unresolved references remaining, they just need to be resolved in
    // outer scopes.
    Scope* lookup = WasLazilyParsed(scope) ? scope->outer_scope() : scope;
1612

1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
    for (VariableProxy* proxy : scope->unresolved_list_) {
      DCHECK(!proxy->is_resolved());
      Variable* var =
          Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope());
      if (var == nullptr) {
        *non_locals = StringSet::Add(isolate, *non_locals, proxy->name());
      } else {
        // In this case we need to leave scopes in a way that they can be
        // allocated. If we resolved variables from lazy parsed scopes, we need
        // to context allocate the var.
1623
        scope->ResolveTo(proxy, var);
1624 1625 1626 1627 1628 1629 1630 1631 1632
        if (!var->is_dynamic() && lookup != scope)
          var->ForceContextAllocation();
      }
    }

    // Clear unresolved_list_ as it's in an inconsistent state.
    scope->unresolved_list_.Clear();
    return Iteration::kDescend;
  });
1633 1634
}

1635 1636
void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
                             AstNodeFactory* ast_node_factory,
1637 1638 1639 1640
                             UnresolvedList* new_unresolved_list,
                             bool maybe_in_arrowhead) {
  this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list,
                 maybe_in_arrowhead](Scope* scope) {
1641 1642 1643 1644 1645
    DCHECK_IMPLIES(scope->is_declaration_scope(),
                   !scope->AsDeclarationScope()->was_lazily_parsed());

    for (VariableProxy* proxy = scope->unresolved_list_.first();
         proxy != nullptr; proxy = proxy->next_unresolved()) {
1646
      if (proxy->is_removed_from_unresolved()) continue;
1647 1648 1649 1650 1651 1652 1653
      DCHECK(!proxy->is_resolved());
      Variable* var =
          Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope());
      if (var == nullptr) {
        // Don't copy unresolved references to the script scope, unless it's a
        // reference to a private name or method. In that case keep it so we
        // can fail later.
1654 1655
        if (!max_outer_scope->outer_scope()->is_script_scope() ||
            maybe_in_arrowhead) {
1656 1657 1658 1659 1660
          VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
          new_unresolved_list->Add(copy);
        }
      } else {
        var->set_is_used();
1661
        if (proxy->is_assigned()) var->SetMaybeAssigned();
1662 1663 1664
      }
    }

1665 1666 1667 1668
    // Clear unresolved_list_ as it's in an inconsistent state.
    scope->unresolved_list_.Clear();
    return Iteration::kDescend;
  });
1669 1670
}

verwaest's avatar
verwaest committed
1671
Handle<StringSet> DeclarationScope::CollectNonLocals(
1672 1673
    Isolate* isolate, Handle<StringSet> non_locals) {
  Scope::CollectNonLocals(this, isolate, &non_locals);
1674
  return non_locals;
1675 1676
}

1677 1678 1679 1680
void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
                                            bool aborted) {
  DCHECK(is_function_scope());

1681
  // Reset all non-trivial members.
1682
  params_.DropAndClear();
1683
  decls_.Clear();
1684
  locals_.Clear();
1685
  inner_scope_ = nullptr;
1686
  unresolved_list_.Clear();
1687
  sloppy_block_functions_.Clear();
1688
  rare_data_ = nullptr;
1689
  has_rest_ = false;
1690
  function_ = nullptr;
1691

1692
  DCHECK_NE(zone(), ast_value_factory->single_parse_zone());
1693 1694 1695 1696 1697
  // Make sure this scope and zone aren't used for allocation anymore.
  {
    // Get the zone, while variables_ is still valid
    Zone* zone = this->zone();
    variables_.Invalidate();
1698
    zone->Reset();
1699
  }
1700

1701 1702
  if (aborted) {
    // Prepare scope for use in the outer zone.
1703
    variables_ = VariableMap(ast_value_factory->single_parse_zone());
1704
    if (!IsArrowFunction(function_kind_)) {
1705
      has_simple_parameters_ = true;
1706 1707
      DeclareDefaultFunctionVariables(ast_value_factory);
    }
1708
  }
1709 1710 1711

#ifdef DEBUG
  needs_migration_ = false;
1712
  is_being_lazily_parsed_ = false;
1713 1714
#endif

1715
  was_lazily_parsed_ = !aborted;
1716 1717
}

1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
bool Scope::IsSkippableFunctionScope() {
  // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
  // those Scopes which have their own PreparseDataBuilder object. This
  // logic ensures that the scope allocation data is consistent with the
  // skippable function data (both agree on where the lazy function boundaries
  // are).
  if (!is_function_scope()) return false;
  DeclarationScope* declaration_scope = AsDeclarationScope();
  return !declaration_scope->is_arrow_scope() &&
         declaration_scope->preparse_data_builder() != nullptr;
}

1730
void Scope::SavePreparseData(Parser* parser) {
1731 1732 1733 1734 1735 1736
  this->ForEach([parser](Scope* scope) {
    if (scope->IsSkippableFunctionScope()) {
      scope->AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
    }
    return Iteration::kDescend;
  });
1737 1738
}

1739
void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) {
1740
  if (preparse_data_builder_ == nullptr) return;
1741
  preparse_data_builder_->SaveScopeAllocationData(this, parser);
1742 1743
}

1744
void DeclarationScope::AnalyzePartially(Parser* parser,
1745 1746
                                        AstNodeFactory* ast_node_factory,
                                        bool maybe_in_arrowhead) {
1747
  DCHECK(!force_eager_compilation_);
1748
  UnresolvedList new_unresolved_list;
1749
  if (!IsArrowFunction(function_kind_) &&
1750
      (!outer_scope_->is_script_scope() || maybe_in_arrowhead ||
1751
       (preparse_data_builder_ != nullptr &&
1752
        preparse_data_builder_->HasInnerFunctions()))) {
1753 1754 1755
    // Try to resolve unresolved variables for this Scope and migrate those
    // which cannot be resolved inside. It doesn't make sense to try to resolve
    // them in the outer Scopes here, because they are incomplete.
1756 1757
    Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list,
                            maybe_in_arrowhead);
1758

1759 1760 1761 1762 1763
    // Migrate function_ to the right Zone.
    if (function_ != nullptr) {
      function_ = ast_node_factory->CopyVariable(function_);
    }

1764
    SavePreparseData(parser);
verwaest's avatar
verwaest committed
1765
  }
1766

1767 1768 1769 1770 1771 1772
#ifdef DEBUG
  if (FLAG_print_scopes) {
    PrintF("Inner function scope:\n");
    Print();
  }
#endif
1773

1774
  ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
1775

1776
  unresolved_list_ = std::move(new_unresolved_list);
1777
}
1778

Simon Zünd's avatar
Simon Zünd committed
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789
void DeclarationScope::RewriteReplGlobalVariables() {
  DCHECK(is_script_scope());
  if (!is_repl_mode_scope()) return;

  for (VariableMap::Entry* p = variables_.Start(); p != nullptr;
       p = variables_.Next(p)) {
    Variable* var = reinterpret_cast<Variable*>(p->value);
    var->RewriteLocationForRepl();
  }
}

1790
#ifdef DEBUG
adamk's avatar
adamk committed
1791 1792 1793 1794
namespace {

const char* Header(ScopeType scope_type, FunctionKind function_kind,
                   bool is_declaration_scope) {
1795
  switch (scope_type) {
1796
    case EVAL_SCOPE: return "eval";
1797
    case FUNCTION_SCOPE:
1798 1799 1800 1801
      if (IsGeneratorFunction(function_kind)) return "function*";
      if (IsAsyncFunction(function_kind)) return "async function";
      if (IsArrowFunction(function_kind)) return "arrow";
      return "function";
1802
    case MODULE_SCOPE: return "module";
1803
    case SCRIPT_SCOPE: return "global";
1804
    case CATCH_SCOPE: return "catch";
1805
    case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
1806 1807
    case CLASS_SCOPE:
      return "class";
1808
    case WITH_SCOPE: return "with";
1809 1810 1811 1812
  }
  UNREACHABLE();
}

adamk's avatar
adamk committed
1813
void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); }
1814

adamk's avatar
adamk committed
1815
void PrintName(const AstRawString* name) {
1816
  PrintF("%.*s", name->length(), name->raw_data());
1817 1818
}

adamk's avatar
adamk committed
1819
void PrintLocation(Variable* var) {
1820
  switch (var->location()) {
1821
    case VariableLocation::UNALLOCATED:
1822
      break;
1823
    case VariableLocation::PARAMETER:
1824 1825
      PrintF("parameter[%d]", var->index());
      break;
1826
    case VariableLocation::LOCAL:
1827 1828
      PrintF("local[%d]", var->index());
      break;
1829
    case VariableLocation::CONTEXT:
1830 1831
      PrintF("context[%d]", var->index());
      break;
1832
    case VariableLocation::LOOKUP:
1833 1834
      PrintF("lookup");
      break;
1835 1836 1837
    case VariableLocation::MODULE:
      PrintF("module");
      break;
Simon Zünd's avatar
Simon Zünd committed
1838 1839 1840
    case VariableLocation::REPL_GLOBAL:
      PrintF("repl global[%d]", var->index());
      break;
1841 1842 1843
  }
}

adamk's avatar
adamk committed
1844 1845 1846 1847 1848 1849 1850
void PrintVar(int indent, Variable* var) {
  Indent(indent, VariableMode2String(var->mode()));
  PrintF(" ");
  if (var->raw_name()->IsEmpty())
    PrintF(".%p", reinterpret_cast<void*>(var));
  else
    PrintName(var->raw_name());
1851
  PrintF(";  // (%p) ", reinterpret_cast<void*>(var));
adamk's avatar
adamk committed
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
  PrintLocation(var);
  bool comma = !var->IsUnallocated();
  if (var->has_forced_context_allocation()) {
    if (comma) PrintF(", ");
    PrintF("forced context allocation");
    comma = true;
  }
  if (var->maybe_assigned() == kNotAssigned) {
    if (comma) PrintF(", ");
    PrintF("never assigned");
1862 1863 1864 1865 1866 1867
    comma = true;
  }
  if (var->initialization_flag() == kNeedsInitialization &&
      !var->binding_needs_init()) {
    if (comma) PrintF(", ");
    PrintF("hole initialization elided");
1868
  }
adamk's avatar
adamk committed
1869
  PrintF("\n");
1870 1871
}

adamk's avatar
adamk committed
1872 1873 1874
void PrintMap(int indent, const char* label, VariableMap* map, bool locals,
              Variable* function_var) {
  bool printed_label = false;
1875
  for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
1876
    Variable* var = reinterpret_cast<Variable*>(p->value);
adamk's avatar
adamk committed
1877
    if (var == function_var) continue;
1878
    bool local = !IsDynamicVariableMode(var->mode());
adamk's avatar
adamk committed
1879 1880 1881 1882 1883
    if ((locals ? local : !local) &&
        (var->is_used() || !var->IsUnallocated())) {
      if (!printed_label) {
        Indent(indent, label);
        printed_label = true;
1884
      }
adamk's avatar
adamk committed
1885
      PrintVar(indent, var);
1886
    }
1887 1888 1889
  }
}

adamk's avatar
adamk committed
1890 1891
}  // anonymous namespace

1892 1893 1894 1895 1896
void DeclarationScope::PrintParameters() {
  PrintF(" (");
  for (int i = 0; i < params_.length(); i++) {
    if (i > 0) PrintF(", ");
    const AstRawString* name = params_[i]->raw_name();
1897
    if (name->IsEmpty()) {
1898
      PrintF(".%p", reinterpret_cast<void*>(params_[i]));
1899
    } else {
1900
      PrintName(name);
1901
    }
1902 1903 1904
  }
  PrintF(")");
}
1905

1906 1907 1908 1909 1910
void Scope::Print(int n) {
  int n0 = (n > 0 ? n : 0);
  int n1 = n0 + 2;  // indentation

  // Print header.
1911 1912
  FunctionKind function_kind = is_function_scope()
                                   ? AsDeclarationScope()->function_kind()
1913
                                   : FunctionKind::kNormalFunction;
1914
  Indent(n0, Header(scope_type_, function_kind, is_declaration_scope()));
1915
  if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
1916 1917 1918 1919 1920
    PrintF(" ");
    PrintName(scope_name_);
  }

  // Print parameters, if any.
1921
  Variable* function = nullptr;
1922
  if (is_function_scope()) {
1923
    AsDeclarationScope()->PrintParameters();
1924
    function = AsDeclarationScope()->function_var();
1925 1926
  }

1927 1928
  PrintF(" { // (%p) (%d, %d)\n", reinterpret_cast<void*>(this),
         start_position(), end_position());
1929 1930 1931
  if (is_hidden()) {
    Indent(n1, "// is hidden\n");
  }
1932 1933

  // Function name, if any (named function literals, only).
1934
  if (function != nullptr) {
1935
    Indent(n1, "// (local) function name: ");
1936
    PrintName(function->raw_name());
1937 1938 1939 1940
    PrintF("\n");
  }

  // Scope info.
1941
  if (is_strict(language_mode())) {
1942
    Indent(n1, "// strict mode scope\n");
1943
  }
1944
#if V8_ENABLE_WEBASSEMBLY
1945
  if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
1946
#endif  // V8_ENABLE_WEBASSEMBLY
1947 1948
  if (is_declaration_scope() &&
      AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1949 1950
    Indent(n1, "// scope calls sloppy 'eval'\n");
  }
1951 1952 1953
  if (private_name_lookup_skips_outer_class()) {
    Indent(n1, "// scope skips outer class for #-names\n");
  }
1954
  if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
1955 1956
  if (is_declaration_scope()) {
    DeclarationScope* scope = AsDeclarationScope();
1957
    if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n");
1958
    if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n");
1959 1960 1961
    if (scope->needs_private_name_context_chain_recalc()) {
      Indent(n1, "// needs #-name context chain recalc\n");
    }
1962 1963
    Indent(n1, "// ");
    PrintF("%s\n", FunctionKind2String(scope->function_kind()));
1964 1965 1966
    if (scope->class_scope_has_private_brand()) {
      Indent(n1, "// class scope has private brand\n");
    }
1967
  }
1968 1969 1970 1971 1972 1973
  if (num_stack_slots_ > 0) {
    Indent(n1, "// ");
    PrintF("%d stack slots\n", num_stack_slots_);
  }
  if (num_heap_slots_ > 0) {
    Indent(n1, "// ");
1974
    PrintF("%d heap slots\n", num_heap_slots_);
1975
  }
1976 1977

  // Print locals.
1978
  if (function != nullptr) {
1979
    Indent(n1, "// function var:\n");
1980
    PrintVar(n1, function);
1981 1982
  }

1983 1984 1985 1986
  // Print temporaries.
  {
    bool printed_header = false;
    for (Variable* local : locals_) {
1987
      if (local->mode() != VariableMode::kTemporary) continue;
1988 1989 1990 1991 1992 1993 1994 1995
      if (!printed_header) {
        printed_header = true;
        Indent(n1, "// temporary vars:\n");
      }
      PrintVar(n1, local);
    }
  }

1996 1997 1998 1999
  if (variables_.occupancy() > 0) {
    PrintMap(n1, "// local vars:\n", &variables_, true, function);
    PrintMap(n1, "// dynamic vars:\n", &variables_, false, function);
  }
2000

2001 2002
  if (is_class_scope()) {
    ClassScope* class_scope = AsClassScope();
2003
    if (class_scope->GetRareData() != nullptr) {
2004
      PrintMap(n1, "// private name vars:\n",
2005
               &(class_scope->GetRareData()->private_name_map), true, function);
2006 2007 2008 2009 2010
      Variable* brand = class_scope->brand();
      if (brand != nullptr) {
        Indent(n1, "// brand var:\n");
        PrintVar(n1, brand);
      }
2011
    }
2012 2013 2014 2015 2016 2017 2018 2019 2020
    if (class_scope->class_variable() != nullptr) {
      Indent(n1, "// class var");
      PrintF("%s%s:\n",
             class_scope->class_variable()->is_used() ? ", used" : ", unused",
             class_scope->should_save_class_variable_index()
                 ? ", index saved"
                 : ", index not saved");
      PrintVar(n1, class_scope->class_variable());
    }
2021 2022
  }

2023 2024
  // Print inner scopes (disable by providing negative n).
  if (n >= 0) {
2025 2026
    for (Scope* scope = inner_scope_; scope != nullptr;
         scope = scope->sibling_) {
2027
      PrintF("\n");
2028
      scope->Print(n1);
2029 2030 2031 2032 2033
    }
  }

  Indent(n0, "}\n");
}
2034 2035

void Scope::CheckScopePositions() {
2036 2037 2038 2039 2040 2041 2042 2043
  this->ForEach([](Scope* scope) {
    // Visible leaf scopes must have real positions.
    if (!scope->is_hidden() && scope->inner_scope_ == nullptr) {
      DCHECK_NE(kNoSourcePosition, scope->start_position());
      DCHECK_NE(kNoSourcePosition, scope->end_position());
    }
    return Iteration::kDescend;
  });
2044
}
2045 2046

void Scope::CheckZones() {
2047
  DCHECK(!needs_migration_);
2048
  this->ForEach([](Scope* scope) {
2049
    if (WasLazilyParsed(scope)) {
2050 2051
      DCHECK_NULL(scope->zone());
      DCHECK_NULL(scope->inner_scope_);
2052
      return Iteration::kContinue;
2053
    }
2054 2055
    return Iteration::kDescend;
  });
2056
}
2057 2058
#endif  // DEBUG

2059
Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
2060 2061
  // Declare a new non-local.
  DCHECK(IsDynamicVariableMode(mode));
2062
  bool was_added;
2063 2064 2065
  Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
                                     kCreatedInitialized, kNotAssigned,
                                     IsStaticFlag::kNotStatic, &was_added);
2066 2067
  // Allocate it by giving it a dynamic lookup.
  var->AllocateTo(VariableLocation::LOOKUP, -1);
2068 2069 2070
  return var;
}

2071
// static
2072
template <Scope::ScopeLookupMode mode>
2073
Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
2074
                        Scope* outer_scope_end, Scope* cache_scope,
2075
                        bool force_context_allocation) {
2076 2077 2078
  // If we have already passed the cache scope in earlier recursions, we should
  // first quickly check if the current scope uses the cache scope before
  // continuing.
2079 2080 2081
  if (mode == kDeserializedScope &&
      scope->deserialized_scope_uses_external_cache()) {
    Variable* var = cache_scope->variables_.Lookup(proxy->raw_name());
2082 2083 2084
    if (var != nullptr) return var;
  }

2085
  while (true) {
2086
    DCHECK_IMPLIES(mode == kParsedScope, !scope->is_debug_evaluate_scope_);
2087 2088 2089 2090 2091 2092 2093
    // Short-cut: whenever we find a debug-evaluate scope, just look everything
    // up dynamically. Debug-evaluate doesn't properly create scope info for the
    // lookups it does. It may not have a valid 'this' declaration, and anything
    // accessed through debug-evaluate might invalidly resolve to
    // stack-allocated variables.
    // TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for
    // the scopes in which it's evaluating.
2094 2095
    if (mode == kDeserializedScope &&
        V8_UNLIKELY(scope->is_debug_evaluate_scope_)) {
2096 2097
      DCHECK(scope->deserialized_scope_uses_external_cache() ||
             scope == cache_scope);
2098
      return cache_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2099 2100
    }

2101
    // Try to find the variable in this scope.
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112
    Variable* var;
    if (mode == kParsedScope) {
      var = scope->LookupLocal(proxy->raw_name());
    } else {
      DCHECK_EQ(mode, kDeserializedScope);
      bool external_cache = scope->deserialized_scope_uses_external_cache();
      if (!external_cache) {
        // Check the cache on each deserialized scope, up to the main cache
        // scope when we get to it (we may still have deserialized scopes
        // in-between the initial and cache scopes so we can't just check the
        // cache before the loop).
2113
        var = scope->variables_.Lookup(proxy->raw_name());
2114 2115
        if (var != nullptr) return var;
      }
2116 2117
      var = scope->LookupInScopeInfo(proxy->raw_name(),
                                     external_cache ? cache_scope : scope);
2118
    }
2119

2120 2121 2122
    // We found a variable and we are done. (Even if there is an 'eval' in this
    // scope which introduces the same variable again, the resulting variable
    // remains the same.)
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
    //
    // For sloppy eval though, we skip dynamic variable to avoid resolving to a
    // variable when the variable and proxy are in the same eval execution. The
    // variable is not available on subsequent lazy executions of functions in
    // the eval, so this avoids inner functions from looking up different
    // variables during eager and lazy compilation.
    //
    // TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy
    // living in a different scope to the current one, or some other
    // optimisation.
    if (var != nullptr &&
        !(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) {
2135 2136
      if (mode == kParsedScope && force_context_allocation &&
          !var->is_dynamic()) {
2137 2138 2139 2140
        var->ForceContextAllocation();
      }
      return var;
    }
2141

2142
    if (scope->outer_scope_ == outer_scope_end) break;
2143

2144 2145
    DCHECK(!scope->is_script_scope());
    if (V8_UNLIKELY(scope->is_with_scope())) {
2146
      return LookupWith(proxy, scope, outer_scope_end, cache_scope,
2147 2148
                        force_context_allocation);
    }
2149 2150 2151
    if (V8_UNLIKELY(
            scope->is_declaration_scope() &&
            scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
2152 2153
      return LookupSloppyEval(proxy, scope, outer_scope_end, cache_scope,
                              force_context_allocation);
2154
    }
2155

2156 2157
    force_context_allocation |= scope->is_function_scope();
    scope = scope->outer_scope_;
2158

2159 2160
    // TODO(verwaest): Separate through AnalyzePartially.
    if (mode == kParsedScope && !scope->scope_info_.is_null()) {
2161
      DCHECK_NULL(cache_scope);
2162
      cache_scope = scope->GetNonEvalDeclarationScope();
2163 2164
      return Lookup<kDeserializedScope>(proxy, scope, outer_scope_end,
                                        cache_scope);
2165
    }
2166
  }
2167

2168 2169 2170
  // We may just be trying to find all free variables. In that case, don't
  // declare them in the outer scope.
  // TODO(marja): Separate Lookup for preparsed scopes better.
2171 2172 2173
  if (mode == kParsedScope && !scope->is_script_scope()) {
    return nullptr;
  }
2174 2175

  // No binding has been found. Declare a variable on the global object.
2176 2177
  return scope->AsDeclarationScope()->DeclareDynamicGlobal(
      proxy->raw_name(), NORMAL_VARIABLE,
2178
      mode == kDeserializedScope ? cache_scope : scope);
2179 2180
}

2181 2182
template Variable* Scope::Lookup<Scope::kParsedScope>(
    VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2183
    Scope* cache_scope, bool force_context_allocation);
2184 2185
template Variable* Scope::Lookup<Scope::kDeserializedScope>(
    VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2186
    Scope* cache_scope, bool force_context_allocation);
2187

2188
Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
2189
                            Scope* outer_scope_end, Scope* cache_scope,
2190 2191 2192
                            bool force_context_allocation) {
  DCHECK(scope->is_with_scope());

2193 2194 2195
  Variable* var =
      scope->outer_scope_->scope_info_.is_null()
          ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2196
                                 nullptr, force_context_allocation)
2197
          : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
2198
                                       outer_scope_end, cache_scope);
2199

2200
  if (var == nullptr) return var;
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211

  // The current scope is a with scope, so the variable binding can not be
  // statically resolved. However, note that it was necessary to do a lookup
  // in the outer scope anyway, because if a binding exists in an outer
  // scope, the associated variable has to be marked as potentially being
  // accessed from inside of an inner with scope (the property may not be in
  // the 'with' object).
  if (!var->is_dynamic() && var->IsUnallocated()) {
    DCHECK(!scope->already_resolved_);
    var->set_is_used();
    var->ForceContextAllocation();
2212
    if (proxy->is_assigned()) var->SetMaybeAssigned();
verwaest's avatar
verwaest committed
2213
  }
2214 2215 2216 2217 2218 2219 2220 2221
  Scope* target_scope;
  if (scope->deserialized_scope_uses_external_cache()) {
    DCHECK_NOT_NULL(cache_scope);
    cache_scope->variables_.Remove(var);
    target_scope = cache_scope;
  } else {
    target_scope = scope;
  }
2222
  Variable* dynamic =
2223
      target_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2224 2225
  dynamic->set_local_if_not_shadowed(var);
  return dynamic;
2226
}
verwaest's avatar
verwaest committed
2227

2228
Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
2229
                                  Scope* outer_scope_end, Scope* cache_scope,
2230 2231
                                  bool force_context_allocation) {
  DCHECK(scope->is_declaration_scope() &&
2232
         scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
2233

2234
  // If we're compiling eval, it's possible that the outer scope is the first
2235 2236 2237 2238 2239 2240
  // ScopeInfo-backed scope. We use the next declaration scope as the cache for
  // this case, to avoid complexity around sloppy block function hoisting and
  // conflict detection through catch scopes in the eval.
  Scope* entry_cache = cache_scope == nullptr
                           ? scope->outer_scope()->GetNonEvalDeclarationScope()
                           : cache_scope;
2241 2242 2243
  Variable* var =
      scope->outer_scope_->scope_info_.is_null()
          ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2244
                                 nullptr, force_context_allocation)
2245
          : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
2246
                                       outer_scope_end, entry_cache);
2247
  if (var == nullptr) return var;
2248

2249 2250 2251 2252 2253 2254 2255 2256
  // We may not want to use the cache scope, change it back to the given scope
  // if necessary.
  if (!scope->deserialized_scope_uses_external_cache()) {
    // For a deserialized scope, we'll be replacing the cache_scope.
    DCHECK_IMPLIES(!scope->scope_info_.is_null(), cache_scope != nullptr);
    cache_scope = scope;
  }

2257 2258 2259 2260 2261 2262 2263 2264
  // A variable binding may have been found in an outer scope, but the current
  // scope makes a sloppy 'eval' call, so the found variable may not be the
  // correct one (the 'eval' may introduce a binding with the same name). In
  // that case, change the lookup result to reflect this situation. Only
  // scopes that can host var bindings (declaration scopes) need be considered
  // here (this excludes block and catch scopes), and variable lookups at
  // script scope are always dynamic.
  if (var->IsGlobalObjectProperty()) {
2265
    Scope* target = cache_scope == nullptr ? scope : cache_scope;
2266
    var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicGlobal);
2267
  }
verwaest's avatar
verwaest committed
2268

2269 2270 2271
  if (var->is_dynamic()) return var;

  Variable* invalidated = var;
2272
  if (cache_scope != nullptr) cache_scope->variables_.Remove(invalidated);
2273

2274
  Scope* target = cache_scope == nullptr ? scope : cache_scope;
2275
  var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicLocal);
2276 2277
  var->set_local_if_not_shadowed(invalidated);

2278 2279 2280
  return var;
}

2281
void Scope::ResolveVariable(VariableProxy* proxy) {
2282
  DCHECK(!proxy->is_resolved());
2283
  Variable* var = Lookup<kParsedScope>(proxy, this, nullptr);
2284
  DCHECK_NOT_NULL(var);
2285
  ResolveTo(proxy, var);
verwaest's avatar
verwaest committed
2286 2287
}

2288 2289
namespace {

2290 2291 2292 2293 2294 2295
void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy) {
  proxy->set_needs_hole_check();
  var->ForceHoleInitialization();
}

void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
2296
  if (var->mode() == VariableMode::kDynamicLocal) {
2297
    // Dynamically introduced variables never need a hole check (since they're
2298 2299 2300
    // VariableMode::kVar bindings, either from var or function declarations),
    // but the variable they shadow might need a hole check, which we want to do
    // if we decide that no shadowing variable was dynamically introoduced.
2301 2302
    DCHECK_EQ(kCreatedInitialized, var->initialization_flag());
    return UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope);
2303 2304
  }

2305
  if (var->initialization_flag() == kCreatedInitialized) return;
2306 2307 2308 2309 2310

  // It's impossible to eliminate module import hole checks here, because it's
  // unknown at compilation time whether the binding referred to in the
  // exporting module itself requires hole checks.
  if (var->location() == VariableLocation::MODULE && !var->IsExport()) {
2311
    return SetNeedsHoleCheck(var, proxy);
2312 2313 2314
  }

  // Check if the binding really needs an initialization check. The check
2315 2316 2317 2318 2319 2320
  // can be skipped in the following situation: we have a VariableMode::kLet or
  // VariableMode::kConst binding, both the Variable and the VariableProxy have
  // the same declaration scope (i.e. they are both in global code, in the same
  // function or in the same eval code), the VariableProxy is in the source
  // physically located after the initializer of the variable, and that the
  // initializer cannot be skipped due to a nonlinear scope.
2321
  //
2322
  // The condition on the closure scopes is a conservative check for
2323 2324 2325 2326 2327 2328 2329 2330 2331
  // nested functions that access a binding and are called before the
  // binding is initialized:
  //   function() { f(); let x = 1; function f() { x = 2; } }
  //
  // The check cannot be skipped on non-linear scopes, namely switch
  // scopes, to ensure tests are done in cases like the following:
  //   switch (1) { case 0: let x = 2; case 1: f(x); }
  // The scope of the variable needs to be checked, in case the use is
  // in a sub-block which may be linear.
2332 2333
  if (var->scope()->GetClosureScope() != scope->GetClosureScope()) {
    return SetNeedsHoleCheck(var, proxy);
2334 2335 2336
  }

  // We should always have valid source positions.
2337 2338
  DCHECK_NE(var->initializer_position(), kNoSourcePosition);
  DCHECK_NE(proxy->position(), kNoSourcePosition);
2339

2340 2341 2342 2343
  if (var->scope()->is_nonlinear() ||
      var->initializer_position() >= proxy->position()) {
    return SetNeedsHoleCheck(var, proxy);
  }
2344 2345 2346 2347
}

}  // anonymous namespace

2348
void Scope::ResolveTo(VariableProxy* proxy, Variable* var) {
2349
  DCHECK_NOT_NULL(var);
2350
  UpdateNeedsHoleCheck(var, proxy, this);
2351
  proxy->BindTo(var);
2352 2353
}

2354
void Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
2355 2356 2357 2358 2359 2360 2361 2362
                                     Scope* end) {
  // Resolve the variable in all parsed scopes to force context allocation.
  for (; scope != end; scope = scope->outer_scope_) {
    Variable* var = scope->LookupLocal(proxy->raw_name());
    if (var != nullptr) {
      var->set_is_used();
      if (!var->is_dynamic()) {
        var->ForceContextAllocation();
2363
        if (proxy->is_assigned()) var->SetMaybeAssigned();
2364
        return;
2365 2366 2367 2368 2369
      }
    }
  }
}

2370
bool Scope::ResolveVariablesRecursively(Scope* end) {
2371 2372 2373
  // Lazy parsed declaration scopes are already partially analyzed. If there are
  // unresolved references remaining, they just need to be resolved in outer
  // scopes.
2374
  if (WasLazilyParsed(this)) {
2375
    DCHECK_EQ(variables_.occupancy(), 0);
2376 2377 2378
    // Resolve in all parsed scopes except for the script scope.
    if (!end->is_script_scope()) end = end->outer_scope();

2379
    for (VariableProxy* proxy : unresolved_list_) {
2380
      ResolvePreparsedVariable(proxy, outer_scope(), end);
2381 2382 2383
    }
  } else {
    // Resolve unresolved variables for this scope.
2384
    for (VariableProxy* proxy : unresolved_list_) {
2385
      ResolveVariable(proxy);
2386
    }
2387

2388 2389 2390
    // Resolve unresolved variables for inner scopes.
    for (Scope* scope = inner_scope_; scope != nullptr;
         scope = scope->sibling_) {
2391
      if (!scope->ResolveVariablesRecursively(end)) return false;
2392
    }
2393
  }
2394
  return true;
2395 2396 2397
}

bool Scope::MustAllocate(Variable* var) {
2398
  DCHECK(var->location() != VariableLocation::MODULE);
2399 2400 2401
  // Give var a read/write use if there is a chance it might be accessed
  // via an eval() call.  This is only possible if the variable has a
  // visible name.
2402
  if (!var->raw_name()->IsEmpty() &&
2403
      (inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
2404
    var->set_is_used();
2405
    if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
2406
  }
2407
  DCHECK(!var->has_forced_context_allocation() || var->is_used());
2408
  // Global variables do not need to be allocated.
2409
  return !var->IsGlobalObjectProperty() && var->is_used();
2410 2411 2412 2413
}


bool Scope::MustAllocateInContext(Variable* var) {
2414 2415 2416
  // If var is accessed from an inner scope, or if there is a possibility
  // that it might be accessed from the current or an inner scope (through
  // an eval() call or a runtime with lookup), it must be allocated in the
2417
  // context.
2418
  //
2419
  // Temporary variables are always stack-allocated.  Catch-bound variables are
2420
  // always context-allocated.
2421 2422
  VariableMode mode = var->mode();
  if (mode == VariableMode::kTemporary) return false;
2423
  if (is_catch_scope()) return true;
2424
  if (is_script_scope() || is_eval_scope()) {
2425
    if (IsLexicalVariableMode(mode)) {
2426 2427
      return true;
    }
2428
  }
2429
  return var->has_forced_context_allocation() || inner_scope_calls_eval_;
2430 2431 2432
}

void Scope::AllocateStackSlot(Variable* var) {
2433
  if (is_block_scope()) {
2434
    outer_scope()->GetDeclarationScope()->AllocateStackSlot(var);
2435
  } else {
2436
    var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
2437
  }
2438 2439 2440 2441
}


void Scope::AllocateHeapSlot(Variable* var) {
2442
  var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
2443 2444
}

2445
void DeclarationScope::AllocateParameterLocals() {
2446
  DCHECK(is_function_scope());
2447

2448
  bool has_mapped_arguments = false;
2449
  if (arguments_ != nullptr) {
2450
    DCHECK(!is_arrow_scope());
2451
    if (MustAllocate(arguments_) && !has_arguments_parameter_) {
2452 2453 2454 2455 2456 2457
      // 'arguments' is used and does not refer to a function
      // parameter of the same name. If the arguments object
      // aliases formal parameters, we conservatively allocate
      // them specially in the loop below.
      has_mapped_arguments =
          GetArgumentsType() == CreateArgumentsType::kMappedArguments;
2458 2459 2460 2461 2462
    } else {
      // 'arguments' is unused. Tell the code generator that it does not need to
      // allocate the arguments object by nulling out arguments_.
      arguments_ = nullptr;
    }
2463 2464 2465 2466 2467 2468
  }

  // The same parameter may occur multiple times in the parameters_ list.
  // If it does, and if it is not copied into the context object, it must
  // receive the highest parameter index for that parameter; thus iteration
  // order is relevant!
2469
  for (int i = num_parameters() - 1; i >= 0; --i) {
2470
    Variable* var = params_[i];
2471
    DCHECK_NOT_NULL(var);
2472
    DCHECK(!has_rest_ || var != rest_parameter());
2473
    DCHECK_EQ(this, var->scope());
2474
    if (has_mapped_arguments) {
2475
      var->set_is_used();
2476
      var->SetMaybeAssigned();
2477
      var->ForceContextAllocation();
2478
    }
2479
    AllocateParameter(var, i);
2480 2481
  }
}
2482

2483
void DeclarationScope::AllocateParameter(Variable* var, int index) {
2484 2485 2486 2487 2488 2489 2490 2491 2492
  if (!MustAllocate(var)) return;
  if (has_forced_context_allocation_for_parameters() ||
      MustAllocateInContext(var)) {
    DCHECK(var->IsUnallocated() || var->IsContextSlot());
    if (var->IsUnallocated()) AllocateHeapSlot(var);
  } else {
    DCHECK(var->IsUnallocated() || var->IsParameter());
    if (var->IsUnallocated()) {
      var->AllocateTo(VariableLocation::PARAMETER, index);
2493 2494 2495 2496
    }
  }
}

2497 2498
void DeclarationScope::AllocateReceiver() {
  if (!has_this_declaration()) return;
2499 2500 2501 2502 2503
  DCHECK_NOT_NULL(receiver());
  DCHECK_EQ(receiver()->scope(), this);
  AllocateParameter(receiver(), -1);
}

2504
void Scope::AllocateNonParameterLocal(Variable* var) {
2505
  DCHECK_EQ(var->scope(), this);
2506
  if (var->IsUnallocated() && MustAllocate(var)) {
2507 2508
    if (MustAllocateInContext(var)) {
      AllocateHeapSlot(var);
2509 2510
      DCHECK_IMPLIES(is_catch_scope(),
                     var->index() == Context::THROWN_OBJECT_INDEX);
2511 2512 2513 2514 2515 2516
    } else {
      AllocateStackSlot(var);
    }
  }
}

2517
void Scope::AllocateNonParameterLocalsAndDeclaredGlobals() {
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534
  if (is_declaration_scope() && AsDeclarationScope()->is_arrow_scope()) {
    // In arrow functions, allocate non-temporaries first and then all the
    // temporaries to make the local variable ordering stable when reparsing to
    // collect source positions.
    for (Variable* local : locals_) {
      if (local->mode() != VariableMode::kTemporary)
        AllocateNonParameterLocal(local);
    }

    for (Variable* local : locals_) {
      if (local->mode() == VariableMode::kTemporary)
        AllocateNonParameterLocal(local);
    }
  } else {
    for (Variable* local : locals_) {
      AllocateNonParameterLocal(local);
    }
2535 2536
  }

2537
  if (is_declaration_scope()) {
2538
    AsDeclarationScope()->AllocateLocals();
2539 2540 2541
  }
}

2542
void DeclarationScope::AllocateLocals() {
2543 2544 2545
  // For now, function_ must be allocated at the very end.  If it gets
  // allocated in the context, it must be the last slot in the context,
  // because of the current ScopeInfo implementation (see
2546
  // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
2547
  if (function_ != nullptr && MustAllocate(function_)) {
2548
    AllocateNonParameterLocal(function_);
2549 2550
  } else {
    function_ = nullptr;
2551
  }
2552

2553
  DCHECK(!has_rest_ || !MustAllocate(rest_parameter()) ||
2554
         !rest_parameter()->IsUnallocated());
2555

2556 2557
  if (new_target_ != nullptr && !MustAllocate(new_target_)) {
    new_target_ = nullptr;
2558 2559
  }

2560 2561
  NullifyRareVariableIf(RareVariable::kThisFunction,
                        [=](Variable* var) { return !MustAllocate(var); });
2562 2563
}

2564 2565 2566
void ModuleScope::AllocateModuleVariables() {
  for (const auto& it : module()->regular_imports()) {
    Variable* var = LookupLocal(it.first);
2567 2568
    var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
    DCHECK(!var->IsExport());
2569 2570
  }

2571 2572
  for (const auto& it : module()->regular_exports()) {
    Variable* var = LookupLocal(it.first);
2573 2574
    var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
    DCHECK(var->IsExport());
2575 2576 2577
  }
}

2578
void Scope::AllocateVariablesRecursively() {
2579 2580 2581
  this->ForEach([](Scope* scope) -> Iteration {
    DCHECK(!scope->already_resolved_);
    if (WasLazilyParsed(scope)) return Iteration::kContinue;
2582
    DCHECK_EQ(scope->ContextHeaderLength(), scope->num_heap_slots_);
2583 2584 2585 2586

    // Allocate variables for this scope.
    // Parameters must be allocated first, if any.
    if (scope->is_declaration_scope()) {
2587
      scope->AsDeclarationScope()->AllocateReceiver();
2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601
      if (scope->is_function_scope()) {
        scope->AsDeclarationScope()->AllocateParameterLocals();
      }
    }
    scope->AllocateNonParameterLocalsAndDeclaredGlobals();

    // Force allocation of a context for this scope if necessary. For a 'with'
    // scope and for a function scope that makes an 'eval' call we need a
    // context, even if no local variables were statically allocated in the
    // scope. Likewise for modules and function scopes representing asm.js
    // modules. Also force a context, if the scope is stricter than the outer
    // scope.
    bool must_have_context =
        scope->is_with_scope() || scope->is_module_scope() ||
2602 2603 2604 2605
#if V8_ENABLE_WEBASSEMBLY
        scope->IsAsmModule() ||
#endif  // V8_ENABLE_WEBASSEMBLY
        scope->ForceContextForLanguageMode() ||
2606
        (scope->is_function_scope() &&
2607
         scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) ||
2608
        (scope->is_block_scope() && scope->is_declaration_scope() &&
2609
         scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
2610

2611 2612
    // If we didn't allocate any locals in the local context, then we only
    // need the minimal number of slots if we must have a context.
2613
    if (scope->num_heap_slots_ == scope->ContextHeaderLength() &&
2614 2615 2616
        !must_have_context) {
      scope->num_heap_slots_ = 0;
    }
2617

2618 2619
    // Allocation done.
    DCHECK(scope->num_heap_slots_ == 0 ||
2620
           scope->num_heap_slots_ >= scope->ContextHeaderLength());
2621 2622
    return Iteration::kDescend;
  });
2623 2624
}

2625 2626
template <typename IsolateT>
void Scope::AllocateScopeInfosRecursively(IsolateT* isolate,
2627
                                          MaybeHandle<ScopeInfo> outer_scope) {
2628
  DCHECK(scope_info_.is_null());
2629
  MaybeHandle<ScopeInfo> next_outer_scope = outer_scope;
2630 2631

  if (NeedsScopeInfo()) {
jochen's avatar
jochen committed
2632
    scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
2633 2634 2635
    // The ScopeInfo chain should mirror the context chain, so we only link to
    // the next outer scope that needs a context.
    if (NeedsContext()) next_outer_scope = scope_info_;
2636 2637 2638 2639
  }

  // Allocate ScopeInfos for inner scopes.
  for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
2640 2641 2642 2643 2644 2645 2646
    if (!scope->is_function_scope() ||
        scope->AsDeclarationScope()->ShouldEagerCompile()) {
      scope->AllocateScopeInfosRecursively(isolate, next_outer_scope);
    }
  }
}

2647 2648 2649 2650
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope::
    AllocateScopeInfosRecursively<Isolate>(Isolate* isolate,
                                           MaybeHandle<ScopeInfo> outer_scope);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope::
2651 2652
    AllocateScopeInfosRecursively<LocalIsolate>(
        LocalIsolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
2653

2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694
void DeclarationScope::RecalcPrivateNameContextChain() {
  // The outermost scope in a class heritage expression is marked to skip the
  // class scope during private name resolution. It is possible, however, that
  // either the class scope won't require a Context and ScopeInfo, or the
  // outermost scope in the heritage position won't. Simply copying the bit from
  // full parse into the ScopeInfo will break lazy compilation. In the former
  // case the scope that is marked to skip its outer scope will incorrectly skip
  // a different class scope than the one we intended to skip. In the latter
  // case variables resolved through an inner scope will incorrectly check the
  // class scope since we lost the skip bit from the outermost heritage scope.
  //
  // This method fixes both cases by, in outermost to innermost order, copying
  // the value of the skip bit from outer scopes that don't require a Context.
  DCHECK(needs_private_name_context_chain_recalc_);
  this->ForEach([](Scope* scope) {
    Scope* outer = scope->outer_scope();
    if (!outer) return Iteration::kDescend;
    if (!outer->NeedsContext()) {
      scope->private_name_lookup_skips_outer_class_ =
          outer->private_name_lookup_skips_outer_class();
    }
    if (!scope->is_function_scope() ||
        scope->AsDeclarationScope()->ShouldEagerCompile()) {
      return Iteration::kDescend;
    }
    return Iteration::kContinue;
  });
}

void DeclarationScope::RecordNeedsPrivateNameContextChainRecalc() {
  DCHECK_EQ(GetClosureScope(), this);
  DeclarationScope* scope;
  for (scope = this; scope != nullptr;
       scope = scope->outer_scope() != nullptr
                   ? scope->outer_scope()->GetClosureScope()
                   : nullptr) {
    if (scope->needs_private_name_context_chain_recalc_) return;
    scope->needs_private_name_context_chain_recalc_ = true;
  }
}

2695
// static
2696 2697
template <typename IsolateT>
void DeclarationScope::AllocateScopeInfos(ParseInfo* info, IsolateT* isolate) {
2698
  DeclarationScope* scope = info->literal()->scope();
2699 2700 2701

  // No one else should have allocated a scope info for this scope yet.
  DCHECK(scope->scope_info_.is_null());
2702

2703
  MaybeHandle<ScopeInfo> outer_scope;
2704
  if (scope->outer_scope_ != nullptr) {
2705
    DCHECK((std::is_same<Isolate, v8::internal::Isolate>::value));
2706 2707 2708
    outer_scope = scope->outer_scope_->scope_info_;
  }

2709 2710 2711
  if (scope->needs_private_name_context_chain_recalc()) {
    scope->RecalcPrivateNameContextChain();
  }
2712 2713 2714 2715 2716
  scope->AllocateScopeInfosRecursively(isolate, outer_scope);

  // The debugger expects all shared function infos to contain a scope info.
  // Since the top-most scope will end up in a shared function info, make sure
  // it has one, even if it doesn't need a scope info.
2717
  // TODO(yangguo): Remove this requirement.
2718 2719 2720 2721 2722 2723 2724 2725
  if (scope->scope_info_.is_null()) {
    scope->scope_info_ =
        ScopeInfo::Create(isolate, scope->zone(), scope, outer_scope);
  }

  // Ensuring that the outer script scope has a scope info avoids having
  // special case for native contexts vs other contexts.
  if (info->script_scope() && info->script_scope()->scope_info_.is_null()) {
2726
    info->script_scope()->scope_info_ = isolate->factory()->empty_scope_info();
2727 2728 2729
  }
}

2730
template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos(
2731
    ParseInfo* info, Isolate* isolate);
2732 2733
template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos(
    ParseInfo* info, LocalIsolate* isolate);
2734

2735 2736
int Scope::ContextLocalCount() const {
  if (num_heap_slots() == 0) return 0;
2737 2738
  Variable* function =
      is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
2739
  bool is_function_var_in_context =
2740
      function != nullptr && function->IsContextSlot();
2741
  return num_heap_slots() - ContextHeaderLength() -
2742
         (is_function_var_in_context ? 1 : 0);
2743
}
2744

2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765
VariableProxy* Scope::NewHomeObjectVariableProxy(AstNodeFactory* factory,
                                                 const AstRawString* name,
                                                 int start_pos) {
  // VariableProxies of the home object cannot be resolved like a normal
  // variable. Consider the case of a super.property usage in heritage position:
  //
  //   class C extends super.foo { m() { super.bar(); } }
  //
  // The super.foo property access is logically nested under C's class scope,
  // which also has a home object due to its own method m's usage of
  // super.bar(). However, super.foo must resolve super in C's outer scope.
  //
  // Because of the above, home object VariableProxies are always made directly
  // on the Scope that needs the home object instead of the innermost scope.
  DCHECK(needs_home_object());
  if (!scope_info_.is_null()) {
    // This is a lazy compile, so the home object's context slot is already
    // known.
    Variable* home_object = variables_.Lookup(name);
    if (home_object == nullptr) {
      VariableLookupResult lookup_result;
2766
      int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786
      DCHECK_GE(index, 0);
      bool was_added;
      home_object = variables_.Declare(zone(), this, name, lookup_result.mode,
                                       NORMAL_VARIABLE, lookup_result.init_flag,
                                       lookup_result.maybe_assigned_flag,
                                       IsStaticFlag::kNotStatic, &was_added);
      DCHECK(was_added);
      home_object->AllocateTo(VariableLocation::CONTEXT, index);
    }
    return factory->NewVariableProxy(home_object, start_pos);
  }
  // This is not a lazy compile. Add the unresolved home object VariableProxy to
  // the unresolved list of the home object scope, which is not necessarily the
  // innermost scope.
  VariableProxy* proxy =
      factory->NewVariableProxy(name, NORMAL_VARIABLE, start_pos);
  AddUnresolved(proxy);
  return proxy;
}

2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797
bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
  switch (a) {
    case VariableMode::kPrivateGetterOnly:
      return b == VariableMode::kPrivateSetterOnly;
    case VariableMode::kPrivateSetterOnly:
      return b == VariableMode::kPrivateGetterOnly;
    default:
      return false;
  }
}

2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821
void ClassScope::FinalizeReparsedClassScope(
    Isolate* isolate, MaybeHandle<ScopeInfo> maybe_scope_info,
    AstValueFactory* ast_value_factory, bool needs_allocation_fixup) {
  // Set this bit so that DelcarationScope::Analyze recognizes
  // the reparsed instance member initializer scope.
#ifdef DEBUG
  is_reparsed_class_scope_ = true;
#endif

  if (!needs_allocation_fixup) {
    return;
  }

  // Restore variable allocation results for context-allocated variables in
  // the class scope from ScopeInfo, so that we don't need to run
  // resolution and allocation on these variables again when generating
  // code for the initializer function.
  DCHECK(!maybe_scope_info.is_null());
  Handle<ScopeInfo> scope_info = maybe_scope_info.ToHandleChecked();
  DCHECK_EQ(scope_info->scope_type(), CLASS_SCOPE);
  DCHECK_EQ(scope_info->StartPosition(), start_position_);

  int context_header_length = scope_info->ContextHeaderLength();
  DisallowGarbageCollection no_gc;
2822 2823
  for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
    int slot_index = context_header_length + it->index();
2824 2825 2826
    DCHECK_LT(slot_index, scope_info->ContextLength());

    const AstRawString* string = ast_value_factory->GetString(
2827
        it->name(), SharedStringAccessGuardIfNeeded(isolate));
2828 2829 2830 2831 2832 2833 2834 2835
    Variable* var = string->IsPrivateName() ? LookupLocalPrivateName(string)
                                            : LookupLocal(string);
    DCHECK_NOT_NULL(var);
    var->AllocateTo(VariableLocation::CONTEXT, slot_index);
  }
  scope_info_ = scope_info;
}

2836
Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
2837 2838 2839
                                         VariableMode mode,
                                         IsStaticFlag is_static_flag,
                                         bool* was_added) {
2840
  Variable* result = EnsureRareData()->private_name_map.Declare(
2841
      zone(), this, name, mode, NORMAL_VARIABLE,
2842 2843
      InitializationFlag::kNeedsInitialization, MaybeAssignedFlag::kNotAssigned,
      is_static_flag, was_added);
2844 2845
  if (*was_added) {
    locals_.Add(result);
2846 2847 2848
    has_static_private_methods_ |=
        (result->is_static() &&
         IsPrivateMethodOrAccessorVariableMode(result->mode()));
2849 2850
  } else if (IsComplementaryAccessorPair(result->mode(), mode) &&
             result->is_static_flag() == is_static_flag) {
2851 2852
    *was_added = true;
    result->set_mode(VariableMode::kPrivateGetterAndSetter);
2853 2854 2855 2856 2857 2858
  }
  result->ForceContextAllocation();
  return result;
}

Variable* ClassScope::LookupLocalPrivateName(const AstRawString* name) {
2859 2860
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr) {
2861 2862
    return nullptr;
  }
2863
  return rare_data->private_name_map.Lookup(name);
2864 2865 2866
}

UnresolvedList::Iterator ClassScope::GetUnresolvedPrivateNameTail() {
2867 2868
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr) {
2869 2870
    return UnresolvedList::Iterator();
  }
2871
  return rare_data->unresolved_private_names.end();
2872 2873 2874
}

void ClassScope::ResetUnresolvedPrivateNameTail(UnresolvedList::Iterator tail) {
2875 2876 2877
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr ||
      rare_data->unresolved_private_names.end() == tail) {
2878 2879 2880 2881 2882 2883
    return;
  }

  bool tail_is_empty = tail == UnresolvedList::Iterator();
  if (tail_is_empty) {
    // If the saved tail is empty, the list used to be empty, so clear it.
2884
    rare_data->unresolved_private_names.Clear();
2885
  } else {
2886
    rare_data->unresolved_private_names.Rewind(tail);
2887 2888 2889 2890 2891
  }
}

void ClassScope::MigrateUnresolvedPrivateNameTail(
    AstNodeFactory* ast_node_factory, UnresolvedList::Iterator tail) {
2892 2893 2894
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr ||
      rare_data->unresolved_private_names.end() == tail) {
2895 2896 2897 2898 2899 2900 2901 2902
    return;
  }
  UnresolvedList migrated_names;

  // If the saved tail is empty, the list used to be empty, so we should
  // migrate everything after the head.
  bool tail_is_empty = tail == UnresolvedList::Iterator();
  UnresolvedList::Iterator it =
2903
      tail_is_empty ? rare_data->unresolved_private_names.begin() : tail;
2904

2905
  for (; it != rare_data->unresolved_private_names.end(); ++it) {
2906 2907 2908 2909 2910 2911 2912
    VariableProxy* proxy = *it;
    VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
    migrated_names.Add(copy);
  }

  // Replace with the migrated copies.
  if (tail_is_empty) {
2913
    rare_data->unresolved_private_names.Clear();
2914
  } else {
2915
    rare_data->unresolved_private_names.Rewind(tail);
2916
  }
2917
  rare_data->unresolved_private_names.Append(std::move(migrated_names));
2918 2919 2920 2921 2922
}

Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
  DCHECK(!scope_info_.is_null());
  DCHECK_NULL(LookupLocalPrivateName(name));
2923
  DisallowGarbageCollection no_gc;
2924

2925
  VariableLookupResult lookup_result;
2926
  int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
2927 2928 2929 2930
  if (index < 0) {
    return nullptr;
  }

2931 2932 2933
  DCHECK(IsConstVariableMode(lookup_result.mode));
  DCHECK_EQ(lookup_result.init_flag, InitializationFlag::kNeedsInitialization);
  DCHECK_EQ(lookup_result.maybe_assigned_flag, MaybeAssignedFlag::kNotAssigned);
2934 2935 2936 2937

  // Add the found private name to the map to speed up subsequent
  // lookups for the same name.
  bool was_added;
2938 2939
  Variable* var = DeclarePrivateName(name, lookup_result.mode,
                                     lookup_result.is_static_flag, &was_added);
2940 2941 2942 2943 2944 2945 2946 2947
  DCHECK(was_added);
  var->AllocateTo(VariableLocation::CONTEXT, index);
  return var;
}

Variable* ClassScope::LookupPrivateName(VariableProxy* proxy) {
  DCHECK(!proxy->is_resolved());

2948 2949 2950
  for (PrivateNameScopeIterator scope_iter(this); !scope_iter.Done();
       scope_iter.Next()) {
    ClassScope* scope = scope_iter.GetScope();
2951 2952
    // Try finding it in the private name map first, if it can't be found,
    // try the deseralized scope info.
2953 2954 2955
    Variable* var = scope->LookupLocalPrivateName(proxy->raw_name());
    if (var == nullptr && !scope->scope_info_.is_null()) {
      var = scope->LookupPrivateNameInScopeInfo(proxy->raw_name());
2956
    }
2957 2958 2959
    if (var != nullptr) {
      return var;
    }
2960 2961 2962 2963 2964
  }
  return nullptr;
}

bool ClassScope::ResolvePrivateNames(ParseInfo* info) {
2965 2966
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
2967 2968 2969
    return true;
  }

2970
  UnresolvedList& list = rare_data->unresolved_private_names;
2971 2972 2973
  for (VariableProxy* proxy : list) {
    Variable* var = LookupPrivateName(proxy);
    if (var == nullptr) {
2974 2975
      // It's only possible to fail to resolve private names here if
      // this is at the top level or the private name is accessed through eval.
2976
      DCHECK(info->flags().is_eval() || outer_scope_->is_script_scope());
2977 2978 2979
      Scanner::Location loc = proxy->location();
      info->pending_error_handler()->ReportMessageAt(
          loc.beg_pos, loc.end_pos,
2980
          MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name());
2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993
      return false;
    } else {
      proxy->BindTo(var);
    }
  }

  // By now all unresolved private names should be resolved so
  // clear the list.
  list.Clear();
  return true;
}

VariableProxy* ClassScope::ResolvePrivateNamesPartially() {
2994 2995
  RareData* rare_data = GetRareData();
  if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
2996 2997 2998
    return nullptr;
  }

2999 3000 3001 3002
  PrivateNameScopeIterator private_name_scope_iter(this);
  private_name_scope_iter.Next();
  UnresolvedList& unresolved = rare_data->unresolved_private_names;
  bool has_private_names = rare_data->private_name_map.capacity() > 0;
3003 3004

  // If the class itself does not have private names, nor does it have
3005
  // an outer private name scope, then we are certain any private name access
3006
  // inside cannot be resolved.
3007
  if (!has_private_names && private_name_scope_iter.Done() &&
3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024
      !unresolved.is_empty()) {
    return unresolved.first();
  }

  for (VariableProxy* proxy = unresolved.first(); proxy != nullptr;) {
    DCHECK(proxy->IsPrivateName());
    VariableProxy* next = proxy->next_unresolved();
    unresolved.Remove(proxy);
    Variable* var = nullptr;

    // If we can find private name in the current class scope, we can bind
    // them immediately because it's going to shadow any outer private names.
    if (has_private_names) {
      var = LookupLocalPrivateName(proxy->raw_name());
      if (var != nullptr) {
        var->set_is_used();
        proxy->BindTo(var);
3025 3026 3027 3028 3029 3030
        // If the variable being accessed is a static private method, we need to
        // save the class variable in the context to check that the receiver is
        // the class during runtime.
        has_explicit_static_private_methods_access_ |=
            (var->is_static() &&
             IsPrivateMethodOrAccessorVariableMode(var->mode()));
3031 3032 3033 3034
      }
    }

    // If the current scope does not have declared private names,
3035 3036
    // try looking from the outer class scope later.
    if (var == nullptr) {
3037
      // There's no outer private name scope so we are certain that the variable
3038
      // cannot be resolved later.
3039
      if (private_name_scope_iter.Done()) {
3040 3041
        return proxy;
      }
3042

3043 3044 3045
      // The private name may be found later in the outer private name scope, so
      // push it to the outer sopce.
      private_name_scope_iter.AddUnresolvedPrivateName(proxy);
3046 3047 3048 3049 3050 3051 3052 3053 3054
    }

    proxy = next;
  }

  DCHECK(unresolved.is_empty());
  return nullptr;
}

3055
Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory,
3056
                                           IsStaticFlag is_static_flag,
3057
                                           int class_token_pos) {
3058
  DCHECK_IMPLIES(GetRareData() != nullptr, GetRareData()->brand == nullptr);
3059 3060 3061 3062
  bool was_added;
  Variable* brand = Declare(zone(), ast_value_factory->dot_brand_string(),
                            VariableMode::kConst, NORMAL_VARIABLE,
                            InitializationFlag::kNeedsInitialization,
3063
                            MaybeAssignedFlag::kNotAssigned, &was_added);
3064
  DCHECK(was_added);
3065
  brand->set_is_static_flag(is_static_flag);
3066 3067 3068 3069 3070 3071 3072
  brand->ForceContextAllocation();
  brand->set_is_used();
  EnsureRareData()->brand = brand;
  brand->set_initializer_position(class_token_pos);
  return brand;
}

3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087
Variable* ClassScope::DeclareClassVariable(AstValueFactory* ast_value_factory,
                                           const AstRawString* name,
                                           int class_token_pos) {
  DCHECK_NULL(class_variable_);
  bool was_added;
  class_variable_ =
      Declare(zone(), name == nullptr ? ast_value_factory->dot_string() : name,
              VariableMode::kConst, NORMAL_VARIABLE,
              InitializationFlag::kNeedsInitialization,
              MaybeAssignedFlag::kMaybeAssigned, &was_added);
  DCHECK(was_added);
  class_variable_->set_initializer_position(class_token_pos);
  return class_variable_;
}

3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
PrivateNameScopeIterator::PrivateNameScopeIterator(Scope* start)
    : start_scope_(start), current_scope_(start) {
  if (!start->is_class_scope() || start->AsClassScope()->IsParsingHeritage()) {
    Next();
  }
}

void PrivateNameScopeIterator::Next() {
  DCHECK(!Done());
  Scope* inner = current_scope_;
  Scope* scope = inner->outer_scope();
  while (scope != nullptr) {
    if (scope->is_class_scope()) {
      if (!inner->private_name_lookup_skips_outer_class()) {
        current_scope_ = scope;
        return;
      }
      skipped_any_scopes_ = true;
    }
    inner = scope;
    scope = scope->outer_scope();
  }
  current_scope_ = nullptr;
}

void PrivateNameScopeIterator::AddUnresolvedPrivateName(VariableProxy* proxy) {
  // During a reparse, current_scope_->already_resolved_ may be true here,
  // because the class scope is deserialized while the function scope inside may
  // be new.
  DCHECK(!proxy->is_resolved());
  DCHECK(proxy->IsPrivateName());
  GetScope()->EnsureRareData()->unresolved_private_names.Add(proxy);
  // Any closure scope that contain uses of private names that skips over a
  // class scope due to heritage expressions need private name context chain
  // recalculation, since not all scopes require a Context or ScopeInfo. See
  // comment in DeclarationScope::RecalcPrivateNameContextChain.
  if (V8_UNLIKELY(skipped_any_scopes_)) {
    start_scope_->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc();
  }
}

3129 3130
}  // namespace internal
}  // namespace v8