Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/scopes.h" | 7 #include "src/scopes.h" |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 return reinterpret_cast<Variable*>(p->value); | 59 return reinterpret_cast<Variable*>(p->value); |
| 60 } | 60 } |
| 61 return NULL; | 61 return NULL; |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 // ---------------------------------------------------------------------------- | 65 // ---------------------------------------------------------------------------- |
| 66 // Implementation of Scope | 66 // Implementation of Scope |
| 67 | 67 |
| 68 Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type, | 68 Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type, |
| 69 AstValueFactory* ast_value_factory) | 69 AstValueFactory* ast_value_factory, FunctionKind function_kind) |
| 70 : inner_scopes_(4, zone), | 70 : inner_scopes_(4, zone), |
| 71 variables_(zone), | 71 variables_(zone), |
| 72 internals_(4, zone), | 72 internals_(4, zone), |
| 73 temps_(4, zone), | 73 temps_(4, zone), |
| 74 params_(4, zone), | 74 params_(4, zone), |
| 75 unresolved_(16, zone), | 75 unresolved_(16, zone), |
| 76 decls_(4, zone), | 76 decls_(4, zone), |
| 77 module_descriptor_( | 77 module_descriptor_( |
| 78 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), | 78 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), |
| 79 already_resolved_(false), | 79 already_resolved_(false), |
| 80 ast_value_factory_(ast_value_factory), | 80 ast_value_factory_(ast_value_factory), |
| 81 zone_(zone) { | 81 zone_(zone) { |
| 82 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null()); | 82 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), |
| 83 function_kind); | |
| 83 // The outermost scope must be a script scope. | 84 // The outermost scope must be a script scope. |
| 84 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); | 85 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); |
| 85 DCHECK(!HasIllegalRedeclaration()); | 86 DCHECK(!HasIllegalRedeclaration()); |
| 86 } | 87 } |
| 87 | 88 |
| 88 | 89 |
| 89 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, | 90 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, |
| 90 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) | 91 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) |
| 91 : inner_scopes_(4, zone), | 92 : inner_scopes_(4, zone), |
| 92 variables_(zone), | 93 variables_(zone), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 Variable* variable = variables_.Declare(this, | 132 Variable* variable = variables_.Declare(this, |
| 132 catch_variable_name, | 133 catch_variable_name, |
| 133 VAR, | 134 VAR, |
| 134 true, // Valid left-hand side. | 135 true, // Valid left-hand side. |
| 135 Variable::NORMAL, | 136 Variable::NORMAL, |
| 136 kCreatedInitialized); | 137 kCreatedInitialized); |
| 137 AllocateHeapSlot(variable); | 138 AllocateHeapSlot(variable); |
| 138 } | 139 } |
| 139 | 140 |
| 140 | 141 |
| 141 void Scope::SetDefaults(ScopeType scope_type, | 142 void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope, |
| 142 Scope* outer_scope, | 143 Handle<ScopeInfo> scope_info, |
| 143 Handle<ScopeInfo> scope_info) { | 144 FunctionKind function_kind) { |
| 144 outer_scope_ = outer_scope; | 145 outer_scope_ = outer_scope; |
| 145 scope_type_ = scope_type; | 146 scope_type_ = scope_type; |
| 147 function_kind_ = function_kind; | |
| 148 block_scope_is_class_scope_ = false; | |
| 146 scope_name_ = ast_value_factory_->empty_string(); | 149 scope_name_ = ast_value_factory_->empty_string(); |
| 147 dynamics_ = NULL; | 150 dynamics_ = NULL; |
| 148 receiver_ = NULL; | 151 receiver_ = NULL; |
| 149 new_target_ = nullptr; | 152 new_target_ = nullptr; |
| 150 function_ = NULL; | 153 function_ = NULL; |
| 151 arguments_ = NULL; | 154 arguments_ = NULL; |
| 152 illegal_redecl_ = NULL; | 155 illegal_redecl_ = NULL; |
| 153 scope_inside_with_ = false; | 156 scope_inside_with_ = false; |
| 154 scope_contains_with_ = false; | 157 scope_contains_with_ = false; |
| 155 scope_calls_eval_ = false; | 158 scope_calls_eval_ = false; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 174 num_modules_ = 0; | 177 num_modules_ = 0; |
| 175 module_var_ = NULL, | 178 module_var_ = NULL, |
| 176 rest_parameter_ = NULL; | 179 rest_parameter_ = NULL; |
| 177 rest_index_ = -1; | 180 rest_index_ = -1; |
| 178 scope_info_ = scope_info; | 181 scope_info_ = scope_info; |
| 179 start_position_ = RelocInfo::kNoPosition; | 182 start_position_ = RelocInfo::kNoPosition; |
| 180 end_position_ = RelocInfo::kNoPosition; | 183 end_position_ = RelocInfo::kNoPosition; |
| 181 if (!scope_info.is_null()) { | 184 if (!scope_info.is_null()) { |
| 182 scope_calls_eval_ = scope_info->CallsEval(); | 185 scope_calls_eval_ = scope_info->CallsEval(); |
| 183 language_mode_ = scope_info->language_mode(); | 186 language_mode_ = scope_info->language_mode(); |
| 187 block_scope_is_class_scope_ = scope_info->block_scope_is_class_scope(); | |
| 188 function_kind_ = scope_info->function_kind(); | |
| 184 } | 189 } |
| 185 } | 190 } |
| 186 | 191 |
| 187 | 192 |
| 188 Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, | 193 Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, |
| 189 Context* context, Scope* script_scope) { | 194 Context* context, Scope* script_scope) { |
| 190 // Reconstruct the outer scope chain from a closure's context chain. | 195 // Reconstruct the outer scope chain from a closure's context chain. |
| 191 Scope* current_scope = NULL; | 196 Scope* current_scope = NULL; |
| 192 Scope* innermost_scope = NULL; | 197 Scope* innermost_scope = NULL; |
| 193 bool contains_with = false; | 198 bool contains_with = false; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 277 : FLAG_print_scopes) { | 282 : FLAG_print_scopes) { |
| 278 scope->Print(); | 283 scope->Print(); |
| 279 } | 284 } |
| 280 #endif | 285 #endif |
| 281 | 286 |
| 282 info->PrepareForCompilation(scope); | 287 info->PrepareForCompilation(scope); |
| 283 return true; | 288 return true; |
| 284 } | 289 } |
| 285 | 290 |
| 286 | 291 |
| 287 void Scope::Initialize(bool subclass_constructor) { | 292 void Scope::Initialize() { |
| 293 bool subclass_constructor = IsSubclassConstructor(function_kind_); | |
| 288 DCHECK(!already_resolved()); | 294 DCHECK(!already_resolved()); |
| 289 | 295 |
| 290 // Add this scope as a new inner scope of the outer scope. | 296 // Add this scope as a new inner scope of the outer scope. |
| 291 if (outer_scope_ != NULL) { | 297 if (outer_scope_ != NULL) { |
| 292 outer_scope_->inner_scopes_.Add(this, zone()); | 298 outer_scope_->inner_scopes_.Add(this, zone()); |
| 293 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope(); | 299 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope(); |
| 294 } else { | 300 } else { |
| 295 scope_inside_with_ = is_with_scope(); | 301 scope_inside_with_ = is_with_scope(); |
| 296 } | 302 } |
| 297 | 303 |
| (...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1063 // (functions and consts may be resolved by the parser). | 1069 // (functions and consts may be resolved by the parser). |
| 1064 if (proxy->is_resolved()) return true; | 1070 if (proxy->is_resolved()) return true; |
| 1065 | 1071 |
| 1066 // Otherwise, try to resolve the variable. | 1072 // Otherwise, try to resolve the variable. |
| 1067 BindingKind binding_kind; | 1073 BindingKind binding_kind; |
| 1068 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1074 Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
| 1069 switch (binding_kind) { | 1075 switch (binding_kind) { |
| 1070 case BOUND: | 1076 case BOUND: |
| 1071 // We found a variable binding. | 1077 // We found a variable binding. |
| 1072 if (is_strong(language_mode())) { | 1078 if (is_strong(language_mode())) { |
| 1073 // Check for declaration-after use (for variables) in strong mode. Note | 1079 if (!CheckStrongModeDeclaration(proxy, var)) return false; |
| 1074 // that we can only do this in the case where we have seen the | |
| 1075 // declaration. And we always allow referencing functions (for now). | |
| 1076 | |
| 1077 // If both the use and the declaration are inside an eval scope | |
| 1078 // (possibly indirectly), or one of them is, we need to check whether | |
| 1079 // they are inside the same eval scope or different | |
| 1080 // ones. | |
| 1081 | |
| 1082 // TODO(marja,rossberg): Detect errors across different evals (depends | |
| 1083 // on the future of eval in strong mode). | |
| 1084 const Scope* eval_for_use = NearestOuterEvalScope(); | |
| 1085 const Scope* eval_for_declaration = | |
| 1086 var->scope()->NearestOuterEvalScope(); | |
| 1087 | |
| 1088 if (proxy->position() != RelocInfo::kNoPosition && | |
| 1089 proxy->position() < var->initializer_position() && | |
| 1090 !var->is_function() && eval_for_use == eval_for_declaration) { | |
| 1091 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | |
| 1092 ReportMessage(proxy->position(), proxy->end_position(), | |
| 1093 "strong_use_before_declaration", proxy->raw_name()); | |
| 1094 return false; | |
| 1095 } | |
| 1096 } | 1080 } |
| 1097 break; | 1081 break; |
| 1098 | 1082 |
| 1099 case BOUND_EVAL_SHADOWED: | 1083 case BOUND_EVAL_SHADOWED: |
| 1100 // We either found a variable binding that might be shadowed by eval or | 1084 // We either found a variable binding that might be shadowed by eval or |
| 1101 // gave up on it (e.g. by encountering a local with the same in the outer | 1085 // gave up on it (e.g. by encountering a local with the same in the outer |
| 1102 // scope which was not promoted to a context, this can happen if we use | 1086 // scope which was not promoted to a context, this can happen if we use |
| 1103 // debugger to evaluate arbitrary expressions at a break point). | 1087 // debugger to evaluate arbitrary expressions at a break point). |
| 1104 if (var->IsGlobalObjectProperty()) { | 1088 if (var->IsGlobalObjectProperty()) { |
| 1105 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); | 1089 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1130 | 1114 |
| 1131 DCHECK(var != NULL); | 1115 DCHECK(var != NULL); |
| 1132 if (proxy->is_assigned()) var->set_maybe_assigned(); | 1116 if (proxy->is_assigned()) var->set_maybe_assigned(); |
| 1133 | 1117 |
| 1134 proxy->BindTo(var); | 1118 proxy->BindTo(var); |
| 1135 | 1119 |
| 1136 return true; | 1120 return true; |
| 1137 } | 1121 } |
| 1138 | 1122 |
| 1139 | 1123 |
| 1124 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) { | |
| 1125 // Check for declaration-after use (for variables) in strong mode. Note that | |
| 1126 // we can only do this in the case where we have seen the declaration. And we | |
| 1127 // always allow referencing functions (for now). | |
| 1128 | |
| 1129 // Allow referencing the class name from methods of that class, even though | |
| 1130 // the initializer position for class names is only after the body. | |
| 1131 Scope* scope = this; | |
| 1132 while (scope) { | |
| 1133 if (scope->ClassVariableForMethod() == var) return true; | |
| 1134 scope = scope->outer_scope(); | |
| 1135 } | |
| 1136 | |
| 1137 // If both the use and the declaration are inside an eval scope (possibly | |
| 1138 // indirectly), or one of them is, we need to check whether they are inside | |
| 1139 // the same eval scope or different ones. | |
| 1140 | |
| 1141 // TODO(marja,rossberg): Detect errors across different evals (depends on the | |
| 1142 // future of eval in strong mode). | |
| 1143 const Scope* eval_for_use = NearestOuterEvalScope(); | |
| 1144 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); | |
| 1145 | |
| 1146 if (proxy->position() != RelocInfo::kNoPosition && | |
| 1147 proxy->position() < var->initializer_position() && !var->is_function() && | |
| 1148 eval_for_use == eval_for_declaration) { | |
| 1149 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | |
| 1150 ReportMessage(proxy->position(), proxy->end_position(), | |
| 1151 "strong_use_before_declaration", proxy->raw_name()); | |
| 1152 return false; | |
| 1153 } | |
| 1154 return true; | |
| 1155 } | |
| 1156 | |
| 1157 | |
| 1140 bool Scope::ResolveVariablesRecursively(CompilationInfo* info, | 1158 bool Scope::ResolveVariablesRecursively(CompilationInfo* info, |
| 1141 AstNodeFactory* factory) { | 1159 AstNodeFactory* factory) { |
| 1142 DCHECK(info->script_scope()->is_script_scope()); | 1160 DCHECK(info->script_scope()->is_script_scope()); |
| 1143 | 1161 |
| 1144 // Resolve unresolved variables for this scope. | 1162 // Resolve unresolved variables for this scope. |
| 1145 for (int i = 0; i < unresolved_.length(); i++) { | 1163 for (int i = 0; i < unresolved_.length(); i++) { |
| 1146 if (!ResolveVariable(info, unresolved_[i], factory)) return false; | 1164 if (!ResolveVariable(info, unresolved_[i], factory)) return false; |
| 1147 } | 1165 } |
| 1148 | 1166 |
| 1149 // Resolve unresolved variables for inner scopes. | 1167 // Resolve unresolved variables for inner scopes. |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1424 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); | 1442 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); |
| 1425 } | 1443 } |
| 1426 | 1444 |
| 1427 | 1445 |
| 1428 int Scope::ContextLocalCount() const { | 1446 int Scope::ContextLocalCount() const { |
| 1429 if (num_heap_slots() == 0) return 0; | 1447 if (num_heap_slots() == 0) return 0; |
| 1430 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1448 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
| 1431 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); | 1449 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |
| 1432 } | 1450 } |
| 1433 | 1451 |
| 1452 | |
| 1453 Variable* Scope::ClassVariableForMethod() const { | |
|
rossberg
2015/03/09 10:41:46
Nit: move this next to CheckStrongModeDeclaration
marja
2015/03/09 13:44:06
Done.
| |
| 1454 if (!is_function_scope()) return nullptr; | |
| 1455 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && | |
| 1456 !IsAccessorFunction(function_kind_)) { | |
| 1457 return nullptr; | |
| 1458 } | |
| 1459 DCHECK_NOT_NULL(outer_scope_); | |
| 1460 DCHECK(outer_scope_->is_class_scope()); | |
| 1461 // The class scope contains at most one variable, the class name. | |
| 1462 DCHECK(outer_scope_->variables_.occupancy() <= 1); | |
| 1463 if (outer_scope_->variables_.occupancy() == 0) return nullptr; | |
| 1464 VariableMap::Entry* p = outer_scope_->variables_.Start(); | |
| 1465 return reinterpret_cast<Variable*>(p->value); | |
| 1466 } | |
| 1434 } } // namespace v8::internal | 1467 } } // namespace v8::internal |
| OLD | NEW |