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 | |
10 | namespace dart { |
11 | namespace 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. |
20 | bool 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 | |
36 | ScopeBuilder::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 | |
64 | ScopeBuildingResult* 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 | ¶meter_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 | |
451 | void 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 | |
458 | void 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 | |
479 | void 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 | |
520 | void ScopeBuilder::VisitProcedure() { |
521 | ProcedureHelper procedure_helper(&helper_); |
522 | procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); |
523 | if (helper_.ReadTag() == kSomething) { |
524 | VisitFunctionNode(); |
525 | } |
526 | } |
527 | |
528 | void 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 | |
538 | void 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 | |
646 | void 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 | |
678 | void 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 | |
978 | void 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 | |
1264 | void 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 | |
1287 | void 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 | |
1339 | AbstractType& 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 | |
1347 | void 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 | |
1380 | void 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 | |
1391 | void 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 | |
1436 | void 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 | |
1470 | void 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 | |
1519 | void 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 | |
1525 | void 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 | |
1532 | void 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 | |
1549 | void 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, ¶meter_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 | |
1625 | LocalVariable* 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 = ¶m_type_md->constant_value; |
1637 | } |
1638 | } |
1639 | return new (Z) LocalVariable(declaration_pos, token_pos, name, type, |
1640 | param_type, param_value); |
1641 | } |
1642 | |
1643 | void 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 | |
1687 | void 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 | |
1712 | void ScopeBuilder::AddTryVariables() { |
1713 | AddExceptionVariable(&result_->catch_context_variables, |
1714 | ":saved_try_context_var" , depth_.try_); |
1715 | } |
1716 | |
1717 | void ScopeBuilder::AddCatchVariables() { |
1718 | AddExceptionVariable(&result_->exception_variables, ":exception" , |
1719 | depth_.catch_); |
1720 | AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace" , |
1721 | depth_.catch_); |
1722 | } |
1723 | |
1724 | void 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 | |
1734 | void 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 | |
1747 | void 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 | |
1758 | void 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 | |
1770 | LocalVariable* 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 | |
1809 | StringIndex 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 | |
1824 | const 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 | |
1830 | void 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 | |
1848 | void 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 | |
1869 | void 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 | |