scope-info.cc 46 KB
Newer Older
1
// Copyright 2011 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 6
#include "src/objects/scope-info.h"

7 8
#include <stdlib.h>

9
#include "src/ast/scopes.h"
10
#include "src/ast/variables.h"
11
#include "src/init/bootstrapper.h"
12
#include "src/objects/module-inl.h"
13
#include "src/objects/objects-inl.h"
14
#include "src/objects/scope-info-inl.h"
15
#include "src/objects/string-set-inl.h"
16
#include "src/roots/roots.h"
17

18 19 20
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

21 22
namespace v8 {
namespace internal {
23

jochen's avatar
jochen committed
24
#ifdef DEBUG
25
bool ScopeInfo::Equals(ScopeInfo other) const {
26
  if (length() != other.length()) return false;
jochen's avatar
jochen committed
27
  for (int index = 0; index < length(); ++index) {
28
    Object entry = get(index);
29 30
    Object other_entry = other.get(index);
    if (entry.IsSmi()) {
jochen's avatar
jochen committed
31 32
      if (entry != other_entry) return false;
    } else {
33 34
      if (HeapObject::cast(entry).map().instance_type() !=
          HeapObject::cast(other_entry).map().instance_type()) {
jochen's avatar
jochen committed
35 36
        return false;
      }
37 38
      if (entry.IsString()) {
        if (!String::cast(entry).Equals(String::cast(other_entry))) {
jochen's avatar
jochen committed
39 40
          return false;
        }
41 42
      } else if (entry.IsScopeInfo()) {
        if (!ScopeInfo::cast(entry).Equals(ScopeInfo::cast(other_entry))) {
jochen's avatar
jochen committed
43 44
          return false;
        }
45 46 47
      } else if (entry.IsSourceTextModuleInfo()) {
        if (!SourceTextModuleInfo::cast(entry).Equals(
                SourceTextModuleInfo::cast(other_entry))) {
jochen's avatar
jochen committed
48 49 50 51 52 53 54 55 56 57 58
          return false;
        }
      } else {
        UNREACHABLE();
      }
    }
  }
  return true;
}
#endif

59
// static
60 61
template <typename IsolateT>
Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
62
                                    MaybeHandle<ScopeInfo> outer_scope) {
63
  // Collect variables.
64
  int context_local_count = 0;
65
  int module_vars_count = 0;
66 67 68 69
  // Stack allocated block scope variables are allocated in the parent
  // declaration scope, but are recorded in the block scope's scope info. First
  // slot index indicates at which offset a particular scope starts in the
  // parent declaration scope.
70
  for (Variable* var : *scope->locals()) {
71 72
    switch (var->location()) {
      case VariableLocation::CONTEXT:
Simon Zünd's avatar
Simon Zünd committed
73
      case VariableLocation::REPL_GLOBAL:
74 75 76 77 78 79 80
        context_local_count++;
        break;
      case VariableLocation::MODULE:
        module_vars_count++;
        break;
      default:
        break;
81 82
    }
  }
83 84
  // Determine use and location of the "this" binding if it is present.
  VariableAllocationInfo receiver_info;
85 86 87
  if (scope->is_declaration_scope() &&
      scope->AsDeclarationScope()->has_this_declaration()) {
    Variable* var = scope->AsDeclarationScope()->receiver();
88
    if (!var->is_used()) {
89
      receiver_info = VariableAllocationInfo::UNUSED;
90
    } else if (var->IsContextSlot()) {
91
      receiver_info = VariableAllocationInfo::CONTEXT;
92 93
    } else {
      DCHECK(var->IsParameter());
94
      receiver_info = VariableAllocationInfo::STACK;
95 96
    }
  } else {
97
    receiver_info = VariableAllocationInfo::NONE;
98 99
  }

100 101 102 103 104
  DCHECK(module_vars_count == 0 || scope->is_module_scope());

  // Make sure we allocate the correct amount.
  DCHECK_EQ(scope->ContextLocalCount(), context_local_count);

105 106 107 108 109
  // If the number of locals is small, we inline directly
  // in the scope info object.
  bool has_inlined_local_names =
      context_local_count < kScopeInfoMaxInlinedLocalNamesSize;

110
  const bool has_new_target =
111 112
      scope->is_declaration_scope() &&
      scope->AsDeclarationScope()->new_target_var() != nullptr;
113 114
  // TODO(cbruni): Don't always waste a field for the inferred name.
  const bool has_inferred_function_name = scope->is_function_scope();
115

116
  // Determine use and location of the function variable if it is present.
117
  VariableAllocationInfo function_name_info;
118 119 120 121
  if (scope->is_function_scope()) {
    if (scope->AsDeclarationScope()->function_var() != nullptr) {
      Variable* var = scope->AsDeclarationScope()->function_var();
      if (!var->is_used()) {
122
        function_name_info = VariableAllocationInfo::UNUSED;
123
      } else if (var->IsContextSlot()) {
124
        function_name_info = VariableAllocationInfo::CONTEXT;
125 126
      } else {
        DCHECK(var->IsStackLocal());
127
        function_name_info = VariableAllocationInfo::STACK;
128
      }
129
    } else {
130
      // Always reserve space for the debug name in the scope info.
131
      function_name_info = VariableAllocationInfo::UNUSED;
132
    }
133 134 135
  } else if (scope->is_module_scope() || scope->is_script_scope() ||
             scope->is_eval_scope()) {
    // Always reserve space for the debug name in the scope info.
136
    function_name_info = VariableAllocationInfo::UNUSED;
137
  } else {
138
    function_name_info = VariableAllocationInfo::NONE;
139 140
  }

141 142 143 144 145
  const bool has_brand =
      scope->is_class_scope()
          ? scope->AsClassScope()->brand() != nullptr
          : scope->IsConstructorScope() &&
                scope->AsDeclarationScope()->class_scope_has_private_brand();
146 147 148 149
  const bool should_save_class_variable_index =
      scope->is_class_scope()
          ? scope->AsClassScope()->should_save_class_variable_index()
          : false;
150 151
  const bool has_function_name =
      function_name_info != VariableAllocationInfo::NONE;
152
  const bool has_position_info = NeedsPositionInfo(scope->scope_type());
153 154 155 156
  const int parameter_count =
      scope->is_declaration_scope()
          ? scope->AsDeclarationScope()->num_parameters()
          : 0;
jochen's avatar
jochen committed
157
  const bool has_outer_scope_info = !outer_scope.is_null();
158

159 160 161 162 163 164
  Handle<SourceTextModuleInfo> module_info;
  if (scope->is_module_scope()) {
    module_info = SourceTextModuleInfo::New(isolate, zone,
                                            scope->AsModuleScope()->module());
  }

165 166 167 168 169 170
// Make sure the Fields enum agrees with Torque-generated offsets.
#define ASSERT_MATCHED_FIELD(name) \
  STATIC_ASSERT(OffsetOfElementAt(k##name) == k##name##Offset);
  FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(ASSERT_MATCHED_FIELD)
#undef ASSERT_MATCHED_FIELD

171 172 173 174 175
  const int local_names_container_size =
      has_inlined_local_names ? context_local_count : 1;

  const int length = kVariablePartIndex + local_names_container_size +
                     context_local_count +
176
                     (should_save_class_variable_index ? 1 : 0) +
177
                     (has_function_name ? kFunctionNameEntries : 0) +
178
                     (has_inferred_function_name ? 1 : 0) +
179
                     (has_position_info ? kPositionInfoEntries : 0) +
jochen's avatar
jochen committed
180
                     (has_outer_scope_info ? 1 : 0) +
181 182 183
                     (scope->is_module_scope()
                          ? 2 + kModuleVariableEntryLength * module_vars_count
                          : 0);
184

185 186 187 188 189 190 191
  // Create hash table if local names are not inlined.
  Handle<NameToIndexHashTable> local_names_hashtable;
  if (!has_inlined_local_names) {
    local_names_hashtable = NameToIndexHashTable::New(
        isolate, context_local_count, AllocationType::kOld);
  }

192
  Handle<ScopeInfo> scope_info_handle =
193 194 195
      isolate->factory()->NewScopeInfo(length);
  int index = kVariablePartIndex;
  {
196
    DisallowGarbageCollection no_gc;
197
    ScopeInfo scope_info = *scope_info_handle;
198
    WriteBarrierMode mode = scope_info.GetWriteBarrierMode(no_gc);
199

200 201
    bool has_simple_parameters = false;
    bool is_asm_module = false;
202
    bool sloppy_eval_can_extend_vars = false;
203 204 205
    if (scope->is_function_scope()) {
      DeclarationScope* function_scope = scope->AsDeclarationScope();
      has_simple_parameters = function_scope->has_simple_parameters();
206
#if V8_ENABLE_WEBASSEMBLY
207
      is_asm_module = function_scope->is_asm_module();
208
#endif  // V8_ENABLE_WEBASSEMBLY
209
    }
210
    FunctionKind function_kind = FunctionKind::kNormalFunction;
211 212
    if (scope->is_declaration_scope()) {
      function_kind = scope->AsDeclarationScope()->function_kind();
213 214
      sloppy_eval_can_extend_vars =
          scope->AsDeclarationScope()->sloppy_eval_can_extend_vars();
215
    }
216

217 218
    // Encode the flags.
    int flags =
219 220 221 222 223
        ScopeTypeBits::encode(scope->scope_type()) |
        SloppyEvalCanExtendVarsBit::encode(sloppy_eval_can_extend_vars) |
        LanguageModeBit::encode(scope->language_mode()) |
        DeclarationScopeBit::encode(scope->is_declaration_scope()) |
        ReceiverVariableBits::encode(receiver_info) |
224
        ClassScopeHasPrivateBrandBit::encode(has_brand) |
225
        HasSavedClassVariableBit::encode(should_save_class_variable_index) |
226 227 228 229 230 231 232 233 234
        HasNewTargetBit::encode(has_new_target) |
        FunctionVariableBits::encode(function_name_info) |
        HasInferredFunctionNameBit::encode(has_inferred_function_name) |
        IsAsmModuleBit::encode(is_asm_module) |
        HasSimpleParametersBit::encode(has_simple_parameters) |
        FunctionKindBits::encode(function_kind) |
        HasOuterScopeInfoBit::encode(has_outer_scope_info) |
        IsDebugEvaluateScopeBit::encode(scope->is_debug_evaluate_scope()) |
        ForceContextAllocationBit::encode(
235
            scope->ForceContextForLanguageMode()) |
236
        PrivateNameLookupSkipsOuterClassBit::encode(
237
            scope->private_name_lookup_skips_outer_class()) |
238 239
        HasContextExtensionSlotBit::encode(scope->HasContextExtensionSlot()) |
        IsReplModeScopeBit::encode(scope->is_repl_mode_scope()) |
Dan Elphick's avatar
Dan Elphick committed
240
        HasLocalsBlockListBit::encode(false);
241
    scope_info.set_flags(flags);
242

243 244
    scope_info.set_parameter_count(parameter_count);
    scope_info.set_context_local_count(context_local_count);
245

246 247 248 249 250
    // Jump ahead to set the number of module variables so that we can use range
    // DCHECKs in future steps.
    if (scope->is_module_scope()) {
      scope_info.set_module_variable_count(module_vars_count);
    }
251 252 253
    if (!has_inlined_local_names) {
      scope_info.set_context_local_names_hashtable(*local_names_hashtable);
    }
254

255 256 257
    // Add context locals' names and info, module variables' names and info.
    // Context locals are added using their index.
    int context_local_base = index;
258 259
    int context_local_info_base =
        context_local_base + local_names_container_size;
260
    int module_var_entry = scope_info.ModuleVariableCountIndex() + 1;
261

262 263
    for (Variable* var : *scope->locals()) {
      switch (var->location()) {
Simon Zünd's avatar
Simon Zünd committed
264 265
        case VariableLocation::CONTEXT:
        case VariableLocation::REPL_GLOBAL: {
266 267
          // Due to duplicate parameters, context locals aren't guaranteed to
          // come in order.
268
          int local_index = var->index() - scope->ContextHeaderLength();
269 270 271
          DCHECK_LE(0, local_index);
          DCHECK_LT(local_index, context_local_count);
          uint32_t info =
272 273 274 275 276
              VariableModeBits::encode(var->mode()) |
              InitFlagBit::encode(var->initialization_flag()) |
              MaybeAssignedFlagBit::encode(var->maybe_assigned()) |
              ParameterNumberBits::encode(ParameterNumberBits::kMax) |
              IsStaticFlagBit::encode(var->is_static_flag());
277 278 279 280 281 282 283
          if (has_inlined_local_names) {
            scope_info.set(context_local_base + local_index, *var->name(),
                           mode);
          } else {
            Handle<NameToIndexHashTable> new_table = NameToIndexHashTable::Add(
                isolate, local_names_hashtable, var->name(), local_index);
            DCHECK_EQ(*new_table, *local_names_hashtable);
284
            USE(new_table);
285
          }
286 287
          scope_info.set(context_local_info_base + local_index,
                         Smi::FromInt(info));
288 289 290
          break;
        }
        case VariableLocation::MODULE: {
291 292 293
          scope_info.set(module_var_entry +
                             TorqueGeneratedModuleVariableOffsets::kNameOffset /
                                 kTaggedSize,
294
                         *var->name(), mode);
295 296 297 298 299
          scope_info.set(
              module_var_entry +
                  TorqueGeneratedModuleVariableOffsets::kIndexOffset /
                      kTaggedSize,
              Smi::FromInt(var->index()));
300
          uint32_t properties =
301 302 303 304 305
              VariableModeBits::encode(var->mode()) |
              InitFlagBit::encode(var->initialization_flag()) |
              MaybeAssignedFlagBit::encode(var->maybe_assigned()) |
              ParameterNumberBits::encode(ParameterNumberBits::kMax) |
              IsStaticFlagBit::encode(var->is_static_flag());
306 307 308 309 310
          scope_info.set(
              module_var_entry +
                  TorqueGeneratedModuleVariableOffsets::kPropertiesOffset /
                      kTaggedSize,
              Smi::FromInt(properties));
311 312 313 314 315
          module_var_entry += kModuleVariableEntryLength;
          break;
        }
        default:
          break;
316
      }
317
    }
318

319 320 321 322 323 324 325 326 327 328 329
    if (scope->is_declaration_scope()) {
      // Mark contexts slots with the parameter number they represent. We walk
      // the list of parameters. That can include duplicate entries if a
      // parameter name is repeated. By walking upwards, we'll automatically
      // mark the context slot with the highest parameter number that uses this
      // variable. That will be the parameter number that is represented by the
      // context slot. All lower parameters will only be available on the stack
      // through the arguments object.
      for (int i = 0; i < parameter_count; i++) {
        Variable* parameter = scope->AsDeclarationScope()->parameter(i);
        if (parameter->location() != VariableLocation::CONTEXT) continue;
330 331
        int param_index = parameter->index() - scope->ContextHeaderLength();
        int info_index = context_local_info_base + param_index;
332
        int info = Smi::ToInt(scope_info.get(info_index));
333
        info = ParameterNumberBits::update(info, i);
334
        scope_info.set(info_index, Smi::FromInt(info));
335
      }
336 337
    }

338 339
    // Advance past local names and local names info.
    index += local_names_container_size + context_local_count;
340

341 342 343 344 345 346 347
    DCHECK_EQ(index, scope_info.SavedClassVariableInfoIndex());
    // If the scope is a class scope and has used static private methods, save
    // the context slot index of the class variable.
    // Store the class variable index.
    if (should_save_class_variable_index) {
      Variable* class_variable = scope->AsClassScope()->class_variable();
      DCHECK_EQ(class_variable->location(), VariableLocation::CONTEXT);
348 349 350 351 352 353 354 355 356
      int local_index;
      if (has_inlined_local_names) {
        local_index = class_variable->index();
      } else {
        Handle<Name> name = class_variable->name();
        InternalIndex entry = local_names_hashtable->FindEntry(isolate, name);
        local_index = entry.as_int();
      }
      scope_info.set(index++, Smi::FromInt(local_index));
357 358
    }

359
    // If present, add the function variable name and its index.
360
    DCHECK_EQ(index, scope_info.FunctionVariableInfoIndex());
361 362 363
    if (has_function_name) {
      Variable* var = scope->AsDeclarationScope()->function_var();
      int var_index = -1;
364
      Object name = Smi::zero();
365 366
      if (var != nullptr) {
        var_index = var->index();
367
        name = *var->name();
368
      }
369 370
      scope_info.set(index++, name, mode);
      scope_info.set(index++, Smi::FromInt(var_index));
371
      DCHECK(function_name_info != VariableAllocationInfo::CONTEXT ||
372
             var_index == scope_info.ContextLength() - 1);
373
    }
374

375
    DCHECK_EQ(index, scope_info.InferredFunctionNameIndex());
376 377 378 379
    if (has_inferred_function_name) {
      // The inferred function name is taken from the SFI.
      index++;
    }
380

381
    DCHECK_EQ(index, scope_info.PositionInfoIndex());
382
    if (has_position_info) {
383 384
      scope_info.set(index++, Smi::FromInt(scope->start_position()));
      scope_info.set(index++, Smi::FromInt(scope->end_position()));
385
    }
386

387
    // If present, add the outer scope info.
388
    DCHECK(index == scope_info.OuterScopeInfoIndex());
389
    if (has_outer_scope_info) {
390
      scope_info.set(index++, *outer_scope.ToHandleChecked(), mode);
391
    }
jochen's avatar
jochen committed
392

393 394 395 396 397
    // Module-specific information (only for module scopes).
    if (scope->is_module_scope()) {
      DCHECK_EQ(index, scope_info.ModuleInfoIndex());
      scope_info.set(index++, *module_info);
      DCHECK_EQ(index, scope_info.ModuleVariableCountIndex());
398 399
      // Module variable count was already written above.
      index++;
400 401 402 403
      DCHECK_EQ(index, scope_info.ModuleVariablesIndex());
      // The variable entries themselves have already been written above.
      index += kModuleVariableEntryLength * module_vars_count;
    }
404 405
  }

406
  DCHECK_EQ(index, scope_info_handle->length());
407
  DCHECK_EQ(parameter_count, scope_info_handle->ParameterCount());
408
  DCHECK_EQ(scope->num_heap_slots(), scope_info_handle->ContextLength());
409

410
  return scope_info_handle;
411 412
}

413
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
414 415 416
    Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
                                        Scope* scope,
                                        MaybeHandle<ScopeInfo> outer_scope);
417
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
418 419 420
    Handle<ScopeInfo> ScopeInfo::Create(LocalIsolate* isolate, Zone* zone,
                                        Scope* scope,
                                        MaybeHandle<ScopeInfo> outer_scope);
421

422
// static
jochen's avatar
jochen committed
423 424 425
Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
    Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) {
  const bool has_outer_scope_info = !outer_scope.is_null();
426
  const int length = kVariablePartIndex + (has_outer_scope_info ? 1 : 0);
427 428 429 430 431 432

  Factory* factory = isolate->factory();
  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);

