summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/scope-info.h
blob: 3fe5c2c5ad1fbea46006d2595620d0a907ef96fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_SCOPE_INFO_H_
#define V8_OBJECTS_SCOPE_INFO_H_

#include "src/common/globals.h"
#include "src/objects/fixed-array.h"
#include "src/objects/function-kind.h"
#include "src/objects/objects.h"
#include "src/utils/utils.h"
#include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck
#include "torque-generated/bit-fields.h"

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

namespace v8 {
namespace internal {

// scope-info-tq.inc uses NameToIndexHashTable.
class NameToIndexHashTable;

#include "torque-generated/src/objects/scope-info-tq.inc"

template <typename T>
class Handle;
class Isolate;
template <typename T>
class MaybeHandle;
class SourceTextModuleInfo;
class Scope;
class StringSet;
class Zone;

struct VariableLookupResult {
  int context_index;
  int slot_index;
  // repl_mode flag is needed to disable inlining of 'const' variables in REPL
  // mode.
  bool is_repl_mode;
  IsStaticFlag is_static_flag;
  VariableMode mode;
  InitializationFlag init_flag;
  MaybeAssignedFlag maybe_assigned_flag;
};

// ScopeInfo represents information about different scopes of a source
// program  and the allocation of the scope's variables. Scope information
// is stored in a compressed form in ScopeInfo objects and is used
// at runtime (stack dumps, deoptimization, etc.).

// This object provides quick access to scope info details for runtime
// routines.
class ScopeInfo : public TorqueGeneratedScopeInfo<ScopeInfo, HeapObject> {
 public:
  DEFINE_TORQUE_GENERATED_SCOPE_FLAGS()

  DECL_PRINTER(ScopeInfo)
  class BodyDescriptor;

  // Return the type of this scope.
  ScopeType scope_type() const;

  // Return the language mode of this scope.
  LanguageMode language_mode() const;

  // True if this scope is a (var) declaration scope.
  bool is_declaration_scope() const;

  // Does this scope make a sloppy eval call?
  bool SloppyEvalCanExtendVars() const;

  // Return the number of context slots for code if a context is allocated. This
  // number consists of three parts:
  //  1. Size of header for every context.
  //  2. One context slot per context allocated local.
  //  3. One context slot for the function name if it is context allocated.
  // Parameters allocated in the context count as context allocated locals. If
  // no contexts are allocated for this scope ContextLength returns 0.
  int ContextLength() const;
  int ContextHeaderLength() const;

  bool HasContextExtensionSlot() const;

  // Does this scope declare a "this" binding?
  bool HasReceiver() const;

  // Does this scope declare a "this" binding, and the "this" binding is stack-
  // or context-allocated?
  bool HasAllocatedReceiver() const;

  // Does this scope has class brand (for private methods)? If it's a class
  // scope, this indicates whether the class has a private brand. If it's a
  // constructor scope, this indicates whther it needs to initialize the
  // brand.
  bool ClassScopeHasPrivateBrand() const;

  // Does this scope contain a saved class variable for checking receivers of
  // static private methods?
  bool HasSavedClassVariable() const;

  // Does this scope declare a "new.target" binding?
  bool HasNewTarget() const;

  // Is this scope the scope of a named function expression?
  V8_EXPORT_PRIVATE bool HasFunctionName() const;

  bool HasContextAllocatedFunctionName() const;

  // See SharedFunctionInfo::HasSharedName.
  V8_EXPORT_PRIVATE bool HasSharedFunctionName() const;

  V8_EXPORT_PRIVATE bool HasInferredFunctionName() const;

  void SetFunctionName(Object name);
  void SetInferredFunctionName(String name);

  // Does this scope belong to a function?
  bool HasPositionInfo() const;

  // Return if contexts are allocated for this scope.
  bool HasContext() const;

  // Return if this is a function scope with "use asm".
  inline bool IsAsmModule() const;

  inline bool HasSimpleParameters() const;

  // Return the function_name if present.
  V8_EXPORT_PRIVATE Object FunctionName() const;

  // The function's name if it is non-empty, otherwise the inferred name or an
  // empty string.
  String FunctionDebugName() const;

  // Return the function's inferred name if present.
  // See SharedFunctionInfo::function_identifier.
  V8_EXPORT_PRIVATE Object InferredFunctionName() const;

  // Position information accessors.
  int StartPosition() const;
  int EndPosition() const;
  void SetPositionInfo(int start, int end);

  SourceTextModuleInfo ModuleDescriptorInfo() const;

  // Return true if the local names are inlined in the scope info object.
  inline bool HasInlinedLocalNames() const;

  template <typename ScopeInfoPtr>
  class LocalNamesRange;

  static inline LocalNamesRange<Handle<ScopeInfo>> IterateLocalNames(
      Handle<ScopeInfo> scope_info);

  static inline LocalNamesRange<ScopeInfo*> IterateLocalNames(
      ScopeInfo* scope_info, const DisallowGarbageCollection& no_gc);

  // Return the name of a given context local.
  // It should only be used if inlined local names.
  String ContextInlinedLocalName(int var) const;
  String ContextInlinedLocalName(PtrComprCageBase cage_base, int var) const;

