| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/scopes.h" | 5 #include "vm/scopes.h" |
| 6 | 6 |
| 7 #include "vm/object.h" | 7 #include "vm/object.h" |
| 8 #include "vm/stack_frame.h" | 8 #include "vm/stack_frame.h" |
| 9 #include "vm/symbols.h" | 9 #include "vm/symbols.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 DEFINE_FLAG(bool, | 13 DEFINE_FLAG(bool, |
| 14 share_enclosing_context, | 14 share_enclosing_context, |
| 15 true, | 15 true, |
| 16 "Allocate captured variables in the existing context of an " | 16 "Allocate captured variables in the existing context of an " |
| 17 "enclosing scope (up to innermost loop) and spare the allocation " | 17 "enclosing scope (up to innermost loop) and spare the allocation " |
| 18 "of a local context."); | 18 "of a local context."); |
| 19 | 19 |
| 20 int SourceLabel::FunctionLevel() const { | 20 int SourceLabel::FunctionLevel() const { |
| 21 ASSERT(owner() != NULL); | 21 ASSERT(owner() != NULL); |
| 22 return owner()->function_level(); | 22 return owner()->function_level(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 | |
| 26 LocalScope::LocalScope(LocalScope* parent, int function_level, int loop_level) | 25 LocalScope::LocalScope(LocalScope* parent, int function_level, int loop_level) |
| 27 : parent_(parent), | 26 : parent_(parent), |
| 28 child_(NULL), | 27 child_(NULL), |
| 29 sibling_(NULL), | 28 sibling_(NULL), |
| 30 function_level_(function_level), | 29 function_level_(function_level), |
| 31 loop_level_(loop_level), | 30 loop_level_(loop_level), |
| 32 context_level_(LocalScope::kUnitializedContextLevel), | 31 context_level_(LocalScope::kUnitializedContextLevel), |
| 33 num_context_variables_(0), | 32 num_context_variables_(0), |
| 34 begin_token_pos_(TokenPosition::kNoSourcePos), | 33 begin_token_pos_(TokenPosition::kNoSourcePos), |
| 35 end_token_pos_(TokenPosition::kNoSourcePos), | 34 end_token_pos_(TokenPosition::kNoSourcePos), |
| 36 variables_(), | 35 variables_(), |
| 37 labels_(), | 36 labels_(), |
| 38 referenced_() { | 37 referenced_() { |
| 39 // Hook this node into the children of the parent, unless the parent has a | 38 // Hook this node into the children of the parent, unless the parent has a |
| 40 // different function_level, since the local scope of a nested function can | 39 // different function_level, since the local scope of a nested function can |
| 41 // be discarded after it has been parsed. | 40 // be discarded after it has been parsed. |
| 42 if ((parent != NULL) && (parent->function_level() == function_level)) { | 41 if ((parent != NULL) && (parent->function_level() == function_level)) { |
| 43 sibling_ = parent->child_; | 42 sibling_ = parent->child_; |
| 44 parent->child_ = this; | 43 parent->child_ = this; |
| 45 } | 44 } |
| 46 } | 45 } |
| 47 | 46 |
| 48 | |
| 49 bool LocalScope::IsNestedWithin(LocalScope* scope) const { | 47 bool LocalScope::IsNestedWithin(LocalScope* scope) const { |
| 50 const LocalScope* current_scope = this; | 48 const LocalScope* current_scope = this; |
| 51 while (current_scope != NULL) { | 49 while (current_scope != NULL) { |
| 52 if (current_scope == scope) { | 50 if (current_scope == scope) { |
| 53 return true; | 51 return true; |
| 54 } | 52 } |
| 55 current_scope = current_scope->parent(); | 53 current_scope = current_scope->parent(); |
| 56 } | 54 } |
| 57 return false; | 55 return false; |
| 58 } | 56 } |
| 59 | 57 |
| 60 | |
| 61 bool LocalScope::AddVariable(LocalVariable* variable) { | 58 bool LocalScope::AddVariable(LocalVariable* variable) { |
| 62 ASSERT(variable != NULL); | 59 ASSERT(variable != NULL); |
| 63 if (LocalLookupVariable(variable->name()) != NULL) { | 60 if (LocalLookupVariable(variable->name()) != NULL) { |
| 64 return false; | 61 return false; |
| 65 } | 62 } |
| 66 variables_.Add(variable); | 63 variables_.Add(variable); |
| 67 if (variable->owner() == NULL) { | 64 if (variable->owner() == NULL) { |
| 68 // Variables must be added to their owner scope first. Subsequent calls | 65 // Variables must be added to their owner scope first. Subsequent calls |
| 69 // to 'add' treat the variable as an alias. | 66 // to 'add' treat the variable as an alias. |
| 70 variable->set_owner(this); | 67 variable->set_owner(this); |
| 71 } | 68 } |
| 72 return true; | 69 return true; |
| 73 } | 70 } |
| 74 | 71 |
| 75 | |
| 76 bool LocalScope::InsertParameterAt(intptr_t pos, LocalVariable* parameter) { | 72 bool LocalScope::InsertParameterAt(intptr_t pos, LocalVariable* parameter) { |
| 77 ASSERT(parameter != NULL); | 73 ASSERT(parameter != NULL); |
| 78 if (LocalLookupVariable(parameter->name()) != NULL) { | 74 if (LocalLookupVariable(parameter->name()) != NULL) { |
| 79 return false; | 75 return false; |
| 80 } | 76 } |
| 81 variables_.InsertAt(pos, parameter); | 77 variables_.InsertAt(pos, parameter); |
| 82 // InsertParameterAt is not used to add aliases of parameters. | 78 // InsertParameterAt is not used to add aliases of parameters. |
| 83 ASSERT(parameter->owner() == NULL); | 79 ASSERT(parameter->owner() == NULL); |
| 84 parameter->set_owner(this); | 80 parameter->set_owner(this); |
| 85 return true; | 81 return true; |
| 86 } | 82 } |
| 87 | 83 |
| 88 | |
| 89 bool LocalScope::AddLabel(SourceLabel* label) { | 84 bool LocalScope::AddLabel(SourceLabel* label) { |
| 90 if (LocalLookupLabel(label->name()) != NULL) { | 85 if (LocalLookupLabel(label->name()) != NULL) { |
| 91 return false; | 86 return false; |
| 92 } | 87 } |
| 93 labels_.Add(label); | 88 labels_.Add(label); |
| 94 if (label->owner() == NULL) { | 89 if (label->owner() == NULL) { |
| 95 // Labels must be added to their owner scope first. Subsequent calls | 90 // Labels must be added to their owner scope first. Subsequent calls |
| 96 // to 'add' treat the label as an alias. | 91 // to 'add' treat the label as an alias. |
| 97 label->set_owner(this); | 92 label->set_owner(this); |
| 98 } | 93 } |
| 99 return true; | 94 return true; |
| 100 } | 95 } |
| 101 | 96 |
| 102 | |
| 103 void LocalScope::MoveLabel(SourceLabel* label) { | 97 void LocalScope::MoveLabel(SourceLabel* label) { |
| 104 ASSERT(LocalLookupLabel(label->name()) == NULL); | 98 ASSERT(LocalLookupLabel(label->name()) == NULL); |
| 105 ASSERT(label->kind() == SourceLabel::kForward); | 99 ASSERT(label->kind() == SourceLabel::kForward); |
| 106 labels_.Add(label); | 100 labels_.Add(label); |
| 107 label->set_owner(this); | 101 label->set_owner(this); |
| 108 } | 102 } |
| 109 | 103 |
| 110 | |
| 111 NameReference* LocalScope::FindReference(const String& name) const { | 104 NameReference* LocalScope::FindReference(const String& name) const { |
| 112 ASSERT(name.IsSymbol()); | 105 ASSERT(name.IsSymbol()); |
| 113 intptr_t num_references = referenced_.length(); | 106 intptr_t num_references = referenced_.length(); |
| 114 for (intptr_t i = 0; i < num_references; i++) { | 107 for (intptr_t i = 0; i < num_references; i++) { |
| 115 if (name.raw() == referenced_[i]->name().raw()) { | 108 if (name.raw() == referenced_[i]->name().raw()) { |
| 116 return referenced_[i]; | 109 return referenced_[i]; |
| 117 } | 110 } |
| 118 } | 111 } |
| 119 return NULL; | 112 return NULL; |
| 120 } | 113 } |
| 121 | 114 |
| 122 | |
| 123 void LocalScope::AddReferencedName(TokenPosition token_pos, | 115 void LocalScope::AddReferencedName(TokenPosition token_pos, |
| 124 const String& name) { | 116 const String& name) { |
| 125 if (LocalLookupVariable(name) != NULL) { | 117 if (LocalLookupVariable(name) != NULL) { |
| 126 return; | 118 return; |
| 127 } | 119 } |
| 128 NameReference* ref = FindReference(name); | 120 NameReference* ref = FindReference(name); |
| 129 if (ref != NULL) { | 121 if (ref != NULL) { |
| 130 ref->set_token_pos(token_pos); | 122 ref->set_token_pos(token_pos); |
| 131 return; | 123 return; |
| 132 } | 124 } |
| 133 ref = new NameReference(token_pos, name); | 125 ref = new NameReference(token_pos, name); |
| 134 referenced_.Add(ref); | 126 referenced_.Add(ref); |
| 135 // Add name reference in innermost enclosing scopes that do not | 127 // Add name reference in innermost enclosing scopes that do not |
| 136 // define a local variable with this name. | 128 // define a local variable with this name. |
| 137 LocalScope* scope = this->parent(); | 129 LocalScope* scope = this->parent(); |
| 138 while (scope != NULL && (scope->LocalLookupVariable(name) == NULL)) { | 130 while (scope != NULL && (scope->LocalLookupVariable(name) == NULL)) { |
| 139 scope->referenced_.Add(ref); | 131 scope->referenced_.Add(ref); |
| 140 scope = scope->parent(); | 132 scope = scope->parent(); |
| 141 } | 133 } |
| 142 } | 134 } |
| 143 | 135 |
| 144 | |
| 145 TokenPosition LocalScope::PreviousReferencePos(const String& name) const { | 136 TokenPosition LocalScope::PreviousReferencePos(const String& name) const { |
| 146 NameReference* ref = FindReference(name); | 137 NameReference* ref = FindReference(name); |
| 147 if (ref != NULL) { | 138 if (ref != NULL) { |
| 148 return ref->token_pos(); | 139 return ref->token_pos(); |
| 149 } | 140 } |
| 150 return TokenPosition::kNoSource; | 141 return TokenPosition::kNoSource; |
| 151 } | 142 } |
| 152 | 143 |
| 153 | |
| 154 void LocalScope::AllocateContextVariable(LocalVariable* variable, | 144 void LocalScope::AllocateContextVariable(LocalVariable* variable, |
| 155 LocalScope** context_owner) { | 145 LocalScope** context_owner) { |
| 156 ASSERT(variable->is_captured()); | 146 ASSERT(variable->is_captured()); |
| 157 ASSERT(variable->owner() == this); | 147 ASSERT(variable->owner() == this); |
| 158 // The context level in the owner scope of a captured variable indicates at | 148 // The context level in the owner scope of a captured variable indicates at |
| 159 // code generation time how far to walk up the context chain in order to | 149 // code generation time how far to walk up the context chain in order to |
| 160 // access the variable from the current context level. | 150 // access the variable from the current context level. |
| 161 if ((*context_owner) == NULL) { | 151 if ((*context_owner) == NULL) { |
| 162 ASSERT(num_context_variables_ == 0); | 152 ASSERT(num_context_variables_ == 0); |
| 163 // This scope becomes the current context owner. | 153 // This scope becomes the current context owner. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 184 if (!HasContextLevel()) { | 174 if (!HasContextLevel()) { |
| 185 ASSERT(variable->owner() != *context_owner); | 175 ASSERT(variable->owner() != *context_owner); |
| 186 set_context_level((*context_owner)->context_level()); | 176 set_context_level((*context_owner)->context_level()); |
| 187 } else { | 177 } else { |
| 188 ASSERT(context_level() == (*context_owner)->context_level()); | 178 ASSERT(context_level() == (*context_owner)->context_level()); |
| 189 } | 179 } |
| 190 } | 180 } |
| 191 variable->set_index((*context_owner)->num_context_variables_++); | 181 variable->set_index((*context_owner)->num_context_variables_++); |
| 192 } | 182 } |
| 193 | 183 |
| 194 | |
| 195 int LocalScope::AllocateVariables(int first_parameter_index, | 184 int LocalScope::AllocateVariables(int first_parameter_index, |
| 196 int num_parameters, | 185 int num_parameters, |
| 197 int first_frame_index, | 186 int first_frame_index, |
| 198 LocalScope* context_owner, | 187 LocalScope* context_owner, |
| 199 bool* found_captured_variables) { | 188 bool* found_captured_variables) { |
| 200 // We should not allocate variables of nested functions while compiling an | 189 // We should not allocate variables of nested functions while compiling an |
| 201 // enclosing function. | 190 // enclosing function. |
| 202 ASSERT(function_level() == 0); | 191 ASSERT(function_level() == 0); |
| 203 ASSERT(num_parameters >= 0); | 192 ASSERT(num_parameters >= 0); |
| 204 // Parameters must be listed first and must all appear in the top scope. | 193 // Parameters must be listed first and must all appear in the top scope. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 dummy_parameter_index, num_parameters_in_child, frame_index, | 248 dummy_parameter_index, num_parameters_in_child, frame_index, |
| 260 context_owner, found_captured_variables); | 249 context_owner, found_captured_variables); |
| 261 if (child_frame_index < min_frame_index) { | 250 if (child_frame_index < min_frame_index) { |
| 262 min_frame_index = child_frame_index; | 251 min_frame_index = child_frame_index; |
| 263 } | 252 } |
| 264 child = child->sibling(); | 253 child = child->sibling(); |
| 265 } | 254 } |
| 266 return min_frame_index; | 255 return min_frame_index; |
| 267 } | 256 } |
| 268 | 257 |
| 269 | |
| 270 // The parser creates internal variables that start with ":" | 258 // The parser creates internal variables that start with ":" |
| 271 static bool IsFilteredIdentifier(const String& str) { | 259 static bool IsFilteredIdentifier(const String& str) { |
| 272 ASSERT(str.Length() > 0); | 260 ASSERT(str.Length() > 0); |
| 273 if (str.raw() == Symbols::AsyncOperation().raw()) { | 261 if (str.raw() == Symbols::AsyncOperation().raw()) { |
| 274 // Keep :async_op for asynchronous debugging. | 262 // Keep :async_op for asynchronous debugging. |
| 275 return false; | 263 return false; |
| 276 } | 264 } |
| 277 if (str.raw() == Symbols::AsyncCompleter().raw()) { | 265 if (str.raw() == Symbols::AsyncCompleter().raw()) { |
| 278 // Keep :async_completer for asynchronous debugging. | 266 // Keep :async_completer for asynchronous debugging. |
| 279 return false; | 267 return false; |
| 280 } | 268 } |
| 281 if (str.raw() == Symbols::ControllerStream().raw()) { | 269 if (str.raw() == Symbols::ControllerStream().raw()) { |
| 282 // Keep :controller_stream for asynchronous debugging. | 270 // Keep :controller_stream for asynchronous debugging. |
| 283 return false; | 271 return false; |
| 284 } | 272 } |
| 285 if (str.raw() == Symbols::AwaitJumpVar().raw()) { | 273 if (str.raw() == Symbols::AwaitJumpVar().raw()) { |
| 286 // Keep :await_jump_var for asynchronous debugging. | 274 // Keep :await_jump_var for asynchronous debugging. |
| 287 return false; | 275 return false; |
| 288 } | 276 } |
| 289 if (str.raw() == Symbols::AsyncStackTraceVar().raw()) { | 277 if (str.raw() == Symbols::AsyncStackTraceVar().raw()) { |
| 290 // Keep :async_stack_trace for asynchronous debugging. | 278 // Keep :async_stack_trace for asynchronous debugging. |
| 291 return false; | 279 return false; |
| 292 } | 280 } |
| 293 return str.CharAt(0) == ':'; | 281 return str.CharAt(0) == ':'; |
| 294 } | 282 } |
| 295 | 283 |
| 296 | |
| 297 RawLocalVarDescriptors* LocalScope::GetVarDescriptors( | 284 RawLocalVarDescriptors* LocalScope::GetVarDescriptors( |
| 298 const Function& func, | 285 const Function& func, |
| 299 ZoneGrowableArray<intptr_t>* context_level_array) { | 286 ZoneGrowableArray<intptr_t>* context_level_array) { |
| 300 GrowableArray<VarDesc> vars(8); | 287 GrowableArray<VarDesc> vars(8); |
| 301 | 288 |
| 302 // Record deopt-id -> context-level mappings, using ranges of deopt-ids with | 289 // Record deopt-id -> context-level mappings, using ranges of deopt-ids with |
| 303 // the same context-level. [context_level_array] contains (deopt_id, | 290 // the same context-level. [context_level_array] contains (deopt_id, |
| 304 // context_level) tuples. | 291 // context_level) tuples. |
| 305 for (intptr_t start = 0; start < context_level_array->length();) { | 292 for (intptr_t start = 0; start < context_level_array->length();) { |
| 306 intptr_t start_deopt_id = (*context_level_array)[start]; | 293 intptr_t start_deopt_id = (*context_level_array)[start]; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 return Object::empty_var_descriptors().raw(); | 351 return Object::empty_var_descriptors().raw(); |
| 365 } | 352 } |
| 366 const LocalVarDescriptors& var_desc = | 353 const LocalVarDescriptors& var_desc = |
| 367 LocalVarDescriptors::Handle(LocalVarDescriptors::New(vars.length())); | 354 LocalVarDescriptors::Handle(LocalVarDescriptors::New(vars.length())); |
| 368 for (int i = 0; i < vars.length(); i++) { | 355 for (int i = 0; i < vars.length(); i++) { |
| 369 var_desc.SetVar(i, *(vars[i].name), &vars[i].info); | 356 var_desc.SetVar(i, *(vars[i].name), &vars[i].info); |
| 370 } | 357 } |
| 371 return var_desc.raw(); | 358 return var_desc.raw(); |
| 372 } | 359 } |
| 373 | 360 |
| 374 | |
| 375 // Add visible variables that are declared in this scope to vars, then | 361 // Add visible variables that are declared in this scope to vars, then |
| 376 // collect visible variables of children, followed by siblings. | 362 // collect visible variables of children, followed by siblings. |
| 377 void LocalScope::CollectLocalVariables(GrowableArray<VarDesc>* vars, | 363 void LocalScope::CollectLocalVariables(GrowableArray<VarDesc>* vars, |
| 378 int16_t* scope_id) { | 364 int16_t* scope_id) { |
| 379 (*scope_id)++; | 365 (*scope_id)++; |
| 380 for (int i = 0; i < this->variables_.length(); i++) { | 366 for (int i = 0; i < this->variables_.length(); i++) { |
| 381 LocalVariable* var = variables_[i]; | 367 LocalVariable* var = variables_[i]; |
| 382 if ((var->owner() == this) && !var->is_invisible()) { | 368 if ((var->owner() == this) && !var->is_invisible()) { |
| 383 if (var->name().raw() == Symbols::CurrentContextVar().raw()) { | 369 if (var->name().raw() == Symbols::CurrentContextVar().raw()) { |
| 384 // This is the local variable in which the function saves its | 370 // This is the local variable in which the function saves its |
| (...skipping 28 matching lines...) Expand all Loading... |
| 413 } | 399 } |
| 414 } | 400 } |
| 415 } | 401 } |
| 416 LocalScope* child = this->child(); | 402 LocalScope* child = this->child(); |
| 417 while (child != NULL) { | 403 while (child != NULL) { |
| 418 child->CollectLocalVariables(vars, scope_id); | 404 child->CollectLocalVariables(vars, scope_id); |
| 419 child = child->sibling(); | 405 child = child->sibling(); |
| 420 } | 406 } |
| 421 } | 407 } |
| 422 | 408 |
| 423 | |
| 424 SourceLabel* LocalScope::LocalLookupLabel(const String& name) const { | 409 SourceLabel* LocalScope::LocalLookupLabel(const String& name) const { |
| 425 ASSERT(name.IsSymbol()); | 410 ASSERT(name.IsSymbol()); |
| 426 for (intptr_t i = 0; i < labels_.length(); i++) { | 411 for (intptr_t i = 0; i < labels_.length(); i++) { |
| 427 SourceLabel* label = labels_[i]; | 412 SourceLabel* label = labels_[i]; |
| 428 if (label->name().raw() == name.raw()) { | 413 if (label->name().raw() == name.raw()) { |
| 429 return label; | 414 return label; |
| 430 } | 415 } |
| 431 } | 416 } |
| 432 return NULL; | 417 return NULL; |
| 433 } | 418 } |
| 434 | 419 |
| 435 | |
| 436 LocalVariable* LocalScope::LocalLookupVariable(const String& name) const { | 420 LocalVariable* LocalScope::LocalLookupVariable(const String& name) const { |
| 437 ASSERT(name.IsSymbol()); | 421 ASSERT(name.IsSymbol()); |
| 438 for (intptr_t i = 0; i < variables_.length(); i++) { | 422 for (intptr_t i = 0; i < variables_.length(); i++) { |
| 439 LocalVariable* var = variables_[i]; | 423 LocalVariable* var = variables_[i]; |
| 440 ASSERT(var->name().IsSymbol()); | 424 ASSERT(var->name().IsSymbol()); |
| 441 if (var->name().raw() == name.raw()) { | 425 if (var->name().raw() == name.raw()) { |
| 442 return var; | 426 return var; |
| 443 } | 427 } |
| 444 } | 428 } |
| 445 return NULL; | 429 return NULL; |
| 446 } | 430 } |
| 447 | 431 |
| 448 | |
| 449 LocalVariable* LocalScope::LookupVariable(const String& name, bool test_only) { | 432 LocalVariable* LocalScope::LookupVariable(const String& name, bool test_only) { |
| 450 LocalScope* current_scope = this; | 433 LocalScope* current_scope = this; |
| 451 while (current_scope != NULL) { | 434 while (current_scope != NULL) { |
| 452 LocalVariable* var = current_scope->LocalLookupVariable(name); | 435 LocalVariable* var = current_scope->LocalLookupVariable(name); |
| 453 // If testing only, return the variable even if invisible. | 436 // If testing only, return the variable even if invisible. |
| 454 if ((var != NULL) && (!var->is_invisible_ || test_only)) { | 437 if ((var != NULL) && (!var->is_invisible_ || test_only)) { |
| 455 if (!test_only && (var->owner()->function_level() != function_level())) { | 438 if (!test_only && (var->owner()->function_level() != function_level())) { |
| 456 CaptureVariable(var); | 439 CaptureVariable(var); |
| 457 } | 440 } |
| 458 return var; | 441 return var; |
| 459 } | 442 } |
| 460 current_scope = current_scope->parent(); | 443 current_scope = current_scope->parent(); |
| 461 } | 444 } |
| 462 return NULL; | 445 return NULL; |
| 463 } | 446 } |
| 464 | 447 |
| 465 | |
| 466 void LocalScope::CaptureVariable(LocalVariable* variable) { | 448 void LocalScope::CaptureVariable(LocalVariable* variable) { |
| 467 ASSERT(variable != NULL); | 449 ASSERT(variable != NULL); |
| 468 // The variable must exist in an enclosing scope, not necessarily in this one. | 450 // The variable must exist in an enclosing scope, not necessarily in this one. |
| 469 variable->set_is_captured(); | 451 variable->set_is_captured(); |
| 470 const int variable_function_level = variable->owner()->function_level(); | 452 const int variable_function_level = variable->owner()->function_level(); |
| 471 LocalScope* scope = this; | 453 LocalScope* scope = this; |
| 472 while (scope->function_level() != variable_function_level) { | 454 while (scope->function_level() != variable_function_level) { |
| 473 // Insert an alias of the variable in the top scope of each function | 455 // Insert an alias of the variable in the top scope of each function |
| 474 // level so that the variable is found in the context. | 456 // level so that the variable is found in the context. |
| 475 LocalScope* parent_scope = scope->parent(); | 457 LocalScope* parent_scope = scope->parent(); |
| 476 while ((parent_scope != NULL) && | 458 while ((parent_scope != NULL) && |
| 477 (parent_scope->function_level() == scope->function_level())) { | 459 (parent_scope->function_level() == scope->function_level())) { |
| 478 scope = parent_scope; | 460 scope = parent_scope; |
| 479 parent_scope = scope->parent(); | 461 parent_scope = scope->parent(); |
| 480 } | 462 } |
| 481 // An alias may already have been added in this scope, and in that case, | 463 // An alias may already have been added in this scope, and in that case, |
| 482 // in parent scopes as needed. If so, we are done. | 464 // in parent scopes as needed. If so, we are done. |
| 483 if (!scope->AddVariable(variable)) { | 465 if (!scope->AddVariable(variable)) { |
| 484 return; | 466 return; |
| 485 } | 467 } |
| 486 ASSERT(variable->owner() != scope); // Item is an alias. | 468 ASSERT(variable->owner() != scope); // Item is an alias. |
| 487 scope = parent_scope; | 469 scope = parent_scope; |
| 488 } | 470 } |
| 489 } | 471 } |
| 490 | 472 |
| 491 | |
| 492 SourceLabel* LocalScope::LookupLabel(const String& name) { | 473 SourceLabel* LocalScope::LookupLabel(const String& name) { |
| 493 LocalScope* current_scope = this; | 474 LocalScope* current_scope = this; |
| 494 while (current_scope != NULL) { | 475 while (current_scope != NULL) { |
| 495 SourceLabel* label = current_scope->LocalLookupLabel(name); | 476 SourceLabel* label = current_scope->LocalLookupLabel(name); |
| 496 if (label != NULL) { | 477 if (label != NULL) { |
| 497 return label; | 478 return label; |
| 498 } | 479 } |
| 499 current_scope = current_scope->parent(); | 480 current_scope = current_scope->parent(); |
| 500 } | 481 } |
| 501 return NULL; | 482 return NULL; |
| 502 } | 483 } |
| 503 | 484 |
| 504 | |
| 505 SourceLabel* LocalScope::LookupInnermostLabel(Token::Kind jump_kind) { | 485 SourceLabel* LocalScope::LookupInnermostLabel(Token::Kind jump_kind) { |
| 506 ASSERT((jump_kind == Token::kCONTINUE) || (jump_kind == Token::kBREAK)); | 486 ASSERT((jump_kind == Token::kCONTINUE) || (jump_kind == Token::kBREAK)); |
| 507 LocalScope* current_scope = this; | 487 LocalScope* current_scope = this; |
| 508 while (current_scope != NULL) { | 488 while (current_scope != NULL) { |
| 509 for (intptr_t i = 0; i < current_scope->labels_.length(); i++) { | 489 for (intptr_t i = 0; i < current_scope->labels_.length(); i++) { |
| 510 SourceLabel* label = current_scope->labels_[i]; | 490 SourceLabel* label = current_scope->labels_[i]; |
| 511 if ((label->kind() == SourceLabel::kWhile) || | 491 if ((label->kind() == SourceLabel::kWhile) || |
| 512 (label->kind() == SourceLabel::kFor) || | 492 (label->kind() == SourceLabel::kFor) || |
| 513 (label->kind() == SourceLabel::kDoWhile) || | 493 (label->kind() == SourceLabel::kDoWhile) || |
| 514 ((jump_kind == Token::kBREAK) && | 494 ((jump_kind == Token::kBREAK) && |
| 515 (label->kind() == SourceLabel::kSwitch))) { | 495 (label->kind() == SourceLabel::kSwitch))) { |
| 516 return label; | 496 return label; |
| 517 } | 497 } |
| 518 } | 498 } |
| 519 current_scope = current_scope->parent(); | 499 current_scope = current_scope->parent(); |
| 520 } | 500 } |
| 521 return NULL; | 501 return NULL; |
| 522 } | 502 } |
| 523 | 503 |
| 524 | |
| 525 LocalScope* LocalScope::LookupSwitchScope() { | 504 LocalScope* LocalScope::LookupSwitchScope() { |
| 526 LocalScope* current_scope = this->parent(); | 505 LocalScope* current_scope = this->parent(); |
| 527 int this_level = this->function_level(); | 506 int this_level = this->function_level(); |
| 528 while (current_scope != NULL && | 507 while (current_scope != NULL && |
| 529 current_scope->function_level() == this_level) { | 508 current_scope->function_level() == this_level) { |
| 530 for (int i = 0; i < current_scope->labels_.length(); i++) { | 509 for (int i = 0; i < current_scope->labels_.length(); i++) { |
| 531 SourceLabel* label = current_scope->labels_[i]; | 510 SourceLabel* label = current_scope->labels_[i]; |
| 532 if (label->kind() == SourceLabel::kSwitch) { | 511 if (label->kind() == SourceLabel::kSwitch) { |
| 533 // This scope contains a label that is bound to a switch statement, | 512 // This scope contains a label that is bound to a switch statement, |
| 534 // so it is the scope of the a statement body. | 513 // so it is the scope of the a statement body. |
| 535 return current_scope; | 514 return current_scope; |
| 536 } | 515 } |
| 537 } | 516 } |
| 538 current_scope = current_scope->parent(); | 517 current_scope = current_scope->parent(); |
| 539 } | 518 } |
| 540 // We did not find a switch statement scope at the same function level. | 519 // We did not find a switch statement scope at the same function level. |
| 541 return NULL; | 520 return NULL; |
| 542 } | 521 } |
| 543 | 522 |
| 544 | |
| 545 SourceLabel* LocalScope::CheckUnresolvedLabels() { | 523 SourceLabel* LocalScope::CheckUnresolvedLabels() { |
| 546 for (int i = 0; i < this->labels_.length(); i++) { | 524 for (int i = 0; i < this->labels_.length(); i++) { |
| 547 SourceLabel* label = this->labels_[i]; | 525 SourceLabel* label = this->labels_[i]; |
| 548 if (label->kind() == SourceLabel::kForward) { | 526 if (label->kind() == SourceLabel::kForward) { |
| 549 LocalScope* outer_switch = LookupSwitchScope(); | 527 LocalScope* outer_switch = LookupSwitchScope(); |
| 550 if (outer_switch == NULL) { | 528 if (outer_switch == NULL) { |
| 551 return label; | 529 return label; |
| 552 } else { | 530 } else { |
| 553 outer_switch->MoveLabel(label); | 531 outer_switch->MoveLabel(label); |
| 554 } | 532 } |
| 555 } | 533 } |
| 556 } | 534 } |
| 557 return NULL; | 535 return NULL; |
| 558 } | 536 } |
| 559 | 537 |
| 560 | |
| 561 int LocalScope::NumCapturedVariables() const { | 538 int LocalScope::NumCapturedVariables() const { |
| 562 // It is not necessary to traverse parent scopes, since we are only interested | 539 // It is not necessary to traverse parent scopes, since we are only interested |
| 563 // in the captured variables referenced in this scope. If this scope is the | 540 // in the captured variables referenced in this scope. If this scope is the |
| 564 // top scope at function level 1 and it (or its children scopes) references a | 541 // top scope at function level 1 and it (or its children scopes) references a |
| 565 // captured variable declared in a parent scope at function level 0, it will | 542 // captured variable declared in a parent scope at function level 0, it will |
| 566 // contain an alias for that variable. | 543 // contain an alias for that variable. |
| 567 | 544 |
| 568 // Since code generation for nested functions is postponed until first | 545 // Since code generation for nested functions is postponed until first |
| 569 // invocation, the function level of the closure scope can only be 1. | 546 // invocation, the function level of the closure scope can only be 1. |
| 570 ASSERT(function_level() == 1); | 547 ASSERT(function_level() == 1); |
| 571 | 548 |
| 572 int num_captured = 0; | 549 int num_captured = 0; |
| 573 for (int i = 0; i < num_variables(); i++) { | 550 for (int i = 0; i < num_variables(); i++) { |
| 574 LocalVariable* variable = VariableAt(i); | 551 LocalVariable* variable = VariableAt(i); |
| 575 // Count the aliases of captured variables belonging to outer scopes. | 552 // Count the aliases of captured variables belonging to outer scopes. |
| 576 if (variable->owner()->function_level() != 1) { | 553 if (variable->owner()->function_level() != 1) { |
| 577 ASSERT(variable->is_captured()); | 554 ASSERT(variable->is_captured()); |
| 578 ASSERT(variable->owner()->function_level() == 0); | 555 ASSERT(variable->owner()->function_level() == 0); |
| 579 num_captured++; | 556 num_captured++; |
| 580 } | 557 } |
| 581 } | 558 } |
| 582 return num_captured; | 559 return num_captured; |
| 583 } | 560 } |
| 584 | 561 |
| 585 | |
| 586 RawContextScope* LocalScope::PreserveOuterScope( | 562 RawContextScope* LocalScope::PreserveOuterScope( |
| 587 int current_context_level) const { | 563 int current_context_level) const { |
| 588 // Since code generation for nested functions is postponed until first | 564 // Since code generation for nested functions is postponed until first |
| 589 // invocation, the function level of the closure scope can only be 1. | 565 // invocation, the function level of the closure scope can only be 1. |
| 590 ASSERT(function_level() == 1); | 566 ASSERT(function_level() == 1); |
| 591 | 567 |
| 592 // Count the number of referenced captured variables. | 568 // Count the number of referenced captured variables. |
| 593 intptr_t num_captured_vars = NumCapturedVariables(); | 569 intptr_t num_captured_vars = NumCapturedVariables(); |
| 594 | 570 |
| 595 // Create a ContextScope with space for num_captured_vars descriptors. | 571 // Create a ContextScope with space for num_captured_vars descriptors. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 621 int adjusted_context_level = | 597 int adjusted_context_level = |
| 622 variable->owner()->context_level() - current_context_level; | 598 variable->owner()->context_level() - current_context_level; |
| 623 context_scope.SetContextLevelAt(captured_idx, adjusted_context_level); | 599 context_scope.SetContextLevelAt(captured_idx, adjusted_context_level); |
| 624 captured_idx++; | 600 captured_idx++; |
| 625 } | 601 } |
| 626 } | 602 } |
| 627 ASSERT(context_scope.num_variables() == captured_idx); // Verify count. | 603 ASSERT(context_scope.num_variables() == captured_idx); // Verify count. |
| 628 return context_scope.raw(); | 604 return context_scope.raw(); |
| 629 } | 605 } |
| 630 | 606 |
| 631 | |
| 632 LocalScope* LocalScope::RestoreOuterScope(const ContextScope& context_scope) { | 607 LocalScope* LocalScope::RestoreOuterScope(const ContextScope& context_scope) { |
| 633 // The function level of the outer scope is one less than the function level | 608 // The function level of the outer scope is one less than the function level |
| 634 // of the current function, which is 0. | 609 // of the current function, which is 0. |
| 635 LocalScope* outer_scope = new LocalScope(NULL, -1, 0); | 610 LocalScope* outer_scope = new LocalScope(NULL, -1, 0); |
| 636 // Add all variables as aliases to the outer scope. | 611 // Add all variables as aliases to the outer scope. |
| 637 for (int i = 0; i < context_scope.num_variables(); i++) { | 612 for (int i = 0; i < context_scope.num_variables(); i++) { |
| 638 LocalVariable* variable; | 613 LocalVariable* variable; |
| 639 if (context_scope.IsConstAt(i)) { | 614 if (context_scope.IsConstAt(i)) { |
| 640 variable = new LocalVariable(context_scope.DeclarationTokenIndexAt(i), | 615 variable = new LocalVariable(context_scope.DeclarationTokenIndexAt(i), |
| 641 context_scope.TokenIndexAt(i), | 616 context_scope.TokenIndexAt(i), |
| (...skipping 18 matching lines...) Expand all Loading... |
| 660 // context level has already been assigned. | 635 // context level has already been assigned. |
| 661 LocalScope* owner_scope = new LocalScope(NULL, 0, 0); | 636 LocalScope* owner_scope = new LocalScope(NULL, 0, 0); |
| 662 owner_scope->set_context_level(context_scope.ContextLevelAt(i)); | 637 owner_scope->set_context_level(context_scope.ContextLevelAt(i)); |
| 663 owner_scope->AddVariable(variable); | 638 owner_scope->AddVariable(variable); |
| 664 outer_scope->AddVariable(variable); // As alias. | 639 outer_scope->AddVariable(variable); // As alias. |
| 665 ASSERT(variable->owner() == owner_scope); | 640 ASSERT(variable->owner() == owner_scope); |
| 666 } | 641 } |
| 667 return outer_scope; | 642 return outer_scope; |
| 668 } | 643 } |
| 669 | 644 |
| 670 | |
| 671 void LocalScope::CaptureLocalVariables(LocalScope* top_scope) { | 645 void LocalScope::CaptureLocalVariables(LocalScope* top_scope) { |
| 672 ASSERT(top_scope->function_level() == function_level()); | 646 ASSERT(top_scope->function_level() == function_level()); |
| 673 LocalScope* scope = this; | 647 LocalScope* scope = this; |
| 674 while (scope != top_scope->parent()) { | 648 while (scope != top_scope->parent()) { |
| 675 for (intptr_t i = 0; i < scope->num_variables(); i++) { | 649 for (intptr_t i = 0; i < scope->num_variables(); i++) { |
| 676 LocalVariable* variable = scope->VariableAt(i); | 650 LocalVariable* variable = scope->VariableAt(i); |
| 677 if (variable->is_forced_stack() || | 651 if (variable->is_forced_stack() || |
| 678 (variable->name().raw() == Symbols::StackTraceVar().raw()) || | 652 (variable->name().raw() == Symbols::StackTraceVar().raw()) || |
| 679 (variable->name().raw() == Symbols::ExceptionVar().raw()) || | 653 (variable->name().raw() == Symbols::ExceptionVar().raw()) || |
| 680 (variable->name().raw() == Symbols::SavedTryContextVar().raw())) { | 654 (variable->name().raw() == Symbols::SavedTryContextVar().raw())) { |
| 681 // Don't capture those variables because the VM expects them to be on | 655 // Don't capture those variables because the VM expects them to be on |
| 682 // the stack. | 656 // the stack. |
| 683 continue; | 657 continue; |
| 684 } | 658 } |
| 685 scope->CaptureVariable(variable); | 659 scope->CaptureVariable(variable); |
| 686 } | 660 } |
| 687 scope = scope->parent(); | 661 scope = scope->parent(); |
| 688 } | 662 } |
| 689 } | 663 } |
| 690 | 664 |
| 691 | |
| 692 RawContextScope* LocalScope::CreateImplicitClosureScope(const Function& func) { | 665 RawContextScope* LocalScope::CreateImplicitClosureScope(const Function& func) { |
| 693 static const intptr_t kNumCapturedVars = 1; | 666 static const intptr_t kNumCapturedVars = 1; |
| 694 | 667 |
| 695 // Create a ContextScope with space for kNumCapturedVars descriptors. | 668 // Create a ContextScope with space for kNumCapturedVars descriptors. |
| 696 const ContextScope& context_scope = | 669 const ContextScope& context_scope = |
| 697 ContextScope::Handle(ContextScope::New(kNumCapturedVars, true)); | 670 ContextScope::Handle(ContextScope::New(kNumCapturedVars, true)); |
| 698 | 671 |
| 699 // Create a descriptor for 'this' variable. | 672 // Create a descriptor for 'this' variable. |
| 700 context_scope.SetTokenIndexAt(0, func.token_pos()); | 673 context_scope.SetTokenIndexAt(0, func.token_pos()); |
| 701 context_scope.SetDeclarationTokenIndexAt(0, func.token_pos()); | 674 context_scope.SetDeclarationTokenIndexAt(0, func.token_pos()); |
| 702 context_scope.SetNameAt(0, Symbols::This()); | 675 context_scope.SetNameAt(0, Symbols::This()); |
| 703 context_scope.SetIsFinalAt(0, true); | 676 context_scope.SetIsFinalAt(0, true); |
| 704 context_scope.SetIsConstAt(0, false); | 677 context_scope.SetIsConstAt(0, false); |
| 705 const AbstractType& type = AbstractType::Handle(func.ParameterTypeAt(0)); | 678 const AbstractType& type = AbstractType::Handle(func.ParameterTypeAt(0)); |
| 706 context_scope.SetTypeAt(0, type); | 679 context_scope.SetTypeAt(0, type); |
| 707 context_scope.SetContextIndexAt(0, 0); | 680 context_scope.SetContextIndexAt(0, 0); |
| 708 context_scope.SetContextLevelAt(0, 0); | 681 context_scope.SetContextLevelAt(0, 0); |
| 709 ASSERT(context_scope.num_variables() == kNumCapturedVars); // Verify count. | 682 ASSERT(context_scope.num_variables() == kNumCapturedVars); // Verify count. |
| 710 return context_scope.raw(); | 683 return context_scope.raw(); |
| 711 } | 684 } |
| 712 | 685 |
| 713 | |
| 714 bool LocalVariable::Equals(const LocalVariable& other) const { | 686 bool LocalVariable::Equals(const LocalVariable& other) const { |
| 715 if (HasIndex() && other.HasIndex() && (index() == other.index())) { | 687 if (HasIndex() && other.HasIndex() && (index() == other.index())) { |
| 716 if (is_captured() == other.is_captured()) { | 688 if (is_captured() == other.is_captured()) { |
| 717 if (!is_captured()) { | 689 if (!is_captured()) { |
| 718 return true; | 690 return true; |
| 719 } | 691 } |
| 720 if (owner()->context_level() == other.owner()->context_level()) { | 692 if (owner()->context_level() == other.owner()->context_level()) { |
| 721 return true; | 693 return true; |
| 722 } | 694 } |
| 723 } | 695 } |
| 724 } | 696 } |
| 725 return false; | 697 return false; |
| 726 } | 698 } |
| 727 | 699 |
| 728 | |
| 729 int LocalVariable::BitIndexIn(intptr_t fixed_parameter_count) const { | 700 int LocalVariable::BitIndexIn(intptr_t fixed_parameter_count) const { |
| 730 ASSERT(!is_captured()); | 701 ASSERT(!is_captured()); |
| 731 // Parameters have positive indexes with the lowest index being | 702 // Parameters have positive indexes with the lowest index being |
| 732 // kParamEndSlotFromFp + 1. Locals and copied parameters have negative | 703 // kParamEndSlotFromFp + 1. Locals and copied parameters have negative |
| 733 // indexes with the lowest (closest to 0) index being kFirstLocalSlotFromFp. | 704 // indexes with the lowest (closest to 0) index being kFirstLocalSlotFromFp. |
| 734 if (index() > 0) { | 705 if (index() > 0) { |
| 735 // Shift non-negative indexes so that the lowest one is 0. | 706 // Shift non-negative indexes so that the lowest one is 0. |
| 736 return fixed_parameter_count - (index() - kParamEndSlotFromFp); | 707 return fixed_parameter_count - (index() - kParamEndSlotFromFp); |
| 737 } else { | 708 } else { |
| 738 // Shift negative indexes so that the lowest one is 0 (they are still | 709 // Shift negative indexes so that the lowest one is 0 (they are still |
| 739 // non-positive). | 710 // non-positive). |
| 740 return fixed_parameter_count - (index() - kFirstLocalSlotFromFp); | 711 return fixed_parameter_count - (index() - kFirstLocalSlotFromFp); |
| 741 } | 712 } |
| 742 } | 713 } |
| 743 | 714 |
| 744 | |
| 745 } // namespace dart | 715 } // namespace dart |
| OLD | NEW |