  // Encode the flags.
  int flags =
433 434 435 436 437
      ScopeTypeBits::encode(WITH_SCOPE) |
      SloppyEvalCanExtendVarsBit::encode(false) |
      LanguageModeBit::encode(LanguageMode::kSloppy) |
      DeclarationScopeBit::encode(false) |
      ReceiverVariableBits::encode(VariableAllocationInfo::NONE) |
438
      ClassScopeHasPrivateBrandBit::encode(false) |
439
      HasSavedClassVariableBit::encode(false) | HasNewTargetBit::encode(false) |
440 441
      FunctionVariableBits::encode(VariableAllocationInfo::NONE) |
      IsAsmModuleBit::encode(false) | HasSimpleParametersBit::encode(true) |
442
      FunctionKindBits::encode(FunctionKind::kNormalFunction) |
443 444 445 446 447
      HasOuterScopeInfoBit::encode(has_outer_scope_info) |
      IsDebugEvaluateScopeBit::encode(false) |
      ForceContextAllocationBit::encode(false) |
      PrivateNameLookupSkipsOuterClassBit::encode(false) |
      HasContextExtensionSlotBit::encode(true) |
Dan Elphick's avatar
Dan Elphick committed
448
      IsReplModeScopeBit::encode(false) | HasLocalsBlockListBit::encode(false);
449
  scope_info->set_flags(flags);
450

451 452
  scope_info->set_parameter_count(0);
  scope_info->set_context_local_count(0);
453 454