  // Return the mode of the given context local.
  VariableMode ContextLocalMode(int var) const;

  // Return whether the given context local variable is static.
  IsStaticFlag ContextLocalIsStaticFlag(int var) const;

  // Return the initialization flag of the given context local.
  InitializationFlag ContextLocalInitFlag(int var) const;

  bool ContextLocalIsParameter(int var) const;
  uint32_t ContextLocalParameterNumber(int var) const;

  // Return the initialization flag of the given context local.
  MaybeAssignedFlag ContextLocalMaybeAssignedFlag(int var) const;

  // Return true if this local was introduced by the compiler, and should not be
  // exposed to the user in a debugger.
  static bool VariableIsSynthetic(String name);

  // Lookup support for serialized scope info. Returns the local context slot
  // index for a given slot name if the slot is present; otherwise
  // returns a value < 0. The name must be an internalized string.
  // If the slot is present and mode != nullptr, sets *mode to the corresponding
  // mode for that variable.
  int ContextSlotIndex(Handle<String> name);
  int ContextSlotIndex(Handle<String> name,
                       VariableLookupResult* lookup_result);

  // Lookup metadata of a MODULE-allocated variable.  Return 0 if there is no
  // module variable with the given name (the index value of a MODULE variable
  // is never 0).
  int ModuleIndex(String name, VariableMode* mode,
                  InitializationFlag* init_flag,
                  MaybeAssignedFlag* maybe_assigned_flag);

  int ModuleVariableCount() const;

  // Lookup support for serialized scope info. Returns the function context
  // slot index if the function name is present and context-allocated (named
  // function expressions, only), otherwise returns a value < 0. The name
  // must be an internalized string.
  int FunctionContextSlotIndex(String name) const;

  // Lookup support for serialized scope info.  Returns the receiver context
  // slot index if scope has a "this" binding, and the binding is
  // context-allocated.  Otherwise returns a value < 0.
  int ReceiverContextSlotIndex() const;

  // Returns the first parameter context slot index.
  int ParametersStartIndex() const;

  // Lookup support for serialized scope info.  Returns the name and index of
  // the saved class variable in context local slots if scope is a class scope
  // and it contains static private methods that may be accessed.
  std::pair<String, int> SavedClassVariable() const;

  FunctionKind function_kind() const;

  // Returns true if this ScopeInfo is linked to a outer ScopeInfo.
  bool HasOuterScopeInfo() const;

  // Returns true if this ScopeInfo was created for a debug-evaluate scope.
  bool IsDebugEvaluateScope() const;

  // Can be used to mark a ScopeInfo that looks like a with-scope as actually
  // being a debug-evaluate scope.
  void SetIsDebugEvaluateScope();

  // Return the outer ScopeInfo if present.
  ScopeInfo OuterScopeInfo() const;

  bool is_script_scope() const;

  // Returns true if this ScopeInfo has a blocklist attached containing stack
  // allocated local variables.
  V8_EXPORT_PRIVATE bool HasLocalsBlockList() const;
  // Returns a list of stack-allocated locals of parent scopes.
  // Used during local debug-evalute to decide whether a context lookup
  // can continue upwards after checking this scope.
  V8_EXPORT_PRIVATE StringSet LocalsBlockList() const;

  // Returns true if this ScopeInfo was created for a scope that skips the
  // closest outer class when resolving private names.
  bool PrivateNameLookupSkipsOuterClass() const;

  // REPL mode scopes allow re-declaraction of let and const variables. They
  // come from debug evaluate but are different to IsDebugEvaluateScope().
  bool IsReplModeScope() const;

#ifdef DEBUG
  // For LiveEdit we ignore:
  //   - position info: "unchanged" functions are allowed to move in a script
  //   - module info: SourceTextModuleInfo::Equals compares exact FixedArray
  //     addresses which will never match for separate instances.
  //   - outer scope info: LiveEdit already analyses outer scopes of unchanged
  //     functions. Also checking it here will break in really subtle cases
  //     e.g. changing a let to a const in an outer function, which is fine.
  bool Equals(ScopeInfo other, bool is_live_edit_compare = false) const;
#endif

  template <typename IsolateT>
  static Handle<ScopeInfo> Create(IsolateT* isolate, Zone* zone, Scope* scope,
                                  MaybeHandle<ScopeInfo> outer_scope);
  V8_EXPORT_PRIVATE static Handle<ScopeInfo> CreateForWithScope(
      Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
  V8_EXPORT_PRIVATE static Handle<ScopeInfo> CreateForEmptyFunction(
      Isolate* isolate);
  static Handle<ScopeInfo> CreateForNativeContext(Isolate* isolate);
  static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);

  // Creates a copy of a {ScopeInfo} but with the provided locals blocklist
  // attached. Does nothing if the original {ScopeInfo} already has a field
  // for a blocklist reserved.
  V8_EXPORT_PRIVATE static Handle<ScopeInfo> RecreateWithBlockList(
      Isolate* isolate, Handle<ScopeInfo> original,
      Handle<StringSet> blocklist);

