Flutter Engine
The Flutter Engine
scopes.h
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_SCOPES_H_
6#define RUNTIME_VM_SCOPES_H_
7
8#include <limits>
9
10#include "platform/assert.h"
11#include "platform/globals.h"
12#include "vm/allocation.h"
13#include "vm/growable_array.h"
14#include "vm/object.h"
15#include "vm/raw_object.h"
16#include "vm/symbols.h"
17#include "vm/token.h"
18
19namespace dart {
20
21class CompileType;
22class LocalScope;
23class Slot;
24
25// Indices of [LocalVariable]s are abstract and have little todo with the
26// actual frame layout!
27//
28// There are generally 4 different kinds of [LocalVariable]s:
29//
30// a) [LocalVariable]s referring to a parameter: The indices for those
31// variables are assigned by the flow graph builder. Parameter n gets
32// assigned the index (function.num_parameters - n - 1). I.e. the last
33// parameter has index 1.
34//
35// b) [LocalVariable]s referring to actual variables in the body of a
36// function (either from Dart code or specially injected ones. The
37// indices of those variables are assigned by the scope builder
38// from 0, -1, ... -(M-1) for M local variables.
39//
40// -> These variables participate in full SSA renaming and can therefore
41// be used with [StoreLocalInstr]s (in addition to [LoadLocal]s).
42//
43// c) [LocalVariable]s referring to values on the expression stack. Those are
44// assigned by the flow graph builder. The indices of those variables are
45// assigned by the flow graph builder (it simulates the expression stack
46// height), they go from -NumVariables - ExpressionHeight.
47//
48// -> These variables participate only partially in SSA renaming and can
49// therefore only be used with [LoadLocalInstr]s and with
50// [StoreLocalInstr]s **where no phis are necessary**.
51//
52// b) [LocalVariable]s referring to captured variables. Those are never
53// loaded/stored directly. Their only purpose is to tell the flow graph
54// builder how many parent links to follow and into which context index to
55// store. The indices of those variables are assigned by the scope
56// builder and they refer to indices into context objects.
58 public:
60
61 explicit VariableIndex(int value = kInvalidIndex) : value_(value) {}
62
63 bool operator==(const VariableIndex& other) const {
64 return value_ == other.value_;
65 }
66
67 bool IsValid() const { return value_ != kInvalidIndex; }
68
69 int value() const { return value_; }
70
71 private:
72 int value_;
73};
74
76 public:
77 static constexpr intptr_t kNoKernelOffset = -1;
78
79 LocalVariable(TokenPosition declaration_pos,
81 const String& name,
84
87 const String& name,
89 intptr_t kernel_offset,
92 const Object* inferred_arg_value = nullptr)
93 : declaration_pos_(declaration_pos),
94 token_pos_(token_pos),
95 name_(name),
96 kernel_offset_(kernel_offset),
97 annotations_offset_(kNoKernelOffset),
98 owner_(nullptr),
99 static_type_(static_type),
100 inferred_type_(inferred_type),
101 inferred_arg_type_(inferred_arg_type),
102 inferred_arg_value_(inferred_arg_value),
103 covariance_mode_(kNotCovariant),
104 late_init_offset_(0),
105 type_check_mode_(kDoTypeCheck),
106 index_(),
107 is_awaiter_link_(IsAwaiterLink::kNotLink) {
108 DEBUG_ASSERT(static_type.IsNotTemporaryScopedHandle());
110 ASSERT(inferred_type != nullptr);
112 if (IsFilteredIdentifier(name)) {
113 set_invisible(true);
114 }
115 }
116
117 TokenPosition token_pos() const { return token_pos_; }
118 TokenPosition declaration_token_pos() const { return declaration_pos_; }
119 const String& name() const { return name_; }
120 intptr_t kernel_offset() const { return kernel_offset_; }
121 intptr_t annotations_offset() const { return annotations_offset_; }
122 LocalScope* owner() const { return owner_; }
124 ASSERT(owner_ == nullptr);
125 owner_ = owner;
126 }
127
129 annotations_offset_ = offset;
130 is_awaiter_link_ = (offset == kNoKernelOffset) ? IsAwaiterLink::kNotLink
131 : IsAwaiterLink::kUnknown;
132 }
133
134 const AbstractType& static_type() const { return static_type_; }
135
136 CompileType* inferred_type() const { return inferred_type_; }
137 CompileType* inferred_arg_type() const { return inferred_arg_type_; }
138 const Object* inferred_arg_value() const { return inferred_arg_value_; }
139
140 bool is_final() const { return IsFinalBit::decode(bitfield_); }
141 void set_is_final() { bitfield_ = IsFinalBit::update(true, bitfield_); }
142
143 bool is_captured() const { return IsCapturedBit::decode(bitfield_); }
144 void set_is_captured() { bitfield_ = IsCapturedBit::update(true, bitfield_); }
145
146 bool ComputeIfIsAwaiterLink(const Library& library);
148 is_awaiter_link_ = value ? IsAwaiterLink::kLink : IsAwaiterLink::kNotLink;
149 }
150
151 // Variables marked as forced to stack are skipped and not captured by
152 // CaptureLocalVariables - which iterates scope chain between two scopes
153 // and indiscriminately marks all variables as captured.
154 // TODO(27590) remove the hardcoded list of names from CaptureLocalVariables
155 bool is_forced_stack() const { return IsForcedStackBit::decode(bitfield_); }
157 bitfield_ = IsForcedStackBit::update(true, bitfield_);
158 }
159
160 bool is_late() const { return IsLateBit::decode(bitfield_); }
161 void set_is_late() { bitfield_ = IsLateBit::update(true, bitfield_); }
162
163 intptr_t late_init_offset() const { return late_init_offset_; }
165 late_init_offset_ = late_init_offset;
166 }
167
169 return covariance_mode_ == kExplicit;
170 }
171 void set_is_explicit_covariant_parameter() { covariance_mode_ = kExplicit; }
172
174 return covariance_mode_ != kNotCovariant;
175 }
177 if (covariance_mode_ == kNotCovariant) {
178 covariance_mode_ = kImplicit;
179 }
180 }
181
186 };
187
188 // Returns true if this local variable represents a parameter that needs type
189 // check when we enter the function.
190 bool needs_type_check() const { return (type_check_mode_ == kDoTypeCheck); }
191
192 // Returns true if this local variable represents a parameter which type is
193 // guaranteed by the caller.
195 return type_check_mode_ == kTypeCheckedByCaller;
196 }
197
198 TypeCheckMode type_check_mode() const { return type_check_mode_; }
199 void set_type_check_mode(TypeCheckMode mode) { type_check_mode_ = mode; }
200
201 bool HasIndex() const { return index_.IsValid(); }
203 ASSERT(HasIndex());
204 return index_;
205 }
206
207 // Assign an index to a local.
210 index_ = index;
211 }
212
213 // Invisible variables are not included into LocalVarDescriptors
214 // and not displayed in the debugger.
215 bool is_invisible() const { return IsInvisibleBit::decode(bitfield_); }
216 void set_invisible(bool value) {
217 bitfield_ = IsInvisibleBit::update(value, bitfield_);
218 }
219
221 return IsCapturedParameterBit::decode(bitfield_);
222 }
224 bitfield_ = IsCapturedParameterBit::update(value, bitfield_);
225 }
226
227 bool Equals(const LocalVariable& other) const;
228
229 private:
230 // If true, this variable is readonly.
231 using IsFinalBit = BitField<uint32_t, bool, 0, 1>;
232 // If true, this variable lives in the context, otherwise
233 // in the stack frame.
236 using IsCapturedParameterBit =
238 using IsForcedStackBit =
241
242 enum CovarianceMode {
243 kNotCovariant,
244 kImplicit,
245 kExplicit,
246 };
247
248 static constexpr int kUninitializedIndex = INT_MIN;
249
250 static bool IsFilteredIdentifier(const String& name);
251
252 const TokenPosition declaration_pos_;
253 const TokenPosition token_pos_;
254 const String& name_;
255 const intptr_t kernel_offset_;
256 intptr_t annotations_offset_;
257 LocalScope* owner_; // Local scope declaring this variable.
258
259 const AbstractType& static_type_; // Declaration type of local variable.
260
261 // Inferred variable type.
262 CompileType* const inferred_type_;
263 // nullptr or inferred type of incoming argument.
264 CompileType* const inferred_arg_type_;
265 // nullptr or inferred value of incoming argument.
266 const Object* const inferred_arg_value_;
267
268 uint32_t bitfield_ = 0;
269 CovarianceMode covariance_mode_;
270 intptr_t late_init_offset_;
271 TypeCheckMode type_check_mode_;
272 VariableIndex index_;
273
274 enum class IsAwaiterLink {
275 kUnknown,
276 kNotLink,
277 kLink,
278 };
279 IsAwaiterLink is_awaiter_link_;
280
281 friend class LocalScope;
283};
284
285// Accumulates local variable descriptors while building
286// LocalVarDescriptors object.
288 public:
289 struct VarDesc {
290 const String* name;
292 };
293
295
296 // Add variable descriptor.
297 void Add(const VarDesc& var_desc) { vars_.Add(var_desc); }
298
299 // Add all variable descriptors from given [LocalVarDescriptors] object.
300 void AddAll(Zone* zone, const LocalVarDescriptors& var_descs);
301
302 // Record deopt-id -> context-level mappings, using ranges of deopt-ids with
303 // the same context-level. [context_level_array] contains (deopt_id,
304 // context_level) tuples.
306 ZoneGrowableArray<intptr_t>* context_level_array);
307
308 // Finish building LocalVarDescriptor object.
309 LocalVarDescriptorsPtr Done();
310
311 private:
313};
314
315class LocalScope : public ZoneAllocated {
316 public:
318
319 LocalScope* parent() const { return parent_; }
320 LocalScope* child() const { return child_; }
321 LocalScope* sibling() const { return sibling_; }
322 int function_level() const { return function_level_; }
323 int loop_level() const { return loop_level_; }
324
325 // Check if this scope is nested within the passed in scope.
326 bool IsNestedWithin(LocalScope* scope) const;
327
328 // The context level is only set in a scope that is either the owner scope of
329 // a captured variable or that is the owner scope of a context.
330 bool HasContextLevel() const {
331 return context_level_ != kUninitializedContextLevel;
332 }
333 int context_level() const {
335 return context_level_;
336 }
339 ASSERT(context_level != kUninitializedContextLevel);
340 context_level_ = context_level;
341 }
342
343 TokenPosition begin_token_pos() const { return begin_token_pos_; }
344 void set_begin_token_pos(TokenPosition value) { begin_token_pos_ = value; }
345
346 TokenPosition end_token_pos() const { return end_token_pos_; }
347 void set_end_token_pos(TokenPosition value) { end_token_pos_ = value; }
348
349 // Return the list of variables allocated in the context and belonging to this
350 // scope and to its children at the same loop level.
352 return context_variables_;
353 }
354
356 return *context_slots_;
357 }
358
359 // The number of variables allocated in the context and belonging to this
360 // scope and to its children at the same loop level.
361 int num_context_variables() const { return context_variables().length(); }
362
363 // Add a variable to the scope. Returns false if a variable with the
364 // same name and kernel offset is already present.
365 bool AddVariable(LocalVariable* variable);
366
367 // Add a variable to the scope as a context allocated variable and assigns
368 // it an index within the context. Does not check if the scope already
369 // contains this variable or a variable with the same name.
371
372 // Insert a formal parameter variable to the scope at the given position,
373 // possibly in front of aliases already added with AddVariable.
374 // Returns false if a variable with the same name is already present.
375 bool InsertParameterAt(intptr_t pos, LocalVariable* parameter);
376
377 // Lookup a variable in this scope only.
379 intptr_t kernel_offset) const;
380
381 // Lookup a variable in this scope and its parents. If the variable
382 // is found in a parent scope and 'test_only' is not true, we insert
383 // aliases of the variable in the current and intermediate scopes up to
384 // the declaration scope in order to detect "used before declared" errors.
385 // We mark a variable as 'captured' when applicable.
387 intptr_t kernel_offset,
388 bool test_only);
389
390 // Lookup a variable in this scope and its parents by name.
392
393 // Mark this variable as captured by this scope.
394 void CaptureVariable(LocalVariable* variable);
395
396 // Accessing the variables in the scope.
397 intptr_t num_variables() const { return variables_.length(); }
398 LocalVariable* VariableAt(intptr_t index) const {
399 ASSERT((index >= 0) && (index < variables_.length()));
400 return variables_[index];
401 }
402
403 // Count the captured variables belonging to outer scopes and referenced in
404 // this local scope.
405 int NumCapturedVariables() const;
406
407 // Allocate both captured and non-captured variables declared in this scope
408 // and in its children scopes of the same function level. Allocating means
409 // assigning a frame slot index or a context slot index.
410 // Parameters to be allocated in the frame must all appear in the top scope
411 // and not in its children (we do not yet handle register parameters).
412 // Locals must be listed after parameters in top scope and in its children.
413 // Two locals in different sibling scopes may share the same frame slot.
414 //
415 // Return the index of the next available frame slot.
417 VariableIndex first_parameter_index,
418 int num_parameters,
419 VariableIndex first_local_index,
420 LocalScope* context_owner,
421 bool* found_captured_variables);
422
423 // Creates variable info for the scope and all its nested scopes.
424 // Must be called after AllocateVariables() has been called.
425 LocalVarDescriptorsPtr GetVarDescriptors(
426 const Function& func,
427 ZoneGrowableArray<intptr_t>* context_level_array);
428
429 // Create a ContextScope object describing all captured variables referenced
430 // from this scope and belonging to outer scopes.
431 ContextScopePtr PreserveOuterScope(const Function& function,
432 intptr_t current_context_level) const;
433
434 // Mark all local variables that are accessible from this scope up to
435 // top_scope (included) as captured unless they are marked as forced to stack.
436 void CaptureLocalVariables(LocalScope* top_scope);
437
438 // Creates a LocalScope representing the outer scope of a local function to be
439 // compiled. This outer scope contains the variables captured by the function
440 // as specified by the given ContextScope, which was created during the
441 // compilation of the enclosing function.
442 static LocalScope* RestoreOuterScope(const ContextScope& context_scope);
443
444 // Create a ContextScope object which will capture "this" for an implicit
445 // closure object.
446 static ContextScopePtr CreateImplicitClosureScope(const Function& func);
447
448 private:
449 // Allocate the variable in the current context, possibly updating the current
450 // context owner scope, if the variable is the first one to be allocated at
451 // this loop level.
452 // The variable may belong to this scope or to any of its children, but at the
453 // same loop level.
454 void AllocateContextVariable(LocalVariable* variable,
455 LocalScope** context_owner);
456
457 void CollectLocalVariables(LocalVarDescriptorsBuilder* vars,
458 int16_t* scope_id);
459
460 static constexpr int kUninitializedContextLevel = INT_MIN;
461 LocalScope* parent_;
462 LocalScope* child_;
463 LocalScope* sibling_;
464 int function_level_; // Reflects the nesting level of local functions.
465 int loop_level_; // Reflects the loop nesting level.
466 int context_level_; // Reflects the level of the runtime context.
467 TokenPosition begin_token_pos_; // Token index of beginning of scope.
468 TokenPosition end_token_pos_; // Token index of end of scope.
470
471 // List of variables allocated into the context which is owned by this scope,
472 // and their corresponding Slots.
473 GrowableArray<LocalVariable*> context_variables_;
474 ZoneGrowableArray<const Slot*>* context_slots_;
475
476 DISALLOW_COPY_AND_ASSIGN(LocalScope);
477};
478
479} // namespace dart
480
481#endif // RUNTIME_VM_SCOPES_H_
SkPoint pos
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
bool IsFinalized() const
Definition: object.h:9053
static constexpr T decode(S value)
Definition: bitfield.h:171
static constexpr S update(T value, S original)
Definition: bitfield.h:188
int context_level() const
Definition: scopes.h:333
LocalScope * parent() const
Definition: scopes.h:319
LocalScope(LocalScope *parent, int function_level, int loop_level)
Definition: scopes.cc:24
const GrowableArray< LocalVariable * > & context_variables() const
Definition: scopes.h:351
const ZoneGrowableArray< const Slot * > & context_slots() const
Definition: scopes.h:355
void set_begin_token_pos(TokenPosition value)
Definition: scopes.h:344
bool IsNestedWithin(LocalScope *scope) const
Definition: scopes.cc:46
void set_end_token_pos(TokenPosition value)
Definition: scopes.h:347
int loop_level() const
Definition: scopes.h:323
TokenPosition end_token_pos() const
Definition: scopes.h:346
LocalScope * sibling() const
Definition: scopes.h:321
static ContextScopePtr CreateImplicitClosureScope(const Function &func)
Definition: scopes.cc:580
int NumCapturedVariables() const
Definition: scopes.cc:409
int function_level() const
Definition: scopes.h:322
static LocalScope * RestoreOuterScope(const ContextScope &context_scope)
Definition: scopes.cc:518
VariableIndex AllocateVariables(const Function &function, VariableIndex first_parameter_index, int num_parameters, VariableIndex first_local_index, LocalScope *context_owner, bool *found_captured_variables)
Definition: scopes.cc:133
LocalVarDescriptorsPtr GetVarDescriptors(const Function &func, ZoneGrowableArray< intptr_t > *context_level_array)
Definition: scopes.cc:249
LocalVariable * LookupVariableByName(const String &name)
Definition: scopes.cc:369
LocalVariable * VariableAt(intptr_t index) const
Definition: scopes.h:398
intptr_t num_variables() const
Definition: scopes.h:397
bool HasContextLevel() const
Definition: scopes.h:330
TokenPosition begin_token_pos() const
Definition: scopes.h:343
LocalVariable * LookupVariable(const String &name, intptr_t kernel_offset, bool test_only)
Definition: scopes.cc:350
bool AddVariable(LocalVariable *variable)
Definition: scopes.cc:57
LocalScope * child() const
Definition: scopes.h:320
void CaptureVariable(LocalVariable *variable)
Definition: scopes.cc:383
bool InsertParameterAt(intptr_t pos, LocalVariable *parameter)
Definition: scopes.cc:72
int num_context_variables() const
Definition: scopes.h:361
ContextScopePtr PreserveOuterScope(const Function &function, intptr_t current_context_level) const
Definition: scopes.cc:433
LocalVariable * LocalLookupVariable(const String &name, intptr_t kernel_offset) const
Definition: scopes.cc:336
void set_context_level(int context_level)
Definition: scopes.h:337
void AddContextVariable(LocalVariable *var)
Definition: scopes.cc:126
void CaptureLocalVariables(LocalScope *top_scope)
Definition: scopes.cc:558
void AddAll(Zone *zone, const LocalVarDescriptors &var_descs)
Definition: scopes.cc:631
LocalVarDescriptorsPtr Done()
Definition: scopes.cc:676
void Add(const VarDesc &var_desc)
Definition: scopes.h:297
void AddDeoptIdToContextLevelMappings(ZoneGrowableArray< intptr_t > *context_level_array)
Definition: scopes.cc:641
bool is_late() const
Definition: scopes.h:160
CompileType * inferred_type() const
Definition: scopes.h:136
VariableIndex index() const
Definition: scopes.h:202
void set_needs_covariant_check_in_method()
Definition: scopes.h:176
void set_late_init_offset(intptr_t late_init_offset)
Definition: scopes.h:164
LocalScope * owner() const
Definition: scopes.h:122
bool HasIndex() const
Definition: scopes.h:201
bool ComputeIfIsAwaiterLink(const Library &library)
Definition: scopes.cc:603
intptr_t annotations_offset() const
Definition: scopes.h:121
void set_is_captured()
Definition: scopes.h:144
bool is_captured() const
Definition: scopes.h:143
LocalVariable(TokenPosition declaration_pos, TokenPosition token_pos, const String &name, const AbstractType &static_type, intptr_t kernel_offset, CompileType *inferred_type, CompileType *inferred_arg_type=nullptr, const Object *inferred_arg_value=nullptr)
Definition: scopes.h:85
void set_is_late()
Definition: scopes.h:161
void set_is_explicit_covariant_parameter()
Definition: scopes.h:171
bool is_forced_stack() const
Definition: scopes.h:155
void set_type_check_mode(TypeCheckMode mode)
Definition: scopes.h:199
TokenPosition declaration_token_pos() const
Definition: scopes.h:118
void set_is_final()
Definition: scopes.h:141
TokenPosition token_pos() const
Definition: scopes.h:117
void set_index(VariableIndex index)
Definition: scopes.h:208
void set_invisible(bool value)
Definition: scopes.h:216
bool is_invisible() const
Definition: scopes.h:215
TypeCheckMode type_check_mode() const
Definition: scopes.h:198
const Object * inferred_arg_value() const
Definition: scopes.h:138
void set_annotations_offset(intptr_t offset)
Definition: scopes.h:128
bool needs_type_check() const
Definition: scopes.h:190
const AbstractType & static_type() const
Definition: scopes.h:134
intptr_t kernel_offset() const
Definition: scopes.h:120
friend class LocalScope
Definition: scopes.h:281
bool Equals(const LocalVariable &other) const
Definition: scopes.cc:617
bool is_captured_parameter() const
Definition: scopes.h:220
static constexpr intptr_t kNoKernelOffset
Definition: scopes.h:77
intptr_t late_init_offset() const
Definition: scopes.h:163
const String & name() const
Definition: scopes.h:119
void set_is_forced_stack()
Definition: scopes.h:156
bool was_type_checked_by_caller() const
Definition: scopes.h:194
void set_is_captured_parameter(bool value)
Definition: scopes.h:223
void set_is_awaiter_link(bool value)
Definition: scopes.h:147
bool is_final() const
Definition: scopes.h:140
void set_owner(LocalScope *owner)
Definition: scopes.h:123
bool needs_covariant_check_in_method() const
Definition: scopes.h:173
LocalVariable(TokenPosition declaration_pos, TokenPosition token_pos, const String &name, const AbstractType &static_type, intptr_t kernel_offset=kNoKernelOffset)
Definition: scopes.cc:224
CompileType * inferred_arg_type() const
Definition: scopes.h:137
bool is_explicit_covariant_parameter() const
Definition: scopes.h:168
bool IsSymbol() const
Definition: object.h:10309
bool IsValid() const
Definition: scopes.h:67
static constexpr int kInvalidIndex
Definition: scopes.h:59
VariableIndex(int value=kInvalidIndex)
Definition: scopes.h:61
int value() const
Definition: scopes.h:69
bool operator==(const VariableIndex &other) const
Definition: scopes.h:63
#define ASSERT(E)
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float min(float r, float g, float b)
Definition: hsl.cpp:48
Definition: dart_vm.cc:33
const char *const name
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
Definition: __init__.py:1
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
SeparatedVector2 offset
UntaggedLocalVarDescriptors::VarInfo info
Definition: scopes.h:291