  int index = kVariablePartIndex;
455
  DCHECK_EQ(index, scope_info->FunctionVariableInfoIndex());
456
  DCHECK_EQ(index, scope_info->InferredFunctionNameIndex());
457
  DCHECK_EQ(index, scope_info->PositionInfoIndex());
458
  DCHECK(index == scope_info->OuterScopeInfoIndex());
jochen's avatar
jochen committed
459 460 461
  if (has_outer_scope_info) {
    scope_info->set(index++, *outer_scope.ToHandleChecked());
  }
462 463
  DCHECK_EQ(index, scope_info->length());
  DCHECK_EQ(0, scope_info->ParameterCount());
464
  DCHECK_EQ(scope_info->ContextHeaderLength(), scope_info->ContextLength());
465 466
  return scope_info;
}
467

468
// static
469
Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
470
  return CreateForBootstrapping(isolate, BootstrappingType::kScript);
471 472 473 474
}

// static
Handle<ScopeInfo> ScopeInfo::CreateForEmptyFunction(Isolate* isolate) {
475
  return CreateForBootstrapping(isolate, BootstrappingType::kFunction);
476 477 478
}

// static
479 480 481
Handle<ScopeInfo> ScopeInfo::CreateForNativeContext(Isolate* isolate) {
  return CreateForBootstrapping(isolate, BootstrappingType::kNative);
}
482

