| 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 | |