  // Serializes empty scope info.
  V8_EXPORT_PRIVATE static ScopeInfo Empty(Isolate* isolate);

#define FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(V) \
  V(Flags)                                   \
  V(ParameterCount)                          \
  V(ContextLocalCount)

#define FIELD_ACCESSORS(name)       \
  inline int name() const;
  FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(FIELD_ACCESSORS)
#undef FIELD_ACCESSORS

  enum Fields {
#define DECL_INDEX(name) k##name,
    FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(DECL_INDEX)
#undef DECL_INDEX
        kVariablePartIndex
  };

  static_assert(LanguageModeSize == 1 << LanguageModeBit::kSize);
  static_assert(FunctionKind::kLastFunctionKind <= FunctionKindBits::kMax);

  bool IsEmpty() const;

  // Returns the size in bytes for a ScopeInfo with |length| slots.
  static constexpr int SizeFor(int length) { return OffsetOfElementAt(length); }

  // Gives access to raw memory which stores the ScopeInfo's data.
  inline ObjectSlot data_start();

  // Hash based on position info and flags. Falls back to flags + local count.
  V8_EXPORT_PRIVATE uint32_t Hash();

 private:
  friend class WebSnapshotDeserializer;

  int InlinedLocalNamesLookup(String name);

  int ContextLocalNamesIndex() const;
  int ContextLocalInfosIndex() const;
  int SavedClassVariableInfoIndex() const;
  int FunctionVariableInfoIndex() const;
  int InferredFunctionNameIndex() const;
  int PositionInfoIndex() const;
  int OuterScopeInfoIndex() const;
  V8_EXPORT_PRIVATE int LocalsBlockListIndex() const;
  int ModuleInfoIndex() const;
  int ModuleVariableCountIndex() const;
  int ModuleVariablesIndex() const;

  static bool NeedsPositionInfo(ScopeType type);

  // Raw access by slot index. These functions rely on the fact that everything
  // in ScopeInfo is tagged. Each slot is tagged-pointer sized. Slot 0 is
  // 'flags', the first field defined by ScopeInfo after the standard-size
  // HeapObject header.
  V8_EXPORT_PRIVATE Object get(int index) const;
  Object get(PtrComprCageBase cage_base, int index) const;
  // Setter that doesn't need write barrier.
  void set(int index, Smi value);
  // Setter with explicit barrier mode.
  void set(int index, Object value,
           WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
  void CopyElements(Isolate* isolate, int dst_index, ScopeInfo src,
                    int src_index, int len, WriteBarrierMode mode);
  ObjectSlot RawFieldOfElementAt(int index);
  // The number of tagged-pointer-sized slots in the ScopeInfo after its
  // standard HeapObject header.
  V8_EXPORT_PRIVATE int length() const;

  // Conversions between offset (bytes from the beginning of the object) and
  // index (number of tagged-pointer-sized slots starting after the standard
  // HeapObject header).
  static constexpr int OffsetOfElementAt(int index) {
    return HeapObject::kHeaderSize + index * kTaggedSize;
  }
  static constexpr int ConvertOffsetToIndex(int offset) {
    int index = (offset - HeapObject::kHeaderSize) / kTaggedSize;
    DCHECK_EQ(OffsetOfElementAt(index), offset);
    return index;
  }

  enum class BootstrappingType { kScript, kFunction, kNative };
  static Handle<ScopeInfo> CreateForBootstrapping(Isolate* isolate,
                                                  BootstrappingType type);

  int Lookup(Handle<String> name, int start, int end, VariableMode* mode,
             VariableLocation* location, InitializationFlag* init_flag,
             MaybeAssignedFlag* maybe_assigned_flag);

  // Get metadata of i-th MODULE-allocated variable, where 0 <= i <
  // ModuleVariableCount.  The metadata is returned via out-arguments, which may
  // be nullptr if the corresponding information is not requested
  void ModuleVariable(int i, String* name, int* index,
                      VariableMode* mode = nullptr,
                      InitializationFlag* init_flag = nullptr,
                      MaybeAssignedFlag* maybe_assigned_flag = nullptr);

  static const int kFunctionNameEntries =
      TorqueGeneratedFunctionVariableInfoOffsets::kSize / kTaggedSize;
  static const int kPositionInfoEntries =
      TorqueGeneratedPositionInfoOffsets::kSize / kTaggedSize;
  static const int kModuleVariableEntryLength =
      TorqueGeneratedModuleVariableOffsets::kSize / kTaggedSize;

  // Properties of variables.
  DEFINE_TORQUE_GENERATED_VARIABLE_PROPERTIES()

  friend class ScopeIterator;
  friend std::ostream& operator<<(std::ostream& os, VariableAllocationInfo var);

  TQ_OBJECT_CONSTRUCTORS(ScopeInfo)
  FRIEND_TEST(TestWithNativeContext, RecreateScopeInfoWithLocalsBlocklistWorks);
};

std::ostream& operator<<(std::ostream& os, VariableAllocationInfo var);

}  // namespace internal
}  // namespace v8

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

#endif  // V8_OBJECTS_SCOPE_INFO_H_