483 484 485
// static
Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
                                                    BootstrappingType type) {
486
  const int parameter_count = 0;
487 488 489 490 491
  const bool is_empty_function = type == BootstrappingType::kFunction;
  const bool is_native_context = type == BootstrappingType::kNative;
  const bool is_script = type == BootstrappingType::kScript;
  const int context_local_count =
      is_empty_function || is_native_context ? 0 : 1;
492
  const bool has_inferred_function_name = is_empty_function;
493
  const bool has_position_info = true;
494 495
  // NOTE: Local names are always inlined here, since context_local_count < 2.
  DCHECK_LT(context_local_count, kScopeInfoMaxInlinedLocalNamesSize);
496
  const int length = kVariablePartIndex + 2 * context_local_count +
497 498
                     (is_empty_function ? kFunctionNameEntries : 0) +
                     (has_inferred_function_name ? 1 : 0) +
499
                     (has_position_info ? kPositionInfoEntries : 0);
500 501

  Factory* factory = isolate->factory();
502 503
  Handle<ScopeInfo> scope_info =
      factory->NewScopeInfo(length, AllocationType::kReadOnly);
504 505

  // Encode the flags.
506 507 508 509 510 511 512
  int flags =
      ScopeTypeBits::encode(is_empty_function ? FUNCTION_SCOPE : SCRIPT_SCOPE) |
      SloppyEvalCanExtendVarsBit::encode(false) |
      LanguageModeBit::encode(LanguageMode::kSloppy) |
      DeclarationScopeBit::encode(true) |
      ReceiverVariableBits::encode(is_script ? VariableAllocationInfo::CONTEXT
                                             : VariableAllocationInfo::UNUSED) |
513
      ClassScopeHasPrivateBrandBit::encode(false) |
514
      HasSavedClassVariableBit::encode(false) | HasNewTargetBit::encode(false) |
515 516 517 518 519 520 521 522 523 524 525
      FunctionVariableBits::encode(is_empty_function
                                       ? VariableAllocationInfo::UNUSED
                                       : VariableAllocationInfo::NONE) |
      HasInferredFunctionNameBit::encode(has_inferred_function_name) |
      IsAsmModuleBit::encode(false) | HasSimpleParametersBit::encode(true) |
      FunctionKindBits::encode(FunctionKind::kNormalFunction) |
      HasOuterScopeInfoBit::encode(false) |
      IsDebugEvaluateScopeBit::encode(false) |
      ForceContextAllocationBit::encode(false) |
      PrivateNameLookupSkipsOuterClassBit::encode(false) |
      HasContextExtensionSlotBit::encode(is_native_context) |
Dan Elphick's avatar
Dan Elphick committed
526
      IsReplModeScopeBit::encode(false) | HasLocalsBlockListBit::encode(false);
527 528 529
  scope_info->set_flags(flags);
  scope_info->set_parameter_count(parameter_count);
  scope_info->set_context_local_count(context_local_count);
530 531 532 533

  int index = kVariablePartIndex;

  // Here we add info for context-allocated "this".
534
  DCHECK_EQ(index, scope_info->ContextLocalNamesIndex());
535
  if (context_local_count) {
536
    scope_info->set(index++, ReadOnlyRoots(isolate).this_string());
537
  }
538
  DCHECK_EQ(index, scope_info->ContextLocalInfosIndex());
539
  if (context_local_count > 0) {
540
    const uint32_t value =
541 542 543 544 545
        VariableModeBits::encode(VariableMode::kConst) |
        InitFlagBit::encode(kCreatedInitialized) |
        MaybeAssignedFlagBit::encode(kNotAssigned) |
        ParameterNumberBits::encode(ParameterNumberBits::kMax) |
        IsStaticFlagBit::encode(IsStaticFlag::kNotStatic);
546 547
    scope_info->set(index++, Smi::FromInt(value));
  }
548

549
  DCHECK_EQ(index, scope_info->FunctionVariableInfoIndex());
550 551
  if (is_empty_function) {
    scope_info->set(index++, *isolate->factory()->empty_string());
552
    scope_info->set(index++, Smi::zero());
553
  }
554
  DCHECK_EQ(index, scope_info->InferredFunctionNameIndex());
555 556 557
  if (has_inferred_function_name) {
    scope_info->set(index++, *isolate->factory()->empty_string());
  }
558 559
  DCHECK_EQ(index, scope_info->PositionInfoIndex());
  // Store dummy position to be in sync with the {scope_type}.
560 561
  scope_info->set(index++, Smi::zero());
  scope_info->set(index++, Smi::zero());
562
  DCHECK_EQ(index, scope_info->OuterScopeInfoIndex());
563
  DCHECK_EQ(index, scope_info->length());
564
  DCHECK_EQ(scope_info->ParameterCount(), parameter_count);
565
  if (is_empty_function || is_native_context) {
566 567
    DCHECK_EQ(scope_info->ContextLength(), 0);
  } else {
568 569
    DCHECK_EQ(scope_info->ContextLength(),
              scope_info->ContextHeaderLength() + 1);
570
  }
571 572 573 574

  return scope_info;
}

575
Object ScopeInfo::get(int index) const {
576 577
  PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
  return get(cage_base, index);
578 579
}

580
Object ScopeInfo::get(PtrComprCageBase cage_base, int index) const {
581
  DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length()));
582
  return TaggedField<Object>::Relaxed_Load(cage_base, *this,
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
                                           OffsetOfElementAt(index));
}

void ScopeInfo::set(int index, Smi value) {
  DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length()));
  DCHECK(Object(value).IsSmi());
  int offset = OffsetOfElementAt(index);
  RELAXED_WRITE_FIELD(*this, offset, value);
}

void ScopeInfo::set(int index, Object value, WriteBarrierMode mode) {
  DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length()));
  int offset = OffsetOfElementAt(index);
  RELAXED_WRITE_FIELD(*this, offset, value);
  CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
}

void ScopeInfo::CopyElements(Isolate* isolate, int dst_index, ScopeInfo src,
                             int src_index, int len, WriteBarrierMode mode) {
  if (len == 0) return;
  DCHECK_LE(src_index + len, src.length());
  DisallowGarbageCollection no_gc;

  ObjectSlot dst_slot(RawFieldOfElementAt(dst_index));
  ObjectSlot src_slot(src.RawFieldOfElementAt(src_index));
  isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode);
}

