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 780 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 791 static const char* Header(ScopeType scope_type) { | 791 static const char* Header(ScopeType scope_type) { |
| 792 switch (scope_type) { | 792 switch (scope_type) { |
| 793 case EVAL_SCOPE: return "eval"; | 793 case EVAL_SCOPE: return "eval"; |
| 794 case FUNCTION_SCOPE: return "function"; | 794 case FUNCTION_SCOPE: return "function"; |
| 795 case MODULE_SCOPE: return "module"; | 795 case MODULE_SCOPE: return "module"; |
| 796 case SCRIPT_SCOPE: return "global"; | 796 case SCRIPT_SCOPE: return "global"; |
| 797 case CATCH_SCOPE: return "catch"; | 797 case CATCH_SCOPE: return "catch"; |
| 798 case BLOCK_SCOPE: return "block"; | 798 case BLOCK_SCOPE: return "block"; |
| 799 case WITH_SCOPE: return "with"; | 799 case WITH_SCOPE: return "with"; |
| 800 case ARROW_SCOPE: return "arrow"; | 800 case ARROW_SCOPE: return "arrow"; |
| 801 case CLASS_SCOPE: | |
| 802 return "class"; | |
| 801 } | 803 } |
| 802 UNREACHABLE(); | 804 UNREACHABLE(); |
| 803 return NULL; | 805 return NULL; |
| 804 } | 806 } |
| 805 | 807 |
| 806 | 808 |
| 807 static void Indent(int n, const char* str) { | 809 static void Indent(int n, const char* str) { |
| 808 PrintF("%*s%s", n, "", str); | 810 PrintF("%*s%s", n, "", str); |
| 809 } | 811 } |
| 810 | 812 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1063 // (functions and consts may be resolved by the parser). | 1065 // (functions and consts may be resolved by the parser). |
| 1064 if (proxy->is_resolved()) return true; | 1066 if (proxy->is_resolved()) return true; |
| 1065 | 1067 |
| 1066 // Otherwise, try to resolve the variable. | 1068 // Otherwise, try to resolve the variable. |
| 1067 BindingKind binding_kind; | 1069 BindingKind binding_kind; |
| 1068 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1070 Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
| 1069 switch (binding_kind) { | 1071 switch (binding_kind) { |
| 1070 case BOUND: | 1072 case BOUND: |
| 1071 // We found a variable binding. | 1073 // We found a variable binding. |
| 1072 if (is_strong(language_mode())) { | 1074 if (is_strong(language_mode())) { |
| 1073 // Check for declaration-after use (for variables) in strong mode. Note | 1075 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 } | 1076 } |
| 1097 break; | 1077 break; |
| 1098 | 1078 |
| 1099 case BOUND_EVAL_SHADOWED: | 1079 case BOUND_EVAL_SHADOWED: |
| 1100 // We either found a variable binding that might be shadowed by eval or | 1080 // 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 | 1081 // 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 | 1082 // scope which was not promoted to a context, this can happen if we use |
| 1103 // debugger to evaluate arbitrary expressions at a break point). | 1083 // debugger to evaluate arbitrary expressions at a break point). |
| 1104 if (var->IsGlobalObjectProperty()) { | 1084 if (var->IsGlobalObjectProperty()) { |
| 1105 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); | 1085 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1130 | 1110 |
| 1131 DCHECK(var != NULL); | 1111 DCHECK(var != NULL); |
| 1132 if (proxy->is_assigned()) var->set_maybe_assigned(); | 1112 if (proxy->is_assigned()) var->set_maybe_assigned(); |
| 1133 | 1113 |
| 1134 proxy->BindTo(var); | 1114 proxy->BindTo(var); |
| 1135 | 1115 |
| 1136 return true; | 1116 return true; |
| 1137 } | 1117 } |
| 1138 | 1118 |
| 1139 | 1119 |
| 1120 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) { | |
| 1121 // Check for declaration-after use (for variables) in strong mode. Note that | |
| 1122 // we can only do this in the case where we have seen the declaration. And we | |
| 1123 // always allow referencing functions (for now). | |
| 1124 | |
| 1125 // If both the use and the declaration are inside an eval scope (possibly | |
| 1126 // indirectly), or one of them is, we need to check whether they are inside | |
| 1127 // the same eval scope or different ones. | |
| 1128 | |
| 1129 // TODO(marja,rossberg): Detect errors across different evals (depends on the | |
| 1130 // future of eval in strong mode). | |
| 1131 const Scope* eval_for_use = NearestOuterEvalScope(); | |
| 1132 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); | |
| 1133 | |
| 1134 // Allow referencing the class name from methods, even though the initializer | |
| 1135 // position for class names is only after the body. Note that the only | |
| 1136 // variable declared in the class scope is the class name. | |
| 1137 bool legal_class_name_reference = false; | |
| 1138 if (var->scope()->is_class_scope()) { | |
| 1139 // Referencing the class name is only allowed inside methods of that class. | |
| 1140 Scope* scope = this; | |
| 1141 bool found_method_scope = false; | |
| 1142 while (scope && !found_method_scope && scope != var->scope()) { | |
| 1143 if (scope->is_function_scope() && scope->outer_scope_ == var->scope()) { | |
| 1144 found_method_scope = true; | |
|
arv (Not doing code reviews)
2015/03/03 15:36:28
It is still not clear why this is only matching th
marja
2015/03/03 15:52:14
This check only fires when we have resolved the Va
| |
| 1145 break; | |
| 1146 } | |
| 1147 scope = scope->outer_scope(); | |
| 1148 } | |
| 1149 legal_class_name_reference = found_method_scope; | |
| 1150 } | |
| 1151 | |
| 1152 if (proxy->position() != RelocInfo::kNoPosition && | |
| 1153 proxy->position() < var->initializer_position() && !var->is_function() && | |
| 1154 eval_for_use == eval_for_declaration && !legal_class_name_reference) { | |
| 1155 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | |
| 1156 ReportMessage(proxy->position(), proxy->end_position(), | |
| 1157 "strong_use_before_declaration", proxy->raw_name()); | |
| 1158 return false; | |
| 1159 } | |
| 1160 return true; | |
| 1161 } | |
| 1162 | |
| 1163 | |
| 1140 bool Scope::ResolveVariablesRecursively(CompilationInfo* info, | 1164 bool Scope::ResolveVariablesRecursively(CompilationInfo* info, |
| 1141 AstNodeFactory* factory) { | 1165 AstNodeFactory* factory) { |
| 1142 DCHECK(info->script_scope()->is_script_scope()); | 1166 DCHECK(info->script_scope()->is_script_scope()); |
| 1143 | 1167 |
| 1144 // Resolve unresolved variables for this scope. | 1168 // Resolve unresolved variables for this scope. |
| 1145 for (int i = 0; i < unresolved_.length(); i++) { | 1169 for (int i = 0; i < unresolved_.length(); i++) { |
| 1146 if (!ResolveVariable(info, unresolved_[i], factory)) return false; | 1170 if (!ResolveVariable(info, unresolved_[i], factory)) return false; |
| 1147 } | 1171 } |
| 1148 | 1172 |
| 1149 // Resolve unresolved variables for inner scopes. | 1173 // Resolve unresolved variables for inner scopes. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1194 } | 1218 } |
| 1195 | 1219 |
| 1196 | 1220 |
| 1197 bool Scope::MustAllocate(Variable* var) { | 1221 bool Scope::MustAllocate(Variable* var) { |
| 1198 // Give var a read/write use if there is a chance it might be accessed | 1222 // Give var a read/write use if there is a chance it might be accessed |
| 1199 // via an eval() call. This is only possible if the variable has a | 1223 // via an eval() call. This is only possible if the variable has a |
| 1200 // visible name. | 1224 // visible name. |
| 1201 if ((var->is_this() || var->is_new_target() || !var->raw_name()->IsEmpty()) && | 1225 if ((var->is_this() || var->is_new_target() || !var->raw_name()->IsEmpty()) && |
| 1202 (var->has_forced_context_allocation() || scope_calls_eval_ || | 1226 (var->has_forced_context_allocation() || scope_calls_eval_ || |
| 1203 inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() || | 1227 inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() || |
| 1204 is_block_scope() || is_module_scope() || is_script_scope())) { | 1228 is_block_scope() || is_class_scope() || is_module_scope() || |
| 1229 is_script_scope())) { | |
| 1205 var->set_is_used(); | 1230 var->set_is_used(); |
| 1206 if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned(); | 1231 if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned(); |
| 1207 } | 1232 } |
| 1208 // Global variables do not need to be allocated. | 1233 // Global variables do not need to be allocated. |
| 1209 return !var->IsGlobalObjectProperty() && var->is_used(); | 1234 return !var->IsGlobalObjectProperty() && var->is_used(); |
| 1210 } | 1235 } |
| 1211 | 1236 |
| 1212 | 1237 |
| 1213 bool Scope::MustAllocateInContext(Variable* var) { | 1238 bool Scope::MustAllocateInContext(Variable* var) { |
| 1214 // If var is accessed from an inner scope, or if there is a possibility | 1239 // If var is accessed from an inner scope, or if there is a possibility |
| 1215 // that it might be accessed from the current or an inner scope (through | 1240 // that it might be accessed from the current or an inner scope (through |
| 1216 // an eval() call or a runtime with lookup), it must be allocated in the | 1241 // an eval() call or a runtime with lookup), it must be allocated in the |
| 1217 // context. | 1242 // context. |
| 1218 // | 1243 // |
| 1219 // Exceptions: If the scope as a whole has forced context allocation, all | 1244 // Exceptions: If the scope as a whole has forced context allocation, all |
| 1220 // variables will have context allocation, even temporaries. Otherwise | 1245 // variables will have context allocation, even temporaries. Otherwise |
| 1221 // temporary variables are always stack-allocated. Catch-bound variables are | 1246 // temporary variables are always stack-allocated. Catch-bound variables are |
| 1222 // always context-allocated. | 1247 // always context-allocated. |
| 1223 if (has_forced_context_allocation()) return true; | 1248 if (has_forced_context_allocation()) return true; |
| 1224 if (var->mode() == TEMPORARY) return false; | 1249 if (var->mode() == TEMPORARY) return false; |
| 1225 if (var->mode() == INTERNAL) return true; | 1250 if (var->mode() == INTERNAL) return true; |
| 1226 if (is_catch_scope() || is_block_scope() || is_module_scope()) return true; | 1251 if (is_catch_scope() || is_block_scope() || is_class_scope() || |
| 1252 is_module_scope()) { | |
| 1253 return true; | |
| 1254 } | |
| 1227 if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; | 1255 if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; |
| 1228 return var->has_forced_context_allocation() || | 1256 return var->has_forced_context_allocation() || |
| 1229 scope_calls_eval_ || | 1257 scope_calls_eval_ || |
| 1230 inner_scope_calls_eval_ || | 1258 inner_scope_calls_eval_ || |
| 1231 scope_contains_with_; | 1259 scope_contains_with_; |
| 1232 } | 1260 } |
| 1233 | 1261 |
| 1234 | 1262 |
| 1235 bool Scope::HasArgumentsParameter(Isolate* isolate) { | 1263 bool Scope::HasArgumentsParameter(Isolate* isolate) { |
| 1236 for (int i = 0; i < params_.length(); i++) { | 1264 for (int i = 0; i < params_.length(); i++) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1425 } | 1453 } |
| 1426 | 1454 |
| 1427 | 1455 |
| 1428 int Scope::ContextLocalCount() const { | 1456 int Scope::ContextLocalCount() const { |
| 1429 if (num_heap_slots() == 0) return 0; | 1457 if (num_heap_slots() == 0) return 0; |
| 1430 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1458 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
| 1431 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); | 1459 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |
| 1432 } | 1460 } |
| 1433 | 1461 |
| 1434 } } // namespace v8::internal | 1462 } } // namespace v8::internal |
| OLD | NEW |