1// Copyright (c) 2018, 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#include "vm/compiler/frontend/scope_builder.h"
6
7#include "vm/compiler/backend/il.h" // For CompileType.
8#include "vm/compiler/frontend/kernel_translation_helper.h"
9
10namespace dart {
11namespace kernel {
12
13#define Z (zone_)
14#define H (translation_helper_)
15#define T (type_translator_)
16#define I Isolate::Current()
17
18// Returns true if the given method can skip type checks for all arguments
19// that are not covariant or generic covariant in its implementation.
20bool MethodCanSkipTypeChecksForNonCovariantArguments(
21 const Function& method,
22 const ProcedureAttributesMetadata& attrs) {
23 // Dart 2 type system at non-dynamic call sites statically guarantees that
24 // argument values match declarated parameter types for all non-covariant
25 // and non-generic-covariant parameters. The same applies to type parameters
26 // bounds for type parameters of generic functions.
27 //
28 // Normally dynamic call sites will call dyn:* forwarders which perform type
29 // checks.
30 //
31 // Though for some kinds of methods (e.g. ffi trampolines called from native
32 // code) we do have to perform type checks for all parameters.
33 return !method.CanReceiveDynamicInvocation();
34}
35
36ScopeBuilder::ScopeBuilder(ParsedFunction* parsed_function)
37 : result_(NULL),
38 parsed_function_(parsed_function),
39 translation_helper_(Thread::Current()),
40 zone_(translation_helper_.zone()),
41 current_function_scope_(NULL),
42 scope_(NULL),
43 depth_(0),
44 name_index_(0),
45 needs_expr_temp_(false),
46 helper_(
47 zone_,
48 &translation_helper_,
49 Script::Handle(Z, parsed_function->function().script()),
50 ExternalTypedData::Handle(Z,
51 parsed_function->function().KernelData()),
52 parsed_function->function().KernelDataProgramOffset()),
53 constant_reader_(&helper_, &active_class_),
54 inferred_type_metadata_helper_(&helper_, &constant_reader_),
55 procedure_attributes_metadata_helper_(&helper_),
56 type_translator_(&helper_,
57 &constant_reader_,
58 &active_class_,
59 /*finalize=*/true) {
60 H.InitFromScript(helper_.script());
61 ASSERT(type_translator_.active_class_ == &active_class_);
62}
63
64ScopeBuildingResult* ScopeBuilder::BuildScopes() {
65 if (result_ != NULL) return result_;
66
67 ASSERT(scope_ == NULL && depth_.loop_ == 0 && depth_.function_ == 0);
68 result_ = new (Z) ScopeBuildingResult();
69
70 const Function& function = parsed_function_->function();
71
72 // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
73 // e.g. for type translation.
74 const Class& klass = Class::Handle(zone_, function.Owner());
75
76 Function& outermost_function =
77 Function::Handle(Z, function.GetOutermostFunction());
78
79 ActiveClassScope active_class_scope(&active_class_, &klass);
80 ActiveMemberScope active_member(&active_class_, &outermost_function);
81 ActiveTypeParametersScope active_type_params(&active_class_, function, Z);
82
83 LocalScope* enclosing_scope = NULL;
84 if (function.IsImplicitClosureFunction() && !function.is_static()) {
85 // Create artificial enclosing scope for the tear-off that contains
86 // captured receiver value. This ensure that AssertAssignable will correctly
87 // load instantiator type arguments if they are needed.
88 Class& klass = Class::Handle(Z, function.Owner());
89 Type& klass_type = H.GetDeclarationType(klass);
90 LocalVariable* receiver_variable =
91 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
92 Symbols::This(), klass_type);
93 parsed_function_->set_receiver_var(receiver_variable);
94 receiver_variable->set_is_captured();
95 enclosing_scope = new (Z) LocalScope(NULL, 0, 0);
96 enclosing_scope->set_context_level(0);
97 enclosing_scope->AddVariable(receiver_variable);
98 enclosing_scope->AddContextVariable(receiver_variable);
99 } else if (function.IsLocalFunction()) {
100 enclosing_scope = LocalScope::RestoreOuterScope(
101 ContextScope::Handle(Z, function.context_scope()));
102 }
103 current_function_scope_ = scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
104 scope_->set_begin_token_pos(function.token_pos());
105 scope_->set_end_token_pos(function.end_token_pos());
106
107 // Add function type arguments variable before current context variable.
108 if ((function.IsGeneric() || function.HasGenericParent())) {
109 LocalVariable* type_args_var = MakeVariable(
110 TokenPosition::kNoSource, TokenPosition::kNoSource,
111 Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type());
112 scope_->AddVariable(type_args_var);
113 parsed_function_->set_function_type_arguments(type_args_var);
114 }
115
116 if (parsed_function_->has_arg_desc_var()) {
117 needs_expr_temp_ = true;
118 scope_->AddVariable(parsed_function_->arg_desc_var());
119 }
120
121 if (parsed_function_->function().IsFfiTrampoline()) {
122 needs_expr_temp_ = true;
123 }
124
125 LocalVariable* context_var = parsed_function_->current_context_var();
126 context_var->set_is_forced_stack();
127 scope_->AddVariable(context_var);
128
129 parsed_function_->set_scope(scope_);
130
131 helper_.SetOffset(function.kernel_offset());
132
133 FunctionNodeHelper function_node_helper(&helper_);
134 const ProcedureAttributesMetadata attrs =
135 procedure_attributes_metadata_helper_.GetProcedureAttributes(
136 function.kernel_offset());
137
138 switch (function.kind()) {
139 case FunctionLayout::kClosureFunction:
140 case FunctionLayout::kImplicitClosureFunction:
141 case FunctionLayout::kRegularFunction:
142 case FunctionLayout::kGetterFunction:
143 case FunctionLayout::kSetterFunction:
144 case FunctionLayout::kConstructor: {
145 const Tag tag = helper_.PeekTag();
146 helper_.ReadUntilFunctionNode();
147 function_node_helper.ReadUntilExcluding(
148 FunctionNodeHelper::kPositionalParameters);
149 current_function_async_marker_ = function_node_helper.async_marker_;
150 // NOTE: FunctionNode is read further below the if.
151
152 intptr_t pos = 0;
153 if (function.IsClosureFunction()) {
154 LocalVariable* closure_parameter = MakeVariable(
155 TokenPosition::kNoSource, TokenPosition::kNoSource,
156 Symbols::ClosureParameter(), AbstractType::dynamic_type());
157 closure_parameter->set_is_forced_stack();
158 scope_->InsertParameterAt(pos++, closure_parameter);
159 } else if (!function.is_static()) {
160 // We use [is_static] instead of [IsStaticFunction] because the latter
161 // returns `false` for constructors.
162 Class& klass = Class::Handle(Z, function.Owner());
163 Type& klass_type = H.GetDeclarationType(klass);
164 LocalVariable* variable =
165 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
166 Symbols::This(), klass_type);
167 scope_->InsertParameterAt(pos++, variable);
168 parsed_function_->set_receiver_var(variable);
169
170 // We visit instance field initializers because they might contain
171 // [Let] expressions and we need to have a mapping.
172 if (tag == kConstructor) {
173 Class& parent_class = Class::Handle(Z, function.Owner());
174 Array& class_fields = Array::Handle(Z, parent_class.fields());
175 Field& class_field = Field::Handle(Z);
176 for (intptr_t i = 0; i < class_fields.Length(); ++i) {
177 class_field ^= class_fields.At(i);
178 if (!class_field.is_static()) {
179 ExternalTypedData& kernel_data =
180 ExternalTypedData::Handle(Z, class_field.KernelData());
181 ASSERT(!kernel_data.IsNull());
182 intptr_t field_offset = class_field.kernel_offset();
183 AlternativeReadingScopeWithNewData alt(
184 &helper_.reader_, &kernel_data, field_offset);
185 FieldHelper field_helper(&helper_);
186 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
187 Tag initializer_tag =
188 helper_.ReadTag(); // read first part of initializer.
189 if (initializer_tag == kSomething) {
190 EnterScope(field_offset);
191 VisitExpression(); // read initializer.
192 ExitScope(field_helper.position_, field_helper.end_position_);
193 }
194 }
195 }
196 }
197 } else if (function.IsFactory()) {
198 LocalVariable* variable = MakeVariable(
199 TokenPosition::kNoSource, TokenPosition::kNoSource,
200 Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type());
201 scope_->InsertParameterAt(pos++, variable);
202 result_->type_arguments_variable = variable;
203 }
204
205 ParameterTypeCheckMode type_check_mode = kTypeCheckAllParameters;
206 if (function.IsSyncYielding()) {
207 // Don't type check the parameter of sync-yielding since these calls are
208 // all synthetic and types should always match.
209 ASSERT((function.NumParameters() - function.NumImplicitParameters()) ==
210 1);
211 ASSERT(
212 Class::Handle(
213 AbstractType::Handle(function.ParameterTypeAt(1)).type_class())
214 .Name() == Symbols::_SyncIterator().raw());
215 type_check_mode = kTypeCheckForStaticFunction;
216 } else if (function.IsNonImplicitClosureFunction()) {
217 type_check_mode = kTypeCheckAllParameters;
218 } else if (function.IsImplicitClosureFunction()) {
219 if (MethodCanSkipTypeChecksForNonCovariantArguments(
220 Function::Handle(Z, function.parent_function()), attrs)) {
221 // This is a tear-off of an instance method that can not be reached
222 // from any dynamic invocation. The method would not check any
223 // parameters except covariant ones and those annotated with
224 // generic-covariant-impl. Which means that we have to check
225 // the rest in the tear-off itself.
226 type_check_mode =
227 kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod;
228 }
229 } else {
230 if (function.is_static()) {
231 // In static functions we don't check anything.
232 type_check_mode = kTypeCheckForStaticFunction;
233 } else if (MethodCanSkipTypeChecksForNonCovariantArguments(function,
234 attrs)) {
235 // If the current function is never a target of a dynamic invocation
236 // and this parameter is not marked with generic-covariant-impl
237 // (which means that among all super-interfaces no type parameters
238 // ever occur at the position of this parameter) then we don't need
239 // to check this parameter on the callee side, because strong mode
240 // guarantees that it was checked at the caller side.
241 type_check_mode = kTypeCheckForNonDynamicallyInvokedMethod;
242 }
243 }
244
245 // Continue reading FunctionNode:
246 // read positional_parameters and named_parameters.
247 AddPositionalAndNamedParameters(pos, type_check_mode, attrs);
248
249 // We generate a synthetic body for implicit closure functions - which
250 // will forward the call to the real function.
251 // -> see BuildGraphOfImplicitClosureFunction
252 if (!function.IsImplicitClosureFunction()) {
253 helper_.SetOffset(function.kernel_offset());
254 first_body_token_position_ = TokenPosition::kNoSource;
255 VisitNode();
256
257 // TODO(jensj): HACK: Push the begin token to after any parameters to
258 // avoid crash when breaking on definition line of async method in
259 // debugger. It seems that another scope needs to be added
260 // in which captures are made, but I can't make that work.
261 // This 'solution' doesn't crash, but I cannot see the parameters at
262 // that particular breakpoint either.
263 // Also push the end token to after the "}" to avoid crashing on
264 // stepping past the last line (to the "}" character).
265 if (first_body_token_position_.IsReal()) {
266 scope_->set_begin_token_pos(first_body_token_position_);
267 }
268 if (scope_->end_token_pos().IsReal()) {
269 scope_->set_end_token_pos(scope_->end_token_pos().Next());
270 }
271 }
272 break;
273 }
274 case FunctionLayout::kImplicitGetter:
275 case FunctionLayout::kImplicitSetter: {
276 ASSERT(helper_.PeekTag() == kField);
277 const bool is_setter = function.IsImplicitSetterFunction();
278 const bool is_method = !function.IsStaticFunction();
279 const auto& field = Field::Handle(Z, function.accessor_field());
280 intptr_t pos = 0;
281 if (is_method) {
282 Class& klass = Class::Handle(Z, function.Owner());
283 Type& klass_type = H.GetDeclarationType(klass);
284 LocalVariable* variable =
285 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
286 Symbols::This(), klass_type);
287 scope_->InsertParameterAt(pos++, variable);
288 parsed_function_->set_receiver_var(variable);
289 }
290 if (is_setter) {
291 if (CompilerState::Current().is_aot()) {
292 const intptr_t kernel_offset = field.kernel_offset();
293 const InferredTypeMetadata parameter_type =
294 inferred_type_metadata_helper_.GetInferredType(kernel_offset);
295 result_->setter_value = MakeVariable(
296 TokenPosition::kNoSource, TokenPosition::kNoSource,
297 Symbols::Value(),
298 AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)),
299 &parameter_type);
300 } else {
301 result_->setter_value = MakeVariable(
302 TokenPosition::kNoSource, TokenPosition::kNoSource,
303 Symbols::Value(),
304 AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)));
305 }
306 scope_->InsertParameterAt(pos++, result_->setter_value);
307
308 if (is_method &&
309 MethodCanSkipTypeChecksForNonCovariantArguments(function, attrs)) {
310 if (field.is_covariant()) {
311 result_->setter_value->set_is_explicit_covariant_parameter();
312 } else if (!field.is_generic_covariant_impl() ||
313 (!attrs.has_non_this_uses && !attrs.has_tearoff_uses)) {
314 result_->setter_value->set_type_check_mode(
315 LocalVariable::kTypeCheckedByCaller);
316 }
317 }
318 }
319 break;
320 }
321 case FunctionLayout::kImplicitStaticGetter: {
322 ASSERT(helper_.PeekTag() == kField);
323 ASSERT(function.IsStaticFunction());
324 // In addition to static field initializers, scopes/local variables
325 // are needed for implicit getters of static const fields, in order to
326 // be able to evaluate their initializers in constant evaluator.
327 if (Field::Handle(Z, function.accessor_field()).is_const()) {
328 VisitNode();
329 }
330 break;
331 }
332 case FunctionLayout::kFieldInitializer: {
333 ASSERT(helper_.PeekTag() == kField);
334 if (!function.is_static()) {
335 Class& klass = Class::Handle(Z, function.Owner());
336 Type& klass_type = H.GetDeclarationType(klass);
337 LocalVariable* variable =
338 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
339 Symbols::This(), klass_type);
340 scope_->InsertParameterAt(0, variable);
341 parsed_function_->set_receiver_var(variable);
342 }
343 VisitNode();
344 break;
345 }
346 case FunctionLayout::kDynamicInvocationForwarder: {
347 const String& name = String::Handle(Z, function.name());
348 ASSERT(Function::IsDynamicInvocationForwarderName(name));
349
350 const auto& target = Function::ZoneHandle(Z, function.ForwardingTarget());
351 ASSERT(!target.IsNull());
352
353 if (helper_.PeekTag() == kField) {
354 // Create [this] variable.
355 const Class& klass = Class::Handle(Z, function.Owner());
356 parsed_function_->set_receiver_var(
357 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
358 Symbols::This(), H.GetDeclarationType(klass)));
359 scope_->InsertParameterAt(0, parsed_function_->receiver_var());
360
361 // Create setter value variable.
362 if (target.IsImplicitSetterFunction()) {
363 result_->setter_value = MakeVariable(
364 TokenPosition::kNoSource, TokenPosition::kNoSource,
365 Symbols::Value(),
366 AbstractType::ZoneHandle(Z, function.ParameterTypeAt(1)));
367 scope_->InsertParameterAt(1, result_->setter_value);
368 }
369 break;
370 }
371
372 // We do not create dyn:* forwarders for method extractors, since those
373 // can never return unboxed values (they return a closure).
374 ASSERT(!target.IsMethodExtractor());
375
376 helper_.ReadUntilFunctionNode();
377 function_node_helper.ReadUntilExcluding(
378 FunctionNodeHelper::kPositionalParameters);
379
380 // Create [this] variable.
381 intptr_t pos = 0;
382 Class& klass = Class::Handle(Z, function.Owner());
383 parsed_function_->set_receiver_var(
384 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
385 Symbols::This(), H.GetDeclarationType(klass)));
386 scope_->InsertParameterAt(pos++, parsed_function_->receiver_var());
387
388 // Create all positional and named parameters.
389 AddPositionalAndNamedParameters(
390 pos, kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
391 attrs);
392 break;
393 }
394 case FunctionLayout::kMethodExtractor: {
395 // Add a receiver parameter. Though it is captured, we emit code to
396 // explicitly copy it to a fixed offset in a freshly-allocated context
397 // instead of using the generic code for regular functions.
398 // Therefore, it isn't necessary to mark it as captured here.
399 Class& klass = Class::Handle(Z, function.Owner());
400 Type& klass_type = H.GetDeclarationType(klass);
401 LocalVariable* variable =
402 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
403 Symbols::This(), klass_type);
404 scope_->InsertParameterAt(0, variable);
405 parsed_function_->set_receiver_var(variable);
406 break;
407 }
408 case FunctionLayout::kNoSuchMethodDispatcher:
409 case FunctionLayout::kInvokeFieldDispatcher:
410 case FunctionLayout::kFfiTrampoline: {
411 for (intptr_t i = 0; i < function.NumParameters(); ++i) {
412 LocalVariable* variable = MakeVariable(
413 TokenPosition::kNoSource, TokenPosition::kNoSource,
414 String::ZoneHandle(Z, function.ParameterNameAt(i)),
415 AbstractType::ZoneHandle(Z, function.IsFfiTrampoline()
416 ? function.ParameterTypeAt(i)
417 : Object::dynamic_type().raw()));
418 scope_->InsertParameterAt(i, variable);
419 }
420 // Callbacks and calls with handles need try/catch variables.
421 if (function.IsFfiTrampoline() &&
422 (function.FfiCallbackTarget() != Function::null() ||
423 function.FfiCSignatureContainsHandles())) {
424 current_function_async_marker_ = FunctionNodeHelper::kSync;
425 ++depth_.try_;
426 AddTryVariables();
427 --depth_.try_;
428 ++depth_.catch_;
429 AddCatchVariables();
430 FinalizeCatchVariables();
431 --depth_.catch_;
432 }
433 break;
434 }
435 case FunctionLayout::kSignatureFunction:
436 case FunctionLayout::kIrregexpFunction:
437 UNREACHABLE();
438 }
439 if (needs_expr_temp_) {
440 scope_->AddVariable(parsed_function_->EnsureExpressionTemp());
441 }
442 if (parsed_function_->function().MayHaveUncheckedEntryPoint()) {
443 scope_->AddVariable(parsed_function_->EnsureEntryPointsTemp());
444 }
445
446 parsed_function_->AllocateVariables();
447
448 return result_;
449}
450
451void ScopeBuilder::ReportUnexpectedTag(const char* variant, Tag tag) {
452 H.ReportError(helper_.script(), TokenPosition::kNoSource,
453 "Unexpected tag %d (%s) in %s, expected %s", tag,
454 Reader::TagName(tag),
455 parsed_function_->function().ToQualifiedCString(), variant);
456}
457
458void ScopeBuilder::VisitNode() {
459 Tag tag = helper_.PeekTag();
460 switch (tag) {
461 case kConstructor:
462 VisitConstructor();
463 return;
464 case kProcedure:
465 VisitProcedure();
466 return;
467 case kField:
468 VisitField();
469 return;
470 case kFunctionNode:
471 VisitFunctionNode();
472 return;
473 default:
474 UNIMPLEMENTED();
475 return;
476 }
477}
478
479void ScopeBuilder::VisitConstructor() {
480 // Field initializers that come from non-static field declarations are
481 // compiled as if they appear in the constructor initializer list. This is
482 // important for closure-valued field initializers because the VM expects the
483 // corresponding closure functions to appear as if they were nested inside the
484 // constructor.
485 ConstructorHelper constructor_helper(&helper_);
486 constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
487 {
488 const Function& function = parsed_function_->function();
489 Class& parent_class = Class::Handle(Z, function.Owner());
490 Array& class_fields = Array::Handle(Z, parent_class.fields());
491 Field& class_field = Field::Handle(Z);
492 for (intptr_t i = 0; i < class_fields.Length(); ++i) {
493 class_field ^= class_fields.At(i);
494 if (!class_field.is_static()) {
495 ExternalTypedData& kernel_data =
496 ExternalTypedData::Handle(Z, class_field.KernelData());
497 ASSERT(!kernel_data.IsNull());
498 intptr_t field_offset = class_field.kernel_offset();
499 AlternativeReadingScopeWithNewData alt(&helper_.reader_, &kernel_data,
500 field_offset);
501 FieldHelper field_helper(&helper_);
502 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
503 Tag initializer_tag = helper_.ReadTag();
504 if (initializer_tag == kSomething) {
505 VisitExpression(); // read initializer.
506 }
507 }
508 }
509 }
510
511 // Visit children (note that there's no reason to visit the name).
512 VisitFunctionNode();
513 intptr_t list_length =
514 helper_.ReadListLength(); // read initializers list length.
515 for (intptr_t i = 0; i < list_length; i++) {
516 VisitInitializer();
517 }
518}
519
520void ScopeBuilder::VisitProcedure() {
521 ProcedureHelper procedure_helper(&helper_);
522 procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
523 if (helper_.ReadTag() == kSomething) {
524 VisitFunctionNode();
525 }
526}
527
528void ScopeBuilder::VisitField() {
529 FieldHelper field_helper(&helper_);
530 field_helper.ReadUntilExcluding(FieldHelper::kType);
531 VisitDartType(); // read type.
532 Tag tag = helper_.ReadTag(); // read initializer (part 1).
533 if (tag == kSomething) {
534 VisitExpression(); // read initializer (part 2).
535 }
536}
537
538void ScopeBuilder::VisitFunctionNode() {
539 FunctionNodeHelper function_node_helper(&helper_);
540 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
541
542 const auto& function = parsed_function_->function();
543
544 intptr_t list_length =
545 helper_.ReadListLength(); // read type_parameters list length.
546 for (intptr_t i = 0; i < list_length; ++i) {
547 TypeParameterHelper helper(&helper_);
548 helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
549 VisitDartType(); // read ith bound.
550 helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
551 if (helper_.ReadTag() == kSomething) {
552 VisitDartType(); // read ith default type.
553 }
554 helper.Finish();
555 }
556 function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
557
558 if (FLAG_causal_async_stacks &&
559 (function_node_helper.dart_async_marker_ == FunctionNodeHelper::kAsync ||
560 function_node_helper.dart_async_marker_ ==
561 FunctionNodeHelper::kAsyncStar)) {
562 LocalVariable* asyncStackTraceVar = MakeVariable(
563 TokenPosition::kNoSource, TokenPosition::kNoSource,
564 Symbols::AsyncStackTraceVar(), AbstractType::dynamic_type());
565 scope_->AddVariable(asyncStackTraceVar);
566 }
567
568 if (function_node_helper.async_marker_ == FunctionNodeHelper::kSyncYielding) {
569 intptr_t offset = function.num_fixed_parameters();
570 for (intptr_t i = 0; i < function.NumOptionalPositionalParameters(); i++) {
571 parsed_function_->ParameterVariable(offset + i)->set_is_forced_stack();
572 }
573 }
574
575 // Read (but don't visit) the positional and named parameters, because they've
576 // already been added to the scope.
577 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody);
578
579 if (helper_.ReadTag() == kSomething) {
580 PositionScope scope(&helper_.reader_);
581 VisitStatement(); // Read body
582 first_body_token_position_ = helper_.reader_.min_position();
583 }
584
585 // Ensure that :await_jump_var, :await_ctx_var, :async_op,
586 // :async_completer and :async_stack_trace are captured.
587 if (function_node_helper.async_marker_ == FunctionNodeHelper::kSyncYielding) {
588 {
589 LocalVariable* temp = NULL;
590 LookupCapturedVariableByName(
591 (depth_.function_ == 0) ? &result_->yield_jump_variable : &temp,
592 Symbols::AwaitJumpVar());
593 }
594 {
595 LocalVariable* temp = NULL;
596 LookupCapturedVariableByName(
597 (depth_.function_ == 0) ? &result_->yield_context_variable : &temp,
598 Symbols::AwaitContextVar());
599 }
600 {
601 LocalVariable* temp =
602 scope_->LookupVariable(Symbols::AsyncOperation(), true);
603 if (temp != NULL) {
604 scope_->CaptureVariable(temp);
605 }
606 }
607 {
608 LocalVariable* temp =
609 scope_->LookupVariable(Symbols::AsyncCompleter(), true);
610 if (temp != NULL) {
611 scope_->CaptureVariable(temp);
612 }
613 }
614 {
615 LocalVariable* temp =
616 scope_->LookupVariable(Symbols::ControllerStream(), true);
617 if (temp != NULL) {
618 scope_->CaptureVariable(temp);
619 }
620 }
621 if (FLAG_causal_async_stacks) {
622 LocalVariable* temp =
623 scope_->LookupVariable(Symbols::AsyncStackTraceVar(), true);
624 if (temp != NULL) {
625 scope_->CaptureVariable(temp);
626 }
627 }
628 }
629
630 // Mark known chained futures such as _Future::timeout()'s _future.
631 if (function.recognized_kind() == MethodRecognizer::kFutureTimeout &&
632 depth_.function_ == 1) {
633 LocalVariable* future = scope_->LookupVariable(Symbols::_future(), true);
634 ASSERT(future != nullptr);
635 future->set_is_chained_future();
636 future->set_expected_context_index(Context::kFutureTimeoutFutureIndex);
637 } else if (function.recognized_kind() == MethodRecognizer::kFutureWait &&
638 depth_.function_ == 1) {
639 LocalVariable* future = scope_->LookupVariable(Symbols::_future(), true);
640 ASSERT(future != nullptr);
641 future->set_is_chained_future();
642 future->set_expected_context_index(Context::kFutureWaitFutureIndex);
643 }
644}
645
646void ScopeBuilder::VisitInitializer() {
647 Tag tag = helper_.ReadTag();
648 helper_.ReadByte(); // read isSynthetic flag.
649 switch (tag) {
650 case kInvalidInitializer:
651 return;
652 case kFieldInitializer:
653 helper_.SkipCanonicalNameReference(); // read field_reference.
654 VisitExpression(); // read value.
655 return;
656 case kSuperInitializer:
657 helper_.ReadPosition(); // read position.
658 helper_.SkipCanonicalNameReference(); // read target_reference.
659 VisitArguments(); // read arguments.
660 return;
661 case kRedirectingInitializer:
662 helper_.ReadPosition(); // read position.
663 helper_.SkipCanonicalNameReference(); // read target_reference.
664 VisitArguments(); // read arguments.
665 return;
666 case kLocalInitializer:
667 VisitVariableDeclaration(); // read variable.
668 return;
669 case kAssertInitializer:
670 VisitStatement();
671 return;
672 default:
673 ReportUnexpectedTag("initializer", tag);
674 UNREACHABLE();
675 }
676}
677
678void ScopeBuilder::VisitExpression() {
679 uint8_t payload = 0;
680 Tag tag = helper_.ReadTag(&payload);
681 switch (tag) {
682 case kInvalidExpression:
683 helper_.ReadPosition();
684 helper_.SkipStringReference();
685 return;
686 case kVariableGet: {
687 helper_.ReadPosition(); // read position.
688 intptr_t variable_kernel_offset =
689 helper_.ReadUInt(); // read kernel position.
690 helper_.ReadUInt(); // read relative variable index.
691 helper_.SkipOptionalDartType(); // read promoted type.
692 VisitVariableGet(variable_kernel_offset);
693 return;
694 }
695 case kSpecializedVariableGet: {
696 helper_.ReadPosition(); // read position.
697 intptr_t variable_kernel_offset =
698 helper_.ReadUInt(); // read kernel position.
699 VisitVariableGet(variable_kernel_offset);
700 return;
701 }
702 case kVariableSet: {
703 helper_.ReadPosition(); // read position.
704 intptr_t variable_kernel_offset =
705 helper_.ReadUInt(); // read kernel position.
706 helper_.ReadUInt(); // read relative variable index.
707 LookupVariable(variable_kernel_offset);
708 VisitExpression(); // read expression.
709 return;
710 }
711 case kSpecializedVariableSet: {
712 helper_.ReadPosition(); // read position.
713 intptr_t variable_kernel_offset =
714 helper_.ReadUInt(); // read kernel position.
715 LookupVariable(variable_kernel_offset);
716 VisitExpression(); // read expression.
717 return;
718 }
719 case kPropertyGet:
720 helper_.ReadPosition(); // read position.
721 VisitExpression(); // read receiver.
722 helper_.SkipName(); // read name.
723 // read interface_target_reference.
724 helper_.SkipInterfaceMemberNameReference();
725 return;
726 case kPropertySet:
727 helper_.ReadPosition(); // read position.
728 VisitExpression(); // read receiver.
729 helper_.SkipName(); // read name.
730 VisitExpression(); // read value.
731 // read interface_target_reference.
732 helper_.SkipInterfaceMemberNameReference();
733 return;
734 case kDirectPropertyGet:
735 helper_.ReadPosition(); // read position.
736 VisitExpression(); // read receiver.
737 helper_.SkipInterfaceMemberNameReference(); // read target_reference.
738 return;
739 case kDirectPropertySet:
740 helper_.ReadPosition(); // read position.
741 VisitExpression(); // read receiver.
742 helper_.SkipInterfaceMemberNameReference(); // read target_reference.
743 VisitExpression(); // read value·
744 return;
745 case kSuperPropertyGet:
746 HandleLoadReceiver();
747 helper_.ReadPosition(); // read position.
748 helper_.SkipName(); // read name.
749 helper_.SkipInterfaceMemberNameReference(); // read target_reference.
750 return;
751 case kSuperPropertySet:
752 HandleLoadReceiver();
753 helper_.ReadPosition(); // read position.
754 helper_.SkipName(); // read name.
755 VisitExpression(); // read value.
756 helper_.SkipInterfaceMemberNameReference(); // read target_reference.
757 return;
758 case kStaticGet:
759 helper_.ReadPosition(); // read position.
760 helper_.SkipCanonicalNameReference(); // read target_reference.
761 return;
762 case kStaticSet:
763 helper_.ReadPosition(); // read position.
764 helper_.SkipCanonicalNameReference(); // read target_reference.
765 VisitExpression(); // read expression.
766 return;
767 case kMethodInvocation:
768 helper_.ReadPosition(); // read position.
769 VisitExpression(); // read receiver.
770 helper_.SkipName(); // read name.
771 VisitArguments(); // read arguments.
772 // read interface_target_reference.
773 helper_.SkipInterfaceMemberNameReference();
774 return;
775 case kDirectMethodInvocation:
776 helper_.ReadPosition(); // read position.
777 VisitExpression(); // read receiver.
778 helper_.SkipInterfaceMemberNameReference(); // read target_reference.
779 VisitArguments(); // read arguments.
780 return;
781 case kSuperMethodInvocation:
782 HandleLoadReceiver();
783 helper_.ReadPosition(); // read position.
784 helper_.SkipName(); // read name.
785 VisitArguments(); // read arguments.
786 // read interface_target_reference.
787 helper_.SkipInterfaceMemberNameReference();
788 return;
789 case kStaticInvocation:
790 helper_.ReadPosition(); // read position.
791 helper_.SkipCanonicalNameReference(); // read procedure_reference.
792 VisitArguments(); // read arguments.
793 return;
794 case kConstructorInvocation:
795 helper_.ReadPosition(); // read position.
796 helper_.SkipCanonicalNameReference(); // read target_reference.
797 VisitArguments(); // read arguments.
798 return;
799 case kNot:
800 VisitExpression(); // read expression.
801 return;
802 case kNullCheck:
803 helper_.ReadPosition(); // read position.
804 VisitExpression(); // read expression.
805 return;
806 case kLogicalExpression:
807 needs_expr_temp_ = true;
808 VisitExpression(); // read left.
809 helper_.SkipBytes(1); // read operator.
810 VisitExpression(); // read right.
811 return;
812 case kConditionalExpression: {
813 needs_expr_temp_ = true;
814 VisitExpression(); // read condition.
815 VisitExpression(); // read then.
816 VisitExpression(); // read otherwise.
817 helper_.SkipOptionalDartType(); // read unused static type.
818 return;
819 }
820 case kStringConcatenation: {
821 helper_.ReadPosition(); // read position.
822 intptr_t list_length = helper_.ReadListLength(); // read list length.
823 for (intptr_t i = 0; i < list_length; ++i) {
824 VisitExpression(); // read ith expression.
825 }
826 return;
827 }
828 case kIsExpression:
829 helper_.ReadPosition(); // read position.
830 if (translation_helper_.info().kernel_binary_version() >= 38) {
831 helper_.ReadFlags(); // read flags.
832 }
833 VisitExpression(); // read operand.
834 VisitDartType(); // read type.
835 return;
836 case kAsExpression:
837 helper_.ReadPosition(); // read position.
838 helper_.ReadFlags(); // read flags.
839 VisitExpression(); // read operand.
840 VisitDartType(); // read type.
841 return;
842 case kTypeLiteral:
843 VisitDartType(); // read type.
844 return;
845 case kThisExpression:
846 HandleLoadReceiver();
847 return;
848 case kRethrow:
849 helper_.ReadPosition(); // read position.
850 return;
851 case kThrow:
852 helper_.ReadPosition(); // read position.
853 VisitExpression(); // read expression.
854 return;
855 case kListLiteral: {
856 helper_.ReadPosition(); // read position.
857 VisitDartType(); // read type.
858 intptr_t list_length = helper_.ReadListLength(); // read list length.
859 for (intptr_t i = 0; i < list_length; ++i) {
860 VisitExpression(); // read ith expression.
861 }
862 return;
863 }
864 case kSetLiteral: {
865 // Set literals are currently desugared in the frontend and will not
866 // reach the VM. See http://dartbug.com/35124 for discussion.
867 UNREACHABLE();
868 return;
869 }
870 case kMapLiteral: {
871 helper_.ReadPosition(); // read position.
872 VisitDartType(); // read key type.
873 VisitDartType(); // read value type.
874 intptr_t list_length = helper_.ReadListLength(); // read list length.
875 for (intptr_t i = 0; i < list_length; ++i) {
876 VisitExpression(); // read ith key.
877 VisitExpression(); // read ith value.
878 }
879 return;
880 }
881 case kFunctionExpression: {
882 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
883 helper_.ReadPosition(); // read position.
884 HandleLocalFunction(offset); // read function node.
885 return;
886 }
887 case kLet: {
888 PositionScope scope(&helper_.reader_);
889 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
890
891 EnterScope(offset);
892
893 VisitVariableDeclaration(); // read variable declaration.
894 VisitExpression(); // read expression.
895
896 ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
897 return;
898 }
899 case kBlockExpression: {
900 PositionScope scope(&helper_.reader_);
901 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
902
903 EnterScope(offset);
904
905 intptr_t list_length =
906 helper_.ReadListLength(); // read number of statements.
907 for (intptr_t i = 0; i < list_length; ++i) {
908 VisitStatement(); // read ith statement.
909 }
910 VisitExpression(); // read expression.
911
912 ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
913 return;
914 }
915 case kBigIntLiteral:
916 helper_.SkipStringReference(); // read string reference.
917 return;
918 case kStringLiteral:
919 helper_.SkipStringReference(); // read string reference.
920 return;
921 case kSpecializedIntLiteral:
922 return;
923 case kNegativeIntLiteral:
924 helper_.ReadUInt(); // read value.
925 return;
926 case kPositiveIntLiteral:
927 helper_.ReadUInt(); // read value.
928 return;
929 case kDoubleLiteral:
930 helper_.ReadDouble(); // read value.
931 return;
932 case kTrueLiteral:
933 return;
934 case kFalseLiteral:
935 return;
936 case kNullLiteral:
937 return;
938 case kConstantExpression:
939 helper_.ReadPosition();
940 helper_.SkipDartType();
941 helper_.SkipConstantReference();
942 return;
943 case kInstantiation: {
944 VisitExpression();
945 const intptr_t list_length =
946 helper_.ReadListLength(); // read list length.
947 for (intptr_t i = 0; i < list_length; ++i) {
948 VisitDartType(); // read ith type.
949 }
950 return;
951 }
952 case kLoadLibrary:
953 case kCheckLibraryIsLoaded:
954 helper_.ReadUInt(); // library index
955 break;
956 case kConstStaticInvocation:
957 case kConstConstructorInvocation:
958 case kConstListLiteral:
959 case kConstSetLiteral:
960 case kConstMapLiteral:
961 case kSymbolLiteral:
962 // Const invocations and const literals are removed by the
963 // constant evaluator.
964 case kListConcatenation:
965 case kSetConcatenation:
966 case kMapConcatenation:
967 case kInstanceCreation:
968 case kFileUriExpression:
969 // Collection concatenation, instance creation operations and
970 // in-expression URI changes are internal to the front end and
971 // removed by the constant evaluator.
972 default:
973 ReportUnexpectedTag("expression", tag);
974 UNREACHABLE();
975 }
976}
977
978void ScopeBuilder::VisitStatement() {
979 Tag tag = helper_.ReadTag(); // read tag.
980 switch (tag) {
981 case kExpressionStatement:
982 VisitExpression(); // read expression.
983 return;
984 case kBlock: {
985 PositionScope scope(&helper_.reader_);
986 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
987
988 EnterScope(offset);
989
990 intptr_t list_length =
991 helper_.ReadListLength(); // read number of statements.
992 for (intptr_t i = 0; i < list_length; ++i) {
993 VisitStatement(); // read ith statement.
994 }
995
996 ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
997 return;
998 }
999 case kEmptyStatement:
1000 return;
1001 case kAssertBlock:
1002 if (I->asserts()) {
1003 PositionScope scope(&helper_.reader_);
1004 intptr_t offset =
1005 helper_.ReaderOffset() - 1; // -1 to include tag byte.
1006
1007 EnterScope(offset);
1008
1009 intptr_t list_length =
1010 helper_.ReadListLength(); // read number of statements.
1011 for (intptr_t i = 0; i < list_length; ++i) {
1012 VisitStatement(); // read ith statement.
1013 }
1014
1015 ExitScope(helper_.reader_.min_position(),
1016 helper_.reader_.max_position());
1017 } else {
1018 helper_.SkipStatementList();
1019 }
1020 return;
1021 case kAssertStatement:
1022 if (I->asserts()) {
1023 VisitExpression(); // Read condition.
1024 helper_.ReadPosition(); // read condition start offset.
1025 helper_.ReadPosition(); // read condition end offset.
1026 Tag tag = helper_.ReadTag(); // read (first part of) message.
1027 if (tag == kSomething) {
1028 VisitExpression(); // read (rest of) message.
1029 }
1030 } else {
1031 helper_.SkipExpression(); // Read condition.
1032 helper_.ReadPosition(); // read condition start offset.
1033 helper_.ReadPosition(); // read condition end offset.
1034 Tag tag = helper_.ReadTag(); // read (first part of) message.
1035 if (tag == kSomething) {
1036 helper_.SkipExpression(); // read (rest of) message.
1037 }
1038 }
1039 return;
1040 case kLabeledStatement:
1041 VisitStatement(); // read body.
1042 return;
1043 case kBreakStatement:
1044 helper_.ReadPosition(); // read position.
1045 helper_.ReadUInt(); // read target_index.
1046 return;
1047 case kWhileStatement:
1048 ++depth_.loop_;
1049 helper_.ReadPosition(); // read position.
1050 VisitExpression(); // read condition.
1051 VisitStatement(); // read body.
1052 --depth_.loop_;
1053 return;
1054 case kDoStatement:
1055 ++depth_.loop_;
1056 helper_.ReadPosition(); // read position.
1057 VisitStatement(); // read body.
1058 VisitExpression(); // read condition.
1059 --depth_.loop_;
1060 return;
1061 case kForStatement: {
1062 PositionScope scope(&helper_.reader_);
1063
1064 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
1065
1066 ++depth_.loop_;
1067 EnterScope(offset);
1068
1069 TokenPosition position = helper_.ReadPosition(); // read position.
1070 intptr_t list_length =
1071 helper_.ReadListLength(); // read number of variables.
1072 for (intptr_t i = 0; i < list_length; ++i) {
1073 VisitVariableDeclaration(); // read ith variable.
1074 }
1075
1076 Tag tag = helper_.ReadTag(); // Read first part of condition.
1077 if (tag == kSomething) {
1078 VisitExpression(); // read rest of condition.
1079 }
1080 list_length = helper_.ReadListLength(); // read number of updates.
1081 for (intptr_t i = 0; i < list_length; ++i) {
1082 VisitExpression(); // read ith update.
1083 }
1084 VisitStatement(); // read body.
1085
1086 ExitScope(position, helper_.reader_.max_position());
1087 --depth_.loop_;
1088 return;
1089 }
1090 case kForInStatement:
1091 case kAsyncForInStatement: {
1092 PositionScope scope(&helper_.reader_);
1093
1094 intptr_t start_offset =
1095 helper_.ReaderOffset() - 1; // -1 to include tag byte.
1096
1097 helper_.ReadPosition(); // read position.
1098 TokenPosition body_position =
1099 helper_.ReadPosition(); // read body position.
1100
1101 // Notice the ordering: We skip the variable, read the iterable, go back,
1102 // re-read the variable, go forward to after having read the iterable.
1103 intptr_t offset = helper_.ReaderOffset();
1104 helper_.SkipVariableDeclaration(); // read variable.
1105 VisitExpression(); // read iterable.
1106
1107 ++depth_.for_in_;
1108 AddIteratorVariable();
1109 ++depth_.loop_;
1110 EnterScope(start_offset);
1111
1112 {
1113 AlternativeReadingScope alt(&helper_.reader_, offset);
1114 VisitVariableDeclaration(); // read variable.
1115 }
1116 VisitStatement(); // read body.
1117
1118 if (!body_position.IsReal()) {
1119 body_position = helper_.reader_.min_position();
1120 }
1121 // TODO(jensj): From kernel_binary.cc
1122 // forinstmt->variable_->set_end_position(forinstmt->position_);
1123 ExitScope(body_position, helper_.reader_.max_position());
1124 --depth_.loop_;
1125 --depth_.for_in_;
1126 return;
1127 }
1128 case kSwitchStatement: {
1129 AddSwitchVariable();
1130 helper_.ReadPosition(); // read position.
1131 VisitExpression(); // read condition.
1132 int case_count = helper_.ReadListLength(); // read number of cases.
1133 for (intptr_t i = 0; i < case_count; ++i) {
1134 int expression_count =
1135 helper_.ReadListLength(); // read number of expressions.
1136 for (intptr_t j = 0; j < expression_count; ++j) {
1137 helper_.ReadPosition(); // read jth position.
1138 VisitExpression(); // read jth expression.
1139 }
1140 helper_.ReadBool(); // read is_default.
1141 VisitStatement(); // read body.
1142 }
1143 return;
1144 }
1145 case kContinueSwitchStatement:
1146 helper_.ReadPosition(); // read position.
1147 helper_.ReadUInt(); // read target_index.
1148 return;
1149 case kIfStatement:
1150 helper_.ReadPosition(); // read position.
1151 VisitExpression(); // read condition.
1152 VisitStatement(); // read then.
1153 VisitStatement(); // read otherwise.
1154 return;
1155 case kReturnStatement: {
1156 if ((depth_.function_ == 0) && (depth_.finally_ > 0) &&
1157 (result_->finally_return_variable == NULL)) {
1158 const String& name = Symbols::TryFinallyReturnValue();
1159 LocalVariable* variable =
1160 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1161 name, AbstractType::dynamic_type());
1162 current_function_scope_->AddVariable(variable);
1163 result_->finally_return_variable = variable;
1164 }
1165
1166 helper_.ReadPosition(); // read position
1167 Tag tag = helper_.ReadTag(); // read (first part of) expression.
1168 if (tag == kSomething) {
1169 VisitExpression(); // read (rest of) expression.
1170 }
1171 return;
1172 }
1173 case kTryCatch: {
1174 ++depth_.try_;
1175 AddTryVariables();
1176 VisitStatement(); // read body.
1177 --depth_.try_;
1178
1179 ++depth_.catch_;
1180 AddCatchVariables();
1181
1182 helper_.ReadByte(); // read flags
1183 intptr_t catch_count =
1184 helper_.ReadListLength(); // read number of catches.
1185 for (intptr_t i = 0; i < catch_count; ++i) {
1186 PositionScope scope(&helper_.reader_);
1187 intptr_t offset = helper_.ReaderOffset(); // Catch has no tag.
1188
1189 EnterScope(offset);
1190
1191 helper_.ReadPosition(); // read position.
1192 VisitDartType(); // Read the guard.
1193 tag = helper_.ReadTag(); // read first part of exception.
1194 if (tag == kSomething) {
1195 VisitVariableDeclaration(); // read exception.
1196 }
1197 tag = helper_.ReadTag(); // read first part of stack trace.
1198 if (tag == kSomething) {
1199 VisitVariableDeclaration(); // read stack trace.
1200 }
1201 VisitStatement(); // read body.
1202
1203 ExitScope(helper_.reader_.min_position(),
1204 helper_.reader_.max_position());
1205 }
1206
1207 FinalizeCatchVariables();
1208
1209 --depth_.catch_;
1210 return;
1211 }
1212 case kTryFinally: {
1213 ++depth_.try_;
1214 ++depth_.finally_;
1215 AddTryVariables();
1216
1217 VisitStatement(); // read body.
1218
1219 --depth_.finally_;
1220 --depth_.try_;
1221 ++depth_.catch_;
1222 AddCatchVariables();
1223
1224 VisitStatement(); // read finalizer.
1225
1226 FinalizeCatchVariables();
1227
1228 --depth_.catch_;
1229 return;
1230 }
1231 case kYieldStatement: {
1232 helper_.ReadPosition(); // read position.
1233 word flags = helper_.ReadByte(); // read flags.
1234 VisitExpression(); // read expression.
1235
1236 ASSERT(flags == kNativeYieldFlags);
1237 if (depth_.function_ == 0) {
1238 AddSwitchVariable();
1239 // Promote all currently visible local variables into the context.
1240 // TODO(27590) CaptureLocalVariables promotes to many variables into
1241 // the scope. Mark those variables as stack_local.
1242 // TODO(27590) we don't need to promote those variables that are
1243 // not used across yields.
1244 scope_->CaptureLocalVariables(current_function_scope_);
1245 }
1246 return;
1247 }
1248 case kVariableDeclaration:
1249 VisitVariableDeclaration(); // read variable declaration.
1250 return;
1251 case kFunctionDeclaration: {
1252 intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
1253 helper_.ReadPosition(); // read position.
1254 VisitVariableDeclaration(); // read variable declaration.
1255 HandleLocalFunction(offset); // read function node.
1256 return;
1257 }
1258 default:
1259 ReportUnexpectedTag("declaration", tag);
1260 UNREACHABLE();
1261 }
1262}
1263
1264void ScopeBuilder::VisitArguments() {
1265 helper_.ReadUInt(); // read argument_count.
1266
1267 // Types
1268 intptr_t list_length = helper_.ReadListLength(); // read list length.
1269 for (intptr_t i = 0; i < list_length; ++i) {
1270 VisitDartType(); // read ith type.
1271 }
1272
1273 // Positional.
1274 list_length = helper_.ReadListLength(); // read list length.
1275 for (intptr_t i = 0; i < list_length; ++i) {
1276 VisitExpression(); // read ith positional.
1277 }
1278
1279 // Named.
1280 list_length = helper_.ReadListLength(); // read list length.
1281 for (intptr_t i = 0; i < list_length; ++i) {
1282 helper_.SkipStringReference(); // read ith name index.
1283 VisitExpression(); // read ith expression.
1284 }
1285}
1286
1287void ScopeBuilder::VisitVariableDeclaration() {
1288 PositionScope scope(&helper_.reader_);
1289
1290 intptr_t kernel_offset_no_tag = helper_.ReaderOffset();
1291 VariableDeclarationHelper helper(&helper_);
1292 helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
1293 AbstractType& type = BuildAndVisitVariableType();
1294
1295 // In case `declaration->IsConst()` the flow graph building will take care of
1296 // evaluating the constant and setting it via
1297 // `declaration->SetConstantValue()`.
1298 const String& name = (H.StringSize(helper.name_index_) == 0)
1299 ? GenerateName(":var", name_index_++)
1300 : H.DartSymbolObfuscate(helper.name_index_);
1301
1302 intptr_t initializer_offset = helper_.ReaderOffset();
1303 Tag tag = helper_.ReadTag(); // read (first part of) initializer.
1304 if (tag == kSomething) {
1305 VisitExpression(); // read (actual) initializer.
1306 }
1307
1308 // Go to next token position so it ends *after* the last potentially
1309 // debuggable position in the initializer.
1310 TokenPosition end_position = helper_.reader_.max_position();
1311 if (end_position.IsReal()) {
1312 end_position.Next();
1313 }
1314 LocalVariable* variable =
1315 MakeVariable(helper.position_, end_position, name, type);
1316 if (helper.IsFinal()) {
1317 variable->set_is_final();
1318 }
1319 if (helper.IsLate()) {
1320 variable->set_is_late();
1321 variable->set_late_init_offset(initializer_offset);
1322 }
1323
1324 // Lift the special async vars out of the function body scope, into the
1325 // outer function declaration scope.
1326 // This way we can allocate them in the outermost context at fixed indices,
1327 // allowing support for --lazy-async-stacks implementation to find awaiters.
1328 if (name.Equals(Symbols::AwaitJumpVar()) ||
1329 name.Equals(Symbols::AsyncCompleter()) ||
1330 name.Equals(Symbols::Controller())) {
1331 scope_->parent()->AddVariable(variable);
1332 } else {
1333 scope_->AddVariable(variable);
1334 }
1335 result_->locals.Insert(helper_.data_program_offset_ + kernel_offset_no_tag,
1336 variable);
1337}
1338
1339AbstractType& ScopeBuilder::BuildAndVisitVariableType() {
1340 const intptr_t offset = helper_.ReaderOffset();
1341 AbstractType& type = T.BuildType();
1342 helper_.SetOffset(offset); // rewind
1343 VisitDartType();
1344 return type;
1345}
1346
1347void ScopeBuilder::VisitDartType() {
1348 Tag tag = helper_.ReadTag();
1349 switch (tag) {
1350 case kInvalidType:
1351 case kDynamicType:
1352 case kVoidType:
1353 case kBottomType:
1354 // those contain nothing.
1355 return;
1356 case kNeverType:
1357 helper_.ReadNullability();
1358 return;
1359 case kInterfaceType:
1360 VisitInterfaceType(false);
1361 return;
1362 case kSimpleInterfaceType:
1363 VisitInterfaceType(true);
1364 return;
1365 case kFunctionType:
1366 VisitFunctionType(false);
1367 return;
1368 case kSimpleFunctionType:
1369 VisitFunctionType(true);
1370 return;
1371 case kTypeParameterType:
1372 VisitTypeParameterType();
1373 return;
1374 default:
1375 ReportUnexpectedTag("type", tag);
1376 UNREACHABLE();
1377 }
1378}
1379
1380void ScopeBuilder::VisitInterfaceType(bool simple) {
1381 helper_.ReadNullability(); // read nullability.
1382 helper_.ReadUInt(); // read klass_name.
1383 if (!simple) {
1384 intptr_t length = helper_.ReadListLength(); // read number of types.
1385 for (intptr_t i = 0; i < length; ++i) {
1386 VisitDartType(); // read the ith type.
1387 }
1388 }
1389}
1390
1391void ScopeBuilder::VisitFunctionType(bool simple) {
1392 helper_.ReadNullability(); // read nullability.
1393
1394 if (!simple) {
1395 intptr_t list_length =
1396 helper_.ReadListLength(); // read type_parameters list length.
1397 for (int i = 0; i < list_length; ++i) {
1398 TypeParameterHelper helper(&helper_);
1399 helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
1400 VisitDartType(); // read bound.
1401 helper.ReadUntilExcludingAndSetJustRead(
1402 TypeParameterHelper::kDefaultType);
1403 if (helper_.ReadTag() == kSomething) {
1404 VisitDartType(); // read default type.
1405 }
1406 helper.Finish();
1407 }
1408 helper_.ReadUInt(); // read required parameter count.
1409 helper_.ReadUInt(); // read total parameter count.
1410 }
1411
1412 const intptr_t positional_count =
1413 helper_.ReadListLength(); // read positional_parameters list length.
1414 for (intptr_t i = 0; i < positional_count; ++i) {
1415 VisitDartType(); // read ith positional parameter.
1416 }
1417
1418 if (!simple) {
1419 const intptr_t named_count =
1420 helper_.ReadListLength(); // read named_parameters list length.
1421 for (intptr_t i = 0; i < named_count; ++i) {
1422 // read string reference (i.e. named_parameters[i].name).
1423 helper_.SkipStringReference();
1424 VisitDartType(); // read named_parameters[i].type.
1425 helper_.ReadByte(); // read flags
1426 }
1427 }
1428
1429 if (!simple) {
1430 helper_.SkipOptionalDartType(); // read typedef reference.
1431 }
1432
1433 VisitDartType(); // read return type.
1434}
1435
1436void ScopeBuilder::VisitTypeParameterType() {
1437 Function& function = Function::Handle(Z, parsed_function_->function().raw());
1438 while (function.IsClosureFunction()) {
1439 function = function.parent_function();
1440 }
1441
1442 helper_.ReadNullability(); // read nullability.
1443
1444 // The index here is the index identifying the type parameter binding site
1445 // inside the DILL file, which uses a different indexing system than the VM
1446 // uses for its 'TypeParameter's internally. This index includes both class
1447 // and function type parameters.
1448
1449 intptr_t index = helper_.ReadUInt(); // read index for parameter.
1450
1451 if (function.IsFactory()) {
1452 // The type argument vector is passed as the very first argument to the
1453 // factory constructor function.
1454 HandleSpecialLoad(&result_->type_arguments_variable,
1455 Symbols::TypeArgumentsParameter());
1456 } else {
1457 // If the type parameter is a parameter to this or an enclosing function, we
1458 // can read it directly from the function type arguments vector later.
1459 // Otherwise, the type arguments vector we need is stored on the instance
1460 // object, so we need to capture 'this'.
1461 Class& parent_class = Class::Handle(Z, function.Owner());
1462 if (index < parent_class.NumTypeParameters()) {
1463 HandleLoadReceiver();
1464 }
1465 }
1466
1467 helper_.SkipOptionalDartType(); // read bound bound.
1468}
1469
1470void ScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
1471 // "Peek" ahead into the function node
1472 intptr_t offset = helper_.ReaderOffset();
1473
1474 FunctionNodeHelper function_node_helper(&helper_);
1475 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
1476
1477 LocalScope* saved_function_scope = current_function_scope_;
1478 FunctionNodeHelper::AsyncMarker saved_function_async_marker =
1479 current_function_async_marker_;
1480 DepthState saved_depth_state = depth_;
1481 depth_ = DepthState(depth_.function_ + 1);
1482 EnterScope(parent_kernel_offset);
1483 current_function_scope_ = scope_;
1484 current_function_async_marker_ = function_node_helper.async_marker_;
1485 if (depth_.function_ == 1) {
1486 FunctionScope function_scope = {offset, scope_};
1487 result_->function_scopes.Add(function_scope);
1488 }
1489
1490 int num_type_params = 0;
1491 {
1492 AlternativeReadingScope _(&helper_.reader_);
1493 num_type_params = helper_.ReadListLength();
1494 }
1495 // Adding this scope here informs the type translator the type parameters of
1496 // this function are now in scope, although they are not defined and will be
1497 // filled in with dynamic. This is OK, since their definitions are not needed
1498 // for scope building of the enclosing function.
1499 TypeTranslator::TypeParameterScope scope(&type_translator_, num_type_params);
1500
1501 // read positional_parameters and named_parameters.
1502 function_node_helper.ReadUntilExcluding(
1503 FunctionNodeHelper::kPositionalParameters);
1504
1505 ProcedureAttributesMetadata default_attrs;
1506 AddPositionalAndNamedParameters(0, kTypeCheckAllParameters, default_attrs);
1507
1508 // "Peek" is now done.
1509 helper_.SetOffset(offset);
1510
1511 VisitFunctionNode(); // read function node.
1512
1513 ExitScope(function_node_helper.position_, function_node_helper.end_position_);
1514 depth_ = saved_depth_state;
1515 current_function_scope_ = saved_function_scope;
1516 current_function_async_marker_ = saved_function_async_marker;
1517}
1518
1519void ScopeBuilder::EnterScope(intptr_t kernel_offset) {
1520 scope_ = new (Z) LocalScope(scope_, depth_.function_, depth_.loop_);
1521 ASSERT(kernel_offset >= 0);
1522 result_->scopes.Insert(kernel_offset, scope_);
1523}
1524
1525void ScopeBuilder::ExitScope(TokenPosition start_position,
1526 TokenPosition end_position) {
1527 scope_->set_begin_token_pos(start_position);
1528 scope_->set_end_token_pos(end_position);
1529 scope_ = scope_->parent();
1530}
1531
1532void ScopeBuilder::AddPositionalAndNamedParameters(
1533 intptr_t pos,
1534 ParameterTypeCheckMode type_check_mode /* = kTypeCheckAllParameters*/,
1535 const ProcedureAttributesMetadata& attrs) {
1536 // List of positional.
1537 intptr_t list_length = helper_.ReadListLength(); // read list length.
1538 for (intptr_t i = 0; i < list_length; ++i) {
1539 AddVariableDeclarationParameter(pos++, type_check_mode, attrs);
1540 }
1541
1542 // List of named.
1543 list_length = helper_.ReadListLength(); // read list length.
1544 for (intptr_t i = 0; i < list_length; ++i) {
1545 AddVariableDeclarationParameter(pos++, type_check_mode, attrs);
1546 }
1547}
1548
1549void ScopeBuilder::AddVariableDeclarationParameter(
1550 intptr_t pos,
1551 ParameterTypeCheckMode type_check_mode,
1552 const ProcedureAttributesMetadata& attrs) {
1553 intptr_t kernel_offset = helper_.ReaderOffset(); // no tag.
1554 const InferredTypeMetadata parameter_type =
1555 inferred_type_metadata_helper_.GetInferredType(kernel_offset);
1556 VariableDeclarationHelper helper(&helper_);
1557 helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
1558 String& name = H.DartSymbolObfuscate(helper.name_index_);
1559 AbstractType& type = BuildAndVisitVariableType(); // read type.
1560 helper.SetJustRead(VariableDeclarationHelper::kType);
1561 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
1562
1563 LocalVariable* variable = MakeVariable(helper.position_, helper.position_,
1564 name, type, &parameter_type);
1565 if (helper.IsFinal()) {
1566 variable->set_is_final();
1567 }
1568 if (helper.IsCovariant()) {
1569 variable->set_is_explicit_covariant_parameter();
1570 }
1571 if (variable->name().raw() == Symbols::IteratorParameter().raw()) {
1572 variable->set_is_forced_stack();
1573 }
1574
1575 const bool needs_covariant_check_in_method =
1576 helper.IsCovariant() ||
1577 (helper.IsGenericCovariantImpl() &&
1578 (attrs.has_non_this_uses || attrs.has_tearoff_uses));
1579
1580 switch (type_check_mode) {
1581 case kTypeCheckAllParameters:
1582 variable->set_type_check_mode(LocalVariable::kDoTypeCheck);
1583 break;
1584 case kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod:
1585 if (needs_covariant_check_in_method) {
1586 // Don't type check covariant parameters - they will be checked by
1587 // a function we forward to. Their types however are not known.
1588 variable->set_type_check_mode(LocalVariable::kSkipTypeCheck);
1589 } else {
1590 variable->set_type_check_mode(LocalVariable::kDoTypeCheck);
1591 }
1592 break;
1593 case kTypeCheckForNonDynamicallyInvokedMethod:
1594 if (needs_covariant_check_in_method) {
1595 variable->set_type_check_mode(LocalVariable::kDoTypeCheck);
1596 } else {
1597 // Types of non-covariant parameters are guaranteed to match by
1598 // front-end enforcing strong mode types at call site.
1599 variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
1600 }
1601 break;
1602 case kTypeCheckForStaticFunction:
1603 variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
1604 break;
1605 }
1606
1607 // TODO(sjindel): We can also skip these checks on dynamic invocations as
1608 // well.
1609 if (parameter_type.IsSkipCheck()) {
1610 variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
1611 }
1612
1613 scope_->InsertParameterAt(pos, variable);
1614 result_->locals.Insert(helper_.data_program_offset_ + kernel_offset,
1615 variable);
1616
1617 // The default value may contain 'let' bindings for which the constant
1618 // evaluator needs scope bindings.
1619 Tag tag = helper_.ReadTag();
1620 if (tag == kSomething) {
1621 VisitExpression(); // read initializer.
1622 }
1623}
1624
1625LocalVariable* ScopeBuilder::MakeVariable(
1626 TokenPosition declaration_pos,
1627 TokenPosition token_pos,
1628 const String& name,
1629 const AbstractType& type,
1630 const InferredTypeMetadata* param_type_md /* = NULL */) {
1631 CompileType* param_type = nullptr;
1632 const Object* param_value = nullptr;
1633 if (param_type_md != nullptr && !param_type_md->IsTrivial()) {
1634 param_type = new (Z) CompileType(param_type_md->ToCompileType(Z));
1635 if (param_type_md->IsConstant()) {
1636 param_value = &param_type_md->constant_value;
1637 }
1638 }
1639 return new (Z) LocalVariable(declaration_pos, token_pos, name, type,
1640 param_type, param_value);
1641}
1642
1643void ScopeBuilder::AddExceptionVariable(
1644 GrowableArray<LocalVariable*>* variables,
1645 const char* prefix,
1646 intptr_t nesting_depth) {
1647 LocalVariable* v = NULL;
1648
1649 // If we are inside a function with yield points then Kernel transformer
1650 // could have lifted some of the auxiliary exception variables into the
1651 // context to preserve them across yield points because they might
1652 // be needed for rethrow.
1653 // Check if it did and capture such variables instead of introducing
1654 // new local ones.
1655 // Note: function that wrap kSyncYielding function does not contain
1656 // its own try/catches.
1657 if (current_function_async_marker_ == FunctionNodeHelper::kSyncYielding) {
1658 ASSERT(current_function_scope_->parent() != NULL);
1659 v = current_function_scope_->parent()->LocalLookupVariable(
1660 GenerateName(prefix, nesting_depth - 1));
1661 if (v != NULL) {
1662 scope_->CaptureVariable(v);
1663 }
1664 }
1665
1666 // No need to create variables for try/catch-statements inside
1667 // nested functions.
1668 if (depth_.function_ > 0) return;
1669 if (variables->length() >= nesting_depth) return;
1670
1671 // If variable was not lifted by the transformer introduce a new
1672 // one into the current function scope.
1673 if (v == NULL) {
1674 v = MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1675 GenerateName(prefix, nesting_depth - 1),
1676 AbstractType::dynamic_type());
1677
1678 // If transformer did not lift the variable then there is no need
1679 // to lift it into the context when we encouter a YieldStatement.
1680 v->set_is_forced_stack();
1681 current_function_scope_->AddVariable(v);
1682 }
1683
1684 variables->Add(v);
1685}
1686
1687void ScopeBuilder::FinalizeExceptionVariable(
1688 GrowableArray<LocalVariable*>* variables,
1689 GrowableArray<LocalVariable*>* raw_variables,
1690 const String& symbol,
1691 intptr_t nesting_depth) {
1692 // No need to create variables for try/catch-statements inside
1693 // nested functions.
1694 if (depth_.function_ > 0) return;
1695
1696 LocalVariable* variable = (*variables)[nesting_depth - 1];
1697 LocalVariable* raw_variable;
1698 if (variable->is_captured()) {
1699 raw_variable =
1700 new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1701 symbol, AbstractType::dynamic_type());
1702 raw_variable->set_is_forced_stack();
1703 const bool ok = scope_->AddVariable(raw_variable);
1704 ASSERT(ok);
1705 } else {
1706 raw_variable = variable;
1707 }
1708 raw_variables->EnsureLength(nesting_depth, nullptr);
1709 (*raw_variables)[nesting_depth - 1] = raw_variable;
1710}
1711
1712void ScopeBuilder::AddTryVariables() {
1713 AddExceptionVariable(&result_->catch_context_variables,
1714 ":saved_try_context_var", depth_.try_);
1715}
1716
1717void ScopeBuilder::AddCatchVariables() {
1718 AddExceptionVariable(&result_->exception_variables, ":exception",
1719 depth_.catch_);
1720 AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace",
1721 depth_.catch_);
1722}
1723
1724void ScopeBuilder::FinalizeCatchVariables() {
1725 const intptr_t unique_id = result_->raw_variable_counter_++;
1726 FinalizeExceptionVariable(
1727 &result_->exception_variables, &result_->raw_exception_variables,
1728 GenerateName(":raw_exception", unique_id), depth_.catch_);
1729 FinalizeExceptionVariable(
1730 &result_->stack_trace_variables, &result_->raw_stack_trace_variables,
1731 GenerateName(":raw_stacktrace", unique_id), depth_.catch_);
1732}
1733
1734void ScopeBuilder::AddIteratorVariable() {
1735 if (depth_.function_ > 0) return;
1736 if (result_->iterator_variables.length() >= depth_.for_in_) return;
1737
1738 ASSERT(result_->iterator_variables.length() == depth_.for_in_ - 1);
1739 LocalVariable* iterator =
1740 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1741 GenerateName(":iterator", depth_.for_in_ - 1),
1742 AbstractType::dynamic_type());
1743 current_function_scope_->AddVariable(iterator);
1744 result_->iterator_variables.Add(iterator);
1745}
1746
1747void ScopeBuilder::AddSwitchVariable() {
1748 if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) {
1749 LocalVariable* variable =
1750 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1751 Symbols::SwitchExpr(), AbstractType::dynamic_type());
1752 variable->set_is_forced_stack();
1753 current_function_scope_->AddVariable(variable);
1754 result_->switch_variable = variable;
1755 }
1756}
1757
1758void ScopeBuilder::VisitVariableGet(intptr_t declaration_binary_offset) {
1759 LocalVariable* variable = LookupVariable(declaration_binary_offset);
1760 if (variable->is_late()) {
1761 // Late variable initializer expressions may also contain local variables
1762 // that need to be captured.
1763 AlternativeReadingScope alt(&helper_.reader_, variable->late_init_offset());
1764 if (helper_.ReadTag() != kNothing) {
1765 VisitExpression();
1766 }
1767 }
1768}
1769
1770LocalVariable* ScopeBuilder::LookupVariable(
1771 intptr_t declaration_binary_offset) {
1772 LocalVariable* variable = result_->locals.Lookup(declaration_binary_offset);
1773 if (variable == NULL) {
1774 // We have not seen a declaration of the variable, so it must be the
1775 // case that we are compiling a nested function and the variable is
1776 // declared in an outer scope. In that case, look it up in the scope by
1777 // name and add it to the variable map to simplify later lookup.
1778 ASSERT(current_function_scope_->parent() != NULL);
1779 StringIndex var_name = GetNameFromVariableDeclaration(
1780 declaration_binary_offset - helper_.data_program_offset_,
1781 parsed_function_->function());
1782
1783 const String& name = H.DartSymbolObfuscate(var_name);
1784 variable = current_function_scope_->parent()->LookupVariable(name, true);
1785 ASSERT(variable != NULL);
1786 result_->locals.Insert(declaration_binary_offset, variable);
1787 }
1788
1789 if (variable->owner()->function_level() < scope_->function_level()) {
1790 // We call `LocalScope->CaptureVariable(variable)` in two scenarios for two
1791 // different reasons:
1792 // Scenario 1:
1793 // We need to know which variables defined in this function
1794 // are closed over by nested closures in order to ensure we will
1795 // create a [Context] object of appropriate size and store captured
1796 // variables there instead of the stack.
1797 // Scenario 2:
1798 // We need to find out which variables defined in enclosing functions
1799 // are closed over by this function/closure or nested closures. This
1800 // is necessary in order to build a fat flattened [ContextScope]
1801 // object.
1802 scope_->CaptureVariable(variable);
1803 } else {
1804 ASSERT(variable->owner()->function_level() == scope_->function_level());
1805 }
1806 return variable;
1807}
1808
1809StringIndex ScopeBuilder::GetNameFromVariableDeclaration(
1810 intptr_t kernel_offset,
1811 const Function& function) {
1812 ExternalTypedData& kernel_data =
1813 ExternalTypedData::Handle(Z, function.KernelData());
1814 ASSERT(!kernel_data.IsNull());
1815
1816 // Temporarily go to the variable declaration, read the name.
1817 AlternativeReadingScopeWithNewData alt(&helper_.reader_, &kernel_data,
1818 kernel_offset);
1819 VariableDeclarationHelper helper(&helper_);
1820 helper.ReadUntilIncluding(VariableDeclarationHelper::kNameIndex);
1821 return helper.name_index_;
1822}
1823
1824const String& ScopeBuilder::GenerateName(const char* prefix, intptr_t suffix) {
1825 char name[64];
1826 Utils::SNPrint(name, 64, "%s%" Pd "", prefix, suffix);
1827 return H.DartSymbolObfuscate(name);
1828}
1829
1830void ScopeBuilder::HandleLoadReceiver() {
1831 if (!parsed_function_->has_receiver_var() &&
1832 current_function_scope_->parent() != nullptr) {
1833 // Lazily populate receiver variable using the parent function scope.
1834 parsed_function_->set_receiver_var(
1835 current_function_scope_->parent()->LookupVariable(Symbols::This(),
1836 true));
1837 }
1838
1839 if ((current_function_scope_->parent() != nullptr) ||
1840 (scope_->function_level() > 0)) {
1841 // Every scope we use the [receiver] from needs to be notified of the usage
1842 // in order to ensure that preserving the context scope on that particular
1843 // use-site also includes the [receiver].
1844 scope_->CaptureVariable(parsed_function_->receiver_var());
1845 }
1846}
1847
1848void ScopeBuilder::HandleSpecialLoad(LocalVariable** variable,
1849 const String& symbol) {
1850 if (current_function_scope_->parent() != NULL) {
1851 // We are building the scope tree of a closure function and saw [node]. We
1852 // lazily populate the variable using the parent function scope.
1853 if (*variable == NULL) {
1854 *variable =
1855 current_function_scope_->parent()->LookupVariable(symbol, true);
1856 ASSERT(*variable != NULL);
1857 }
1858 }
1859
1860 if ((current_function_scope_->parent() != NULL) ||
1861 (scope_->function_level() > 0)) {
1862 // Every scope we use the [variable] from needs to be notified of the usage
1863 // in order to ensure that preserving the context scope on that particular
1864 // use-site also includes the [variable].
1865 scope_->CaptureVariable(*variable);
1866 }
1867}
1868
1869void ScopeBuilder::LookupCapturedVariableByName(LocalVariable** variable,
1870 const String& name) {
1871 if (*variable == NULL) {
1872 *variable = scope_->LookupVariable(name, true);
1873 ASSERT(*variable != NULL);
1874 scope_->CaptureVariable(*variable);
1875 }
1876}
1877
1878} // namespace kernel
1879} // namespace dart
1880