ObjectSlot ScopeInfo::RawFieldOfElementAt(int index) {
  return RawField(OffsetOfElementAt(index));
}

int ScopeInfo::length() const {
  // AllocatedSize() is generated by Torque and represents the size in bytes of
  // the object, as computed from flags, context_local_count, and possibly
  // module_variable_count. Convert that size into a number of slots.
619
  return (AllocatedSize() - HeapObject::kHeaderSize) / kTaggedSize;
620 621
}

622
// static
Dan Elphick's avatar
Dan Elphick committed
623 624
Handle<ScopeInfo> ScopeInfo::RecreateWithBlockList(
    Isolate* isolate, Handle<ScopeInfo> original, Handle<StringSet> blocklist) {
625
  DCHECK(!original.is_null());
Dan Elphick's avatar
Dan Elphick committed
626
  if (original->HasLocalsBlockList()) return original;
627

628 629
  int length = original->length() + 1;
  Handle<ScopeInfo> scope_info = isolate->factory()->NewScopeInfo(length);
630 631

  // Copy the static part first and update the flags to include the
Dan Elphick's avatar
Dan Elphick committed
632
  // blocklist field, so {LocalsBlockListIndex} returns the correct value.
633 634
  scope_info->CopyElements(isolate, 0, *original, 0, kVariablePartIndex,
                           WriteBarrierMode::UPDATE_WRITE_BARRIER);
635
  scope_info->set_flags(
Dan Elphick's avatar
Dan Elphick committed
636
      HasLocalsBlockListBit::update(scope_info->Flags(), true));
637

Dan Elphick's avatar
Dan Elphick committed
638 639 640
  // Copy the dynamic part including the provided blocklist:
  //   1) copy all the fields up to the blocklist index
  //   2) add the blocklist
641 642 643
  //   3) copy the remaining fields
  scope_info->CopyElements(
      isolate, kVariablePartIndex, *original, kVariablePartIndex,
Dan Elphick's avatar
Dan Elphick committed
644
      scope_info->LocalsBlockListIndex() - kVariablePartIndex,
645
      WriteBarrierMode::UPDATE_WRITE_BARRIER);
646
  scope_info->set_locals_block_list(*blocklist);
647 648 649 650
  scope_info->CopyElements(isolate, scope_info->LocalsBlockListIndex() + 1,
                           *original, scope_info->LocalsBlockListIndex(),
                           length - scope_info->LocalsBlockListIndex() - 1,
                           WriteBarrierMode::UPDATE_WRITE_BARRIER);
651 652 653
  return scope_info;
}

654
ScopeInfo ScopeInfo::Empty(Isolate* isolate) {
655
  return ReadOnlyRoots(isolate).empty_scope_info();
656 657
}

658 659
bool ScopeInfo::IsEmpty() const { return IsEmptyBit::decode(Flags()); }

660
ScopeType ScopeInfo::scope_type() const {
661
  DCHECK(!IsEmpty());
662
  return ScopeTypeBits::decode(Flags());
663 664
}

665
bool ScopeInfo::is_script_scope() const {
666
  return !IsEmpty() && scope_type() == SCRIPT_SCOPE;
667 668
}

669 670
bool ScopeInfo::SloppyEvalCanExtendVars() const {
  bool sloppy_eval_can_extend_vars =
671
      SloppyEvalCanExtendVarsBit::decode(Flags());
672 673 674
  DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_sloppy(language_mode()));
  DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_declaration_scope());
  return sloppy_eval_can_extend_vars;
675 676
}

677
LanguageMode ScopeInfo::language_mode() const {
678
  return LanguageModeBit::decode(Flags());
679 680
}

681
bool ScopeInfo::is_declaration_scope() const {
682
  return DeclarationScopeBit::decode(Flags());
683 684
}

685
int ScopeInfo::ContextLength() const {
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
  if (IsEmpty()) return 0;
  int context_locals = ContextLocalCount();
  bool function_name_context_slot = HasContextAllocatedFunctionName();
  bool force_context = ForceContextAllocationBit::decode(Flags());
  bool has_context =
      context_locals > 0 || force_context || function_name_context_slot ||
      scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE ||
      (scope_type() == BLOCK_SCOPE && SloppyEvalCanExtendVars() &&
       is_declaration_scope()) ||
      (scope_type() == FUNCTION_SCOPE && SloppyEvalCanExtendVars()) ||
      (scope_type() == FUNCTION_SCOPE && IsAsmModule()) ||
      scope_type() == MODULE_SCOPE;

  if (!has_context) return 0;
  return ContextHeaderLength() + context_locals +
         (function_name_context_slot ? 1 : 0);
702 703
}

704
bool ScopeInfo::HasContextExtensionSlot() const {
705
  return HasContextExtensionSlotBit::decode(Flags());
706 707 708
}

int ScopeInfo::ContextHeaderLength() const {
709 710
  return HasContextExtensionSlot() ? Context::MIN_CONTEXT_EXTENDED_SLOTS
                                   : Context::MIN_CONTEXT_SLOTS;
711 712
}

713
bool ScopeInfo::HasReceiver() const {
714
  return VariableAllocationInfo::NONE != ReceiverVariableBits::decode(Flags());
715 716
}

717
bool ScopeInfo::HasAllocatedReceiver() const {
718 719 720
  VariableAllocationInfo allocation = ReceiverVariableBits::decode(Flags());
  return allocation == VariableAllocationInfo::STACK ||
         allocation == VariableAllocationInfo::CONTEXT;
721 722
}

723 724
bool ScopeInfo::ClassScopeHasPrivateBrand() const {
  return ClassScopeHasPrivateBrandBit::decode(Flags());
725 726
}

727 728
bool ScopeInfo::HasSavedClassVariable() const {
  return HasSavedClassVariableBit::decode(Flags());
729 730
}

731
bool ScopeInfo::HasNewTarget() const {
732
  return HasNewTargetBit::decode(Flags());
733
}
734

735
bool ScopeInfo::HasFunctionName() const {
736
  return VariableAllocationInfo::NONE != FunctionVariableBits::decode(Flags());
737 738
}

739 740 741 742 743
bool ScopeInfo::HasContextAllocatedFunctionName() const {
  return VariableAllocationInfo::CONTEXT ==
         FunctionVariableBits::decode(Flags());
}

744
bool ScopeInfo::HasInferredFunctionName() const {
745
  return HasInferredFunctionNameBit::decode(Flags());
746 747
}

748
bool ScopeInfo::HasPositionInfo() const {
749
  if (IsEmpty()) return false;
750 751 752 753 754 755
  return NeedsPositionInfo(scope_type());
}

// static
bool ScopeInfo::NeedsPositionInfo(ScopeType type) {
  return type == FUNCTION_SCOPE || type == SCRIPT_SCOPE || type == EVAL_SCOPE ||
756
         type == MODULE_SCOPE || type == CLASS_SCOPE;
757 758
}

759 760
bool ScopeInfo::HasSharedFunctionName() const {
  return FunctionName() != SharedFunctionInfo::kNoSharedNameSentinel;
761 762
}

