Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(682)

Side by Side Diff: src/scopes.cc

Issue 1060913005: [strong] Stricter check for referring to other classes inside methods. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: code review (rossberg@) Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/scopes.h ('k') | src/variables.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/accessors.h" 7 #include "src/accessors.h"
8 #include "src/bootstrapper.h" 8 #include "src/bootstrapper.h"
9 #include "src/messages.h" 9 #include "src/messages.h"
10 #include "src/parser.h" 10 #include "src/parser.h"
(...skipping 14 matching lines...) Expand all
25 25
26 VariableMap::VariableMap(Zone* zone) 26 VariableMap::VariableMap(Zone* zone)
27 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), 27 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
28 zone_(zone) {} 28 zone_(zone) {}
29 VariableMap::~VariableMap() {} 29 VariableMap::~VariableMap() {}
30 30
31 31
32 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, 32 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
33 VariableMode mode, Variable::Kind kind, 33 VariableMode mode, Variable::Kind kind,
34 InitializationFlag initialization_flag, 34 InitializationFlag initialization_flag,
35 MaybeAssignedFlag maybe_assigned_flag) { 35 MaybeAssignedFlag maybe_assigned_flag,
36 int declaration_group_start) {
36 // AstRawStrings are unambiguous, i.e., the same string is always represented 37 // AstRawStrings are unambiguous, i.e., the same string is always represented
37 // by the same AstRawString*. 38 // by the same AstRawString*.
38 // FIXME(marja): fix the type of Lookup. 39 // FIXME(marja): fix the type of Lookup.
39 Entry* p = 40 Entry* p =
40 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), 41 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
41 ZoneAllocationPolicy(zone())); 42 ZoneAllocationPolicy(zone()));
42 if (p->value == NULL) { 43 if (p->value == NULL) {
43 // The variable has not been declared yet -> insert it. 44 // The variable has not been declared yet -> insert it.
44 DCHECK(p->key == name); 45 DCHECK(p->key == name);
45 p->value = new (zone()) Variable(scope, name, mode, kind, 46 if (kind == Variable::CLASS) {
46 initialization_flag, maybe_assigned_flag); 47 p->value = new (zone())
48 ClassVariable(scope, name, mode, kind, initialization_flag,
49 maybe_assigned_flag, declaration_group_start);
50 } else {
51 p->value = new (zone()) Variable(
52 scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
53 }
47 } 54 }
48 return reinterpret_cast<Variable*>(p->value); 55 return reinterpret_cast<Variable*>(p->value);
49 } 56 }
50 57
51 58
52 Variable* VariableMap::Lookup(const AstRawString* name) { 59 Variable* VariableMap::Lookup(const AstRawString* name) {
53 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); 60 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash());
54 if (p != NULL) { 61 if (p != NULL) {
55 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); 62 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
56 DCHECK(p->value != NULL); 63 DCHECK(p->value != NULL);
(...skipping 12 matching lines...) Expand all
69 variables_(zone), 76 variables_(zone),
70 internals_(4, zone), 77 internals_(4, zone),
71 temps_(4, zone), 78 temps_(4, zone),
72 params_(4, zone), 79 params_(4, zone),
73 unresolved_(16, zone), 80 unresolved_(16, zone),
74 decls_(4, zone), 81 decls_(4, zone),
75 module_descriptor_( 82 module_descriptor_(
76 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), 83 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL),
77 already_resolved_(false), 84 already_resolved_(false),
78 ast_value_factory_(ast_value_factory), 85 ast_value_factory_(ast_value_factory),
79 zone_(zone) { 86 zone_(zone),
87 class_declaration_group_start_(-1) {
80 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), 88 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
81 function_kind); 89 function_kind);
82 // The outermost scope must be a script scope. 90 // The outermost scope must be a script scope.
83 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); 91 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
84 DCHECK(!HasIllegalRedeclaration()); 92 DCHECK(!HasIllegalRedeclaration());
85 } 93 }
86 94
87 95
88 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, 96 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type,
89 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) 97 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory)
90 : inner_scopes_(4, zone), 98 : inner_scopes_(4, zone),
91 variables_(zone), 99 variables_(zone),
92 internals_(4, zone), 100 internals_(4, zone),
93 temps_(4, zone), 101 temps_(4, zone),
94 params_(4, zone), 102 params_(4, zone),
95 unresolved_(16, zone), 103 unresolved_(16, zone),
96 decls_(4, zone), 104 decls_(4, zone),
97 module_descriptor_(NULL), 105 module_descriptor_(NULL),
98 already_resolved_(true), 106 already_resolved_(true),
99 ast_value_factory_(value_factory), 107 ast_value_factory_(value_factory),
100 zone_(zone) { 108 zone_(zone),
109 class_declaration_group_start_(-1) {
101 SetDefaults(scope_type, NULL, scope_info); 110 SetDefaults(scope_type, NULL, scope_info);
102 if (!scope_info.is_null()) { 111 if (!scope_info.is_null()) {
103 num_heap_slots_ = scope_info_->ContextLength(); 112 num_heap_slots_ = scope_info_->ContextLength();
104 } 113 }
105 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. 114 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
106 num_heap_slots_ = Max(num_heap_slots_, 115 num_heap_slots_ = Max(num_heap_slots_,
107 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); 116 static_cast<int>(Context::MIN_CONTEXT_SLOTS));
108 AddInnerScope(inner_scope); 117 AddInnerScope(inner_scope);
109 } 118 }
110 119
111 120
112 Scope::Scope(Zone* zone, Scope* inner_scope, 121 Scope::Scope(Zone* zone, Scope* inner_scope,
113 const AstRawString* catch_variable_name, 122 const AstRawString* catch_variable_name,
114 AstValueFactory* value_factory) 123 AstValueFactory* value_factory)
115 : inner_scopes_(1, zone), 124 : inner_scopes_(1, zone),
116 variables_(zone), 125 variables_(zone),
117 internals_(0, zone), 126 internals_(0, zone),
118 temps_(0, zone), 127 temps_(0, zone),
119 params_(0, zone), 128 params_(0, zone),
120 unresolved_(0, zone), 129 unresolved_(0, zone),
121 decls_(0, zone), 130 decls_(0, zone),
122 module_descriptor_(NULL), 131 module_descriptor_(NULL),
123 already_resolved_(true), 132 already_resolved_(true),
124 ast_value_factory_(value_factory), 133 ast_value_factory_(value_factory),
125 zone_(zone) { 134 zone_(zone),
135 class_declaration_group_start_(-1) {
126 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); 136 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
127 AddInnerScope(inner_scope); 137 AddInnerScope(inner_scope);
128 ++num_var_or_const_; 138 ++num_var_or_const_;
129 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; 139 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
130 Variable* variable = variables_.Declare(this, 140 Variable* variable = variables_.Declare(this,
131 catch_variable_name, 141 catch_variable_name,
132 VAR, 142 VAR,
133 Variable::NORMAL, 143 Variable::NORMAL,
134 kCreatedInitialized); 144 kCreatedInitialized);
135 AllocateHeapSlot(variable); 145 AllocateHeapSlot(variable);
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 413
404 mode = DYNAMIC; 414 mode = DYNAMIC;
405 location = Variable::LOOKUP; 415 location = Variable::LOOKUP;
406 init_flag = kCreatedInitialized; 416 init_flag = kCreatedInitialized;
407 // Be conservative and flag parameters as maybe assigned. Better information 417 // Be conservative and flag parameters as maybe assigned. Better information
408 // would require ScopeInfo to serialize the maybe_assigned bit also for 418 // would require ScopeInfo to serialize the maybe_assigned bit also for
409 // parameters. 419 // parameters.
410 maybe_assigned_flag = kMaybeAssigned; 420 maybe_assigned_flag = kMaybeAssigned;
411 } 421 }
412 422
423 // TODO(marja, rossberg): Declare variables of the right Kind.
413 Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL, 424 Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL,
414 init_flag, maybe_assigned_flag); 425 init_flag, maybe_assigned_flag);
415 var->AllocateTo(location, index); 426 var->AllocateTo(location, index);
416 return var; 427 return var;
417 } 428 }
418 429
419 430
420 Variable* Scope::LookupFunctionVar(const AstRawString* name, 431 Variable* Scope::LookupFunctionVar(const AstRawString* name,
421 AstNodeFactory* factory) { 432 AstNodeFactory* factory) {
422 if (function_ != NULL && function_->proxy()->raw_name() == name) { 433 if (function_ != NULL && function_->proxy()->raw_name() == name) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 } 475 }
465 // TODO(wingo): Avoid O(n^2) check. 476 // TODO(wingo): Avoid O(n^2) check.
466 *is_duplicate = IsDeclaredParameter(name); 477 *is_duplicate = IsDeclaredParameter(name);
467 params_.Add(var, zone()); 478 params_.Add(var, zone());
468 return var; 479 return var;
469 } 480 }
470 481
471 482
472 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, 483 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
473 InitializationFlag init_flag, Variable::Kind kind, 484 InitializationFlag init_flag, Variable::Kind kind,
474 MaybeAssignedFlag maybe_assigned_flag) { 485 MaybeAssignedFlag maybe_assigned_flag,
486 int declaration_group_start) {
475 DCHECK(!already_resolved()); 487 DCHECK(!already_resolved());
476 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are 488 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
477 // introduces during variable allocation, INTERNAL variables are allocated 489 // introduces during variable allocation, INTERNAL variables are allocated
478 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). 490 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
479 DCHECK(IsDeclaredVariableMode(mode)); 491 DCHECK(IsDeclaredVariableMode(mode));
480 ++num_var_or_const_; 492 ++num_var_or_const_;
481 return variables_.Declare(this, name, mode, kind, init_flag, 493 return variables_.Declare(this, name, mode, kind, init_flag,
482 maybe_assigned_flag); 494 maybe_assigned_flag, declaration_group_start);
483 } 495 }
484 496
485 497
486 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { 498 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
487 DCHECK(is_script_scope()); 499 DCHECK(is_script_scope());
488 return variables_.Declare(this, 500 return variables_.Declare(this,
489 name, 501 name,
490 DYNAMIC_GLOBAL, 502 DYNAMIC_GLOBAL,
491 Variable::NORMAL, 503 Variable::NORMAL,
492 kCreatedInitialized); 504 kCreatedInitialized);
(...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after
1125 1137
1126 return true; 1138 return true;
1127 } 1139 }
1128 1140
1129 1141
1130 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) { 1142 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) {
1131 // Check for declaration-after use (for variables) in strong mode. Note that 1143 // Check for declaration-after use (for variables) in strong mode. Note that
1132 // we can only do this in the case where we have seen the declaration. And we 1144 // we can only do this in the case where we have seen the declaration. And we
1133 // always allow referencing functions (for now). 1145 // always allow referencing functions (for now).
1134 1146
1147 // This might happen during lazy compilation; we don't keep track of
1148 // initializer positions for variables stored in ScopeInfo, so we cannot check
1149 // bindings against them. TODO(marja, rossberg): remove this hack.
1150 if (var->initializer_position() == RelocInfo::kNoPosition) return true;
1151
1135 // Allow referencing the class name from methods of that class, even though 1152 // Allow referencing the class name from methods of that class, even though
1136 // the initializer position for class names is only after the body. 1153 // the initializer position for class names is only after the body.
1137 Scope* scope = this; 1154 Scope* scope = this;
1138 while (scope) { 1155 while (scope) {
1139 if (scope->ClassVariableForMethod() == var) return true; 1156 if (scope->ClassVariableForMethod() == var) return true;
1140 scope = scope->outer_scope(); 1157 scope = scope->outer_scope();
1141 } 1158 }
1142 1159
1143 // Allow references from methods to classes declared later, if we detect no 1160 // Allow references from methods to classes declared later, if we detect no
1144 // problematic dependency cycles. 1161 // problematic dependency cycles. Note that we can be inside multiple methods
1162 // at the same time, and it's enough if we find one where the reference is
1163 // allowed.
1164 if (var->is_class() &&
1165 var->AsClassVariable()->declaration_group_start() >= 0) {
1166 for (scope = this; scope && scope != var->scope();
1167 scope = scope->outer_scope()) {
1168 ClassVariable* class_var = scope->ClassVariableForMethod();
1169 if (class_var) {
1170 // A method is referring to some other class, possibly declared
1171 // later. Referring to a class declared earlier is always OK and covered
1172 // by the code outside this if. Here we only need to allow special cases
1173 // for referring to a class which is declared later.
1145 1174
1146 if (ClassVariableForMethod() && var->is_class()) { 1175 // Referring to a class C declared later is OK under the following
1147 // A method is referring to some other class, possibly declared 1176 // circumstances:
1148 // later. Referring to a class declared earlier is always OK and covered by
1149 // the code outside this if. Here we only need to allow special cases for
1150 // referring to a class which is declared later.
1151 1177
1152 // Referring to a class C declared later is OK under the following 1178 // 1. The class declarations are in a consecutive group with no other
1153 // circumstances: 1179 // declarations or statements in between, and
1154 1180
1155 // 1. The class declarations are in a consecutive group with no other 1181 // 2. There is no dependency cycle where the first edge is an
1156 // declarations or statements in between, and 1182 // initialization time dependency (computed property name or extends
1183 // clause) from C to something that depends on this class directly or
1184 // transitively.
1157 1185
1158 // 2. There is no dependency cycle where the first edge is an initialization 1186 // This is needed because a class ("class Name { }") creates two
1159 // time dependency (computed property name or extends clause) from C to 1187 // bindings (one in the outer scope, and one in the class scope). The
1160 // something that depends on this class directly or transitively. 1188 // method is a function scope inside the inner scope (class scope). The
1189 // consecutive class declarations are in the outer scope.
1190 class_var = class_var->corresponding_outer_class_variable();
1191 if (class_var &&
1192 class_var->declaration_group_start() ==
1193 var->AsClassVariable()->declaration_group_start()) {
1194 return true;
1195 }
1161 1196
1162 // TODO(marja,rossberg): implement these checks. Here we undershoot the 1197 // TODO(marja,rossberg): implement the dependency cycle detection. Here
1163 // target and allow referring to any class. 1198 // we undershoot the target and allow referring to any class in the same
1164 return true; 1199 // consectuive declaration group.
1200
1201 // The cycle detection can work roughly like this: 1) detect init-time
1202 // references here (they are free variables which are inside the class
1203 // scope but not inside a method scope - no parser changes needed to
1204 // detect them) 2) if we encounter an init-time reference here, allow
1205 // it, but record it for a later dependency cycle check 3) also record
1206 // non-init-time references here 4) after scope analysis is done,
1207 // analyse the dependency cycles: an illegal cycle is one starting with
1208 // an init-time reference and leading back to the starting point with
1209 // either non-init-time and init-time references.
1210 }
1211 }
1165 } 1212 }
1166 1213
1167 // If both the use and the declaration are inside an eval scope (possibly 1214 // If both the use and the declaration are inside an eval scope (possibly
1168 // indirectly), or one of them is, we need to check whether they are inside 1215 // indirectly), or one of them is, we need to check whether they are inside
1169 // the same eval scope or different ones. 1216 // the same eval scope or different ones.
1170 1217
1171 // TODO(marja,rossberg): Detect errors across different evals (depends on the 1218 // TODO(marja,rossberg): Detect errors across different evals (depends on the
1172 // future of eval in strong mode). 1219 // future of eval in strong mode).
1173 const Scope* eval_for_use = NearestOuterEvalScope(); 1220 const Scope* eval_for_use = NearestOuterEvalScope();
1174 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); 1221 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope();
1175 1222
1176 if (proxy->position() != RelocInfo::kNoPosition && 1223 if (proxy->position() != RelocInfo::kNoPosition &&
1177 proxy->position() < var->initializer_position() && !var->is_function() && 1224 proxy->position() < var->initializer_position() && !var->is_function() &&
1178 eval_for_use == eval_for_declaration) { 1225 eval_for_use == eval_for_declaration) {
1179 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); 1226 DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
1180 ReportMessage(proxy->position(), proxy->end_position(), 1227 ReportMessage(proxy->position(), proxy->end_position(),
1181 "strong_use_before_declaration", proxy->raw_name()); 1228 "strong_use_before_declaration", proxy->raw_name());
1182 return false; 1229 return false;
1183 } 1230 }
1184 return true; 1231 return true;
1185 } 1232 }
1186 1233
1187 1234
1188 Variable* Scope::ClassVariableForMethod() const { 1235 ClassVariable* Scope::ClassVariableForMethod() const {
1236 // TODO(marja, rossberg): This fails to find a class variable in the following
1237 // cases:
1238 // let A = class { ... }
1239 // It needs to be investigated whether this causes any practical problems.
1189 if (!is_function_scope()) return nullptr; 1240 if (!is_function_scope()) return nullptr;
1190 if (IsInObjectLiteral(function_kind_)) return nullptr; 1241 if (IsInObjectLiteral(function_kind_)) return nullptr;
1191 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && 1242 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) &&
1192 !IsAccessorFunction(function_kind_)) { 1243 !IsAccessorFunction(function_kind_)) {
1193 return nullptr; 1244 return nullptr;
1194 } 1245 }
1195 DCHECK_NOT_NULL(outer_scope_); 1246 DCHECK_NOT_NULL(outer_scope_);
1196 DCHECK(outer_scope_->is_class_scope()); 1247 DCHECK(outer_scope_->is_class_scope());
1197 // The class scope contains at most one variable, the class name. 1248 // The class scope contains at most one variable, the class name.
1198 DCHECK(outer_scope_->variables_.occupancy() <= 1); 1249 DCHECK(outer_scope_->variables_.occupancy() <= 1);
1199 if (outer_scope_->variables_.occupancy() == 0) return nullptr; 1250 if (outer_scope_->variables_.occupancy() == 0) return nullptr;
1200 VariableMap::Entry* p = outer_scope_->variables_.Start(); 1251 VariableMap::Entry* p = outer_scope_->variables_.Start();
1201 return reinterpret_cast<Variable*>(p->value); 1252 Variable* var = reinterpret_cast<Variable*>(p->value);
1253 if (!var->is_class()) return nullptr;
1254 return var->AsClassVariable();
1202 } 1255 }
1203 1256
1204 1257
1205 bool Scope::ResolveVariablesRecursively(ParseInfo* info, 1258 bool Scope::ResolveVariablesRecursively(ParseInfo* info,
1206 AstNodeFactory* factory) { 1259 AstNodeFactory* factory) {
1207 DCHECK(info->script_scope()->is_script_scope()); 1260 DCHECK(info->script_scope()->is_script_scope());
1208 1261
1209 // Resolve unresolved variables for this scope. 1262 // Resolve unresolved variables for this scope.
1210 for (int i = 0; i < unresolved_.length(); i++) { 1263 for (int i = 0; i < unresolved_.length(); i++) {
1211 if (!ResolveVariable(info, unresolved_[i], factory)) return false; 1264 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
1490 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); 1543 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
1491 } 1544 }
1492 1545
1493 1546
1494 int Scope::ContextLocalCount() const { 1547 int Scope::ContextLocalCount() const {
1495 if (num_heap_slots() == 0) return 0; 1548 if (num_heap_slots() == 0) return 0;
1496 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1549 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
1497 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); 1550 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
1498 } 1551 }
1499 } } // namespace v8::internal 1552 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/scopes.h ('k') | src/variables.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698