763
void ScopeInfo::SetFunctionName(Object name) {
764
  DCHECK(HasFunctionName());
765
  DCHECK(name.IsString() || name == SharedFunctionInfo::kNoSharedNameSentinel);
766 767
  DCHECK_IMPLIES(HasContextAllocatedFunctionName(),
                 name.IsInternalizedString());
768
  set_function_variable_info_name(name);
769 770
}

771
void ScopeInfo::SetInferredFunctionName(String name) {
772
  DCHECK(HasInferredFunctionName());
773
  set_inferred_function_name(name);
774 775
}

776
bool ScopeInfo::HasOuterScopeInfo() const {
777
  return HasOuterScopeInfoBit::decode(Flags());
jochen's avatar
jochen committed
778
}
779

780
bool ScopeInfo::IsDebugEvaluateScope() const {
781
  return IsDebugEvaluateScopeBit::decode(Flags());
782 783 784
}

void ScopeInfo::SetIsDebugEvaluateScope() {
785 786
  CHECK(!IsEmpty());
  DCHECK_EQ(scope_type(), WITH_SCOPE);
787
  set_flags(Flags() | IsDebugEvaluateScopeBit::encode(true));
788 789
}

790
bool ScopeInfo::PrivateNameLookupSkipsOuterClass() const {
791
  return PrivateNameLookupSkipsOuterClassBit::decode(Flags());
792 793
}

Simon Zünd's avatar
Simon Zünd committed
794
bool ScopeInfo::IsReplModeScope() const {
795
  return IsReplModeScopeBit::decode(Flags());
Simon Zünd's avatar
Simon Zünd committed
796 797
}

Dan Elphick's avatar
Dan Elphick committed
798 799
bool ScopeInfo::HasLocalsBlockList() const {
  return HasLocalsBlockListBit::decode(Flags());
800 801
}

Dan Elphick's avatar
Dan Elphick committed
802 803
StringSet ScopeInfo::LocalsBlockList() const {
  DCHECK(HasLocalsBlockList());
804
  return StringSet::cast(locals_block_list());
805 806
}

807
bool ScopeInfo::HasContext() const { return ContextLength() > 0; }
808

809
Object ScopeInfo::FunctionName() const {
810
  DCHECK(HasFunctionName());
811
  return function_variable_info_name();
812 813
}

814
Object ScopeInfo::InferredFunctionName() const {
815
  DCHECK(HasInferredFunctionName());
816
  return inferred_function_name();
817 818
}

819
String ScopeInfo::FunctionDebugName() const {
820
  if (!HasFunctionName()) return GetReadOnlyRoots().empty_string();
821
  Object name = FunctionName();
822
  if (name.IsString() && String::cast(name).length() > 0) {
823 824 825 826
    return String::cast(name);
  }
  if (HasInferredFunctionName()) {
    name = InferredFunctionName();
827
    if (name.IsString()) return String::cast(name);
828
  }
829
  return GetReadOnlyRoots().empty_string();
830 831
}

832
int ScopeInfo::StartPosition() const {
833
  DCHECK(HasPositionInfo());
834
  return position_info_start();
835 836
}

837
int ScopeInfo::EndPosition() const {
838
  DCHECK(HasPositionInfo());
839
  return position_info_end();
840 841 842 843 844
}

void ScopeInfo::SetPositionInfo(int start, int end) {
  DCHECK(HasPositionInfo());
  DCHECK_LE(start, end);
845 846
  set_position_info_start(start);
  set_position_info_end(end);
847 848
}

849
ScopeInfo ScopeInfo::OuterScopeInfo() const {
jochen's avatar
jochen committed
850
  DCHECK(HasOuterScopeInfo());
851
  return ScopeInfo::cast(outer_scope_info());
jochen's avatar
jochen committed
852 853
}

854
SourceTextModuleInfo ScopeInfo::ModuleDescriptorInfo() const {
855
  DCHECK(scope_type() == MODULE_SCOPE);
856
  return SourceTextModuleInfo::cast(module_info());
857
}
858

859 860
String ScopeInfo::ContextInlinedLocalName(int var) const {
  DCHECK(HasInlinedLocalNames());
861
  return context_local_names(var);
862 863
}

864 865 866 867 868 869
String ScopeInfo::ContextInlinedLocalName(PtrComprCageBase cage_base,
                                          int var) const {
  DCHECK(HasInlinedLocalNames());
  return context_local_names(cage_base, var);
}

870
VariableMode ScopeInfo::ContextLocalMode(int var) const {
871 872
  int value = context_local_infos(var);
  return VariableModeBits::decode(value);
873 874
}

875
IsStaticFlag ScopeInfo::ContextLocalIsStaticFlag(int var) const {
876 877
  int value = context_local_infos(var);
  return IsStaticFlagBit::decode(value);
878 879
}

880
InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) const {
881 882
  int value = context_local_infos(var);
  return InitFlagBit::decode(value);
883 884
}

885
bool ScopeInfo::ContextLocalIsParameter(int var) const {
886 887
  int value = context_local_infos(var);
  return ParameterNumberBits::decode(value) != ParameterNumberBits::kMax;
888 889 890 891
}

uint32_t ScopeInfo::ContextLocalParameterNumber(int var) const {
  DCHECK(ContextLocalIsParameter(var));
892 893
  int value = context_local_infos(var);
  return ParameterNumberBits::decode(value);
894 895
}

896
MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) const {
897 898
  int value = context_local_infos(var);
  return MaybeAssignedFlagBit::decode(value);
899 900
}

901
// static
902
bool ScopeInfo::VariableIsSynthetic(String name) {
903 904 905 906
  // There's currently no flag stored on the ScopeInfo to indicate that a
  // variable is a compiler-introduced temporary. However, to avoid conflict
  // with user declarations, the current temporaries like .generator_object and
  // .result start with a dot, so we can use that as a flag. It's a hack!
907
  return name.length() == 0 || name.Get(0) == '.' || name.Get(0) == '#' ||
908
         name.Equals(name.GetReadOnlyRoots().this_string());
909 910
}

911 912 913 914 915
int ScopeInfo::ModuleVariableCount() const {
  DCHECK_EQ(scope_type(), MODULE_SCOPE);
  return module_variable_count();
}

916
int ScopeInfo::ModuleIndex(String name, VariableMode* mode,
917 918
                           InitializationFlag* init_flag,
                           MaybeAssignedFlag* maybe_assigned_flag) {
919
  DisallowGarbageCollection no_gc;
920
  DCHECK(name.IsInternalizedString());
921 922 923 924 925
  DCHECK_EQ(scope_type(), MODULE_SCOPE);
  DCHECK_NOT_NULL(mode);
  DCHECK_NOT_NULL(init_flag);
  DCHECK_NOT_NULL(maybe_assigned_flag);

926
  int module_vars_count = module_variable_count();
927
  for (int i = 0; i < module_vars_count; ++i) {
928
    String var_name = module_variables_name(i);
929
    if (name.Equals(var_name)) {
930 931
      int index;
      ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag);
932 933 934 935
      return index;
    }
  }

936
  return 0;
937
}
938

939
int ScopeInfo::InlinedLocalNamesLookup(String name) {
940 941
  DisallowGarbageCollection no_gc;
  PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
942 943
  int local_count = context_local_count();
  for (int i = 0; i < local_count; ++i) {
944
    if (name == ContextInlinedLocalName(cage_base, i)) {
945 946 947 948 949 950 951
      return i;
    }
  }
  return -1;
}

int ScopeInfo::ContextSlotIndex(Handle<String> name,
952
                                VariableLookupResult* lookup_result) {
953
  DisallowGarbageCollection no_gc;
954
  DCHECK(name->IsInternalizedString());
955
  DCHECK_NOT_NULL(lookup_result);
956

957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
  if (IsEmpty()) return -1;

  int index = HasInlinedLocalNames()
                  ? InlinedLocalNamesLookup(*name)
                  : context_local_names_hashtable().Lookup(name);

  if (index != -1) {
    lookup_result->mode = ContextLocalMode(index);
    lookup_result->is_static_flag = ContextLocalIsStaticFlag(index);
    lookup_result->init_flag = ContextLocalInitFlag(index);
    lookup_result->maybe_assigned_flag = ContextLocalMaybeAssignedFlag(index);
    lookup_result->is_repl_mode = IsReplModeScope();
    int context_slot = ContextHeaderLength() + index;
    DCHECK_LT(context_slot, ContextLength());
    return context_slot;
972
  }
973

974 975 976
  return -1;
}

977 978 979 980 981
int ScopeInfo::ContextSlotIndex(Handle<String> name) {
  VariableLookupResult lookup_result;
  return ContextSlotIndex(name, &lookup_result);
}

982 983 984 985 986 987 988
std::pair<String, int> ScopeInfo::SavedClassVariable() const {
  DCHECK(HasSavedClassVariableBit::decode(Flags()));
  if (HasInlinedLocalNames()) {
    // The saved class variable info corresponds to the context slot index.
    int index = saved_class_variable_info() - Context::MIN_CONTEXT_SLOTS;
    DCHECK_GE(index, 0);
    DCHECK_LT(index, ContextLocalCount());
989
    String name = ContextInlinedLocalName(index);
990 991 992 993
    return std::make_pair(name, index);
  } else {
    // The saved class variable info corresponds to the offset in the hash
    // table storage.
994 995 996 997 998
    InternalIndex entry(saved_class_variable_info());
    NameToIndexHashTable table = context_local_names_hashtable();
    Object name = table.KeyAt(entry);
    DCHECK(name.IsString());
    return std::make_pair(String::cast(name), table.IndexAt(entry));
999 1000 1001
  }
}

1002
int ScopeInfo::ReceiverContextSlotIndex() const {
1003 1004
  if (ReceiverVariableBits::decode(Flags()) ==
      VariableAllocationInfo::CONTEXT) {
1005
    return ContextHeaderLength();
1006
  }
1007 1008 1009
  return -1;
}

1010 1011 1012 1013 1014 1015 1016 1017
int ScopeInfo::ParametersStartIndex() const {
  if (ReceiverVariableBits::decode(Flags()) ==
      VariableAllocationInfo::CONTEXT) {
    return ContextHeaderLength() + 1;
  }
  return ContextHeaderLength();
}

1018
int ScopeInfo::FunctionContextSlotIndex(String name) const {
1019
  DCHECK(name.IsInternalizedString());
1020 1021 1022 1023 1024
  if (HasContextAllocatedFunctionName()) {
    DCHECK_IMPLIES(HasFunctionName(), FunctionName().IsInternalizedString());
    if (FunctionName() == name) {
      return function_variable_info_context_or_stack_slot_index();
    }
1025 1026 1027 1028
  }
  return -1;
}

1029
FunctionKind ScopeInfo::function_kind() const {
1030
  return FunctionKindBits::decode(Flags());
1031 1032
}

1033
int ScopeInfo::ContextLocalNamesIndex() const {
1034
  return ConvertOffsetToIndex(kContextLocalNamesOffset);
1035 1036
}

1037
int ScopeInfo::ContextLocalInfosIndex() const {
1038
  return ConvertOffsetToIndex(ContextLocalInfosOffset());
1039 1040
}

1041
int ScopeInfo::SavedClassVariableInfoIndex() const {
1042
  return ConvertOffsetToIndex(SavedClassVariableInfoOffset());
1043 1044
}

1045 1046
int ScopeInfo::FunctionVariableInfoIndex() const {
  return ConvertOffsetToIndex(FunctionVariableInfoOffset());
1047 1048
}

1049
int ScopeInfo::InferredFunctionNameIndex() const {
1050
  return ConvertOffsetToIndex(InferredFunctionNameOffset());
1051 1052
}

1053
int ScopeInfo::PositionInfoIndex() const {
1054
  return ConvertOffsetToIndex(PositionInfoOffset());
1055 1056
}

1057
int ScopeInfo::OuterScopeInfoIndex() const {
1058
  return ConvertOffsetToIndex(OuterScopeInfoOffset());
1059 1060
}

Dan Elphick's avatar
Dan Elphick committed
1061
int ScopeInfo::LocalsBlockListIndex() const {
1062
  return ConvertOffsetToIndex(LocalsBlockListOffset());
jochen's avatar
jochen committed
1063 1064
}

1065
int ScopeInfo::ModuleInfoIndex() const {
1066
  return ConvertOffsetToIndex(ModuleInfoOffset());
1067 1068
}

1069
int ScopeInfo::ModuleVariableCountIndex() const {
1070
  return ConvertOffsetToIndex(ModuleVariableCountOffset());
1071
}
1072

1073
int ScopeInfo::ModuleVariablesIndex() const {
1074
  return ConvertOffsetToIndex(ModuleVariablesOffset());
1075
}
1076

1077
void ScopeInfo::ModuleVariable(int i, String* name, int* index,
1078 1079 1080
                               VariableMode* mode,
                               InitializationFlag* init_flag,
                               MaybeAssignedFlag* maybe_assigned_flag) {
1081
  int properties = module_variables_properties(i);
1082 1083

  if (name != nullptr) {
1084
    *name = module_variables_name(i);
1085 1086
  }
  if (index != nullptr) {
1087
    *index = module_variables_index(i);
1088
    DCHECK_NE(*index, 0);
1089 1090
  }
  if (mode != nullptr) {
1091
    *mode = VariableModeBits::decode(properties);
1092 1093
  }
  if (init_flag != nullptr) {
1094
    *init_flag = InitFlagBit::decode(properties);
1095 1096
  }
  if (maybe_assigned_flag != nullptr) {
1097
    *maybe_assigned_flag = MaybeAssignedFlagBit::decode(properties);
1098 1099 1100
  }
}

1101
std::ostream& operator<<(std::ostream& os, VariableAllocationInfo var_info) {
1102
  switch (var_info) {
1103
    case VariableAllocationInfo::NONE:
1104
      return os << "NONE";
1105
    case VariableAllocationInfo::STACK:
1106
      return os << "STACK";
1107
    case VariableAllocationInfo::CONTEXT:
1108
      return os << "CONTEXT";
1109
    case VariableAllocationInfo::UNUSED:
1110 1111 1112 1113 1114
      return os << "UNUSED";
  }
  UNREACHABLE();
}

1115 1116
template <typename IsolateT>
Handle<ModuleRequest> ModuleRequest::New(IsolateT* isolate,
1117
                                         Handle<String> specifier,
1118 1119
                                         Handle<FixedArray> import_assertions,
                                         int position) {
1120 1121 1122 1123
  Handle<ModuleRequest> result = Handle<ModuleRequest>::cast(
      isolate->factory()->NewStruct(MODULE_REQUEST_TYPE, AllocationType::kOld));
  result->set_specifier(*specifier);
  result->set_import_assertions(*import_assertions);
1124
  result->set_position(position);
1125 1126 1127 1128 1129
  return result;
}

template Handle<ModuleRequest> ModuleRequest::New(
    Isolate* isolate, Handle<String> specifier,
1130
    Handle<FixedArray> import_assertions, int position);
1131 1132
template Handle<ModuleRequest> ModuleRequest::New(
    LocalIsolate* isolate, Handle<String> specifier,
1133
    Handle<FixedArray> import_assertions, int position);
1134

1135
template <typename IsolateT>
1136
Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New(
1137
    IsolateT* isolate, Handle<PrimitiveHeapObject> export_name,
1138 1139 1140 1141 1142 1143
    Handle<PrimitiveHeapObject> local_name,
    Handle<PrimitiveHeapObject> import_name, int module_request, int cell_index,
    int beg_pos, int end_pos) {
  Handle<SourceTextModuleInfoEntry> result =
      Handle<SourceTextModuleInfoEntry>::cast(isolate->factory()->NewStruct(
          SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, AllocationType::kOld));
1144 1145 1146 1147 1148 1149 1150
  result->set_export_name(*export_name);
  result->set_local_name(*local_name);
  result->set_import_name(*import_name);
  result->set_module_request(module_request);
  result->set_cell_index(cell_index);
  result->set_beg_pos(beg_pos);
  result->set_end_pos(end_pos);
1151 1152 1153
  return result;
}

1154 1155 1156 1157 1158
template Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New(
    Isolate* isolate, Handle<PrimitiveHeapObject> export_name,
    Handle<PrimitiveHeapObject> local_name,
    Handle<PrimitiveHeapObject> import_name, int module_request, int cell_index,
    int beg_pos, int end_pos);
1159
template Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New(
1160
    LocalIsolate* isolate, Handle<PrimitiveHeapObject> export_name,
1161 1162 1163 1164
    Handle<PrimitiveHeapObject> local_name,
    Handle<PrimitiveHeapObject> import_name, int module_request, int cell_index,
    int beg_pos, int end_pos);

1165
template <typename IsolateT>
1166
Handle<SourceTextModuleInfo> SourceTextModuleInfo::New(
1167
    IsolateT* isolate, Zone* zone, SourceTextModuleDescriptor* descr) {
1168
  // Serialize module requests.
1169
  int size = static_cast<int>(descr->module_requests().size());
1170 1171
  Handle<FixedArray> module_requests =
      isolate->factory()->NewFixedArray(size, AllocationType::kOld);
1172
  for (const auto& elem : descr->module_requests()) {
1173 1174
    Handle<ModuleRequest> serialized_module_request = elem->Serialize(isolate);
    module_requests->set(elem->index(), *serialized_module_request);
1175 1176
  }

1177
  // Serialize special exports.
1178
  Handle<FixedArray> special_exports = isolate->factory()->NewFixedArray(
1179
      static_cast<int>(descr->special_exports().size()), AllocationType::kOld);
1180 1181 1182
  {
    int i = 0;
    for (auto entry : descr->special_exports()) {
1183
      Handle<SourceTextModuleInfoEntry> serialized_entry =
1184
          entry->Serialize(isolate);
1185
      special_exports->set(i++, *serialized_entry);
1186 1187 1188
    }
  }

1189
  // Serialize namespace imports.
1190
  Handle<FixedArray> namespace_imports = isolate->factory()->NewFixedArray(
1191 1192
      static_cast<int>(descr->namespace_imports().size()),
      AllocationType::kOld);
1193 1194
  {
    int i = 0;
1195
    for (auto entry : descr->namespace_imports()) {
1196
      Handle<SourceTextModuleInfoEntry> serialized_entry =
1197
          entry->Serialize(isolate);
1198
      namespace_imports->set(i++, *serialized_entry);
1199 1200 1201
    }
  }

1202
  // Serialize regular exports.
1203
  Handle<FixedArray> regular_exports =
1204
      descr->SerializeRegularExports(isolate, zone);
1205

1206
  // Serialize regular imports.
1207
  Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray(
1208
      static_cast<int>(descr->regular_imports().size()), AllocationType::kOld);
1209 1210 1211
  {
    int i = 0;
    for (const auto& elem : descr->regular_imports()) {
1212
      Handle<SourceTextModuleInfoEntry> serialized_entry =
1213 1214
          elem.second->Serialize(isolate);
      regular_imports->set(i++, *serialized_entry);
1215 1216 1217
    }
  }

1218
  Handle<SourceTextModuleInfo> result =
1219
      isolate->factory()->NewSourceTextModuleInfo();
1220
  result->set(kModuleRequestsIndex, *module_requests);
1221 1222
  result->set(kSpecialExportsIndex, *special_exports);
  result->set(kRegularExportsIndex, *regular_exports);
1223
  result->set(kNamespaceImportsIndex, *namespace_imports);
1224
  result->set(kRegularImportsIndex, *regular_imports);
1225 1226
  return result;
}
1227 1228
template Handle<SourceTextModuleInfo> SourceTextModuleInfo::New(
    Isolate* isolate, Zone* zone, SourceTextModuleDescriptor* descr);
1229
template Handle<SourceTextModuleInfo> SourceTextModuleInfo::New(
1230
    LocalIsolate* isolate, Zone* zone, SourceTextModuleDescriptor* descr);
1231

1232
int SourceTextModuleInfo::RegularExportCount() const {
1233 1234
  DCHECK_EQ(regular_exports().length() % kRegularExportLength, 0);
  return regular_exports().length() / kRegularExportLength;
1235 1236
}

1237
String SourceTextModuleInfo::RegularExportLocalName(int i) const {
1238 1239
  return String::cast(regular_exports().get(i * kRegularExportLength +
                                            kRegularExportLocalNameOffset));
1240 1241
}

1242
int SourceTextModuleInfo::RegularExportCellIndex(int i) const {
1243 1244
  return Smi::ToInt(regular_exports().get(i * kRegularExportLength +
                                          kRegularExportCellIndexOffset));
1245 1246
}

1247
FixedArray SourceTextModuleInfo::RegularExportExportNames(int i) const {
1248
  return FixedArray::cast(regular_exports().get(
1249 1250 1251
      i * kRegularExportLength + kRegularExportExportNamesOffset));
}

1252 1253
}  // namespace internal
}  // namespace v8
1254 1255

#include "src/objects/object-macros-undef.h"