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

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: . 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
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 consecutive_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 p->value = new (zone())
46 initialization_flag, maybe_assigned_flag); 47 Variable(scope, name, mode, kind, initialization_flag,
48 maybe_assigned_flag, consecutive_declaration_group_start);
47 } 49 }
48 return reinterpret_cast<Variable*>(p->value); 50 return reinterpret_cast<Variable*>(p->value);
49 } 51 }
50 52
51 53
52 Variable* VariableMap::Lookup(const AstRawString* name) { 54 Variable* VariableMap::Lookup(const AstRawString* name) {
53 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); 55 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash());
54 if (p != NULL) { 56 if (p != NULL) {
55 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); 57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
56 DCHECK(p->value != NULL); 58 DCHECK(p->value != NULL);
(...skipping 12 matching lines...) Expand all
69 variables_(zone), 71 variables_(zone),
70 internals_(4, zone), 72 internals_(4, zone),
71 temps_(4, zone), 73 temps_(4, zone),
72 params_(4, zone), 74 params_(4, zone),
73 unresolved_(16, zone), 75 unresolved_(16, zone),
74 decls_(4, zone), 76 decls_(4, zone),
75 module_descriptor_( 77 module_descriptor_(
76 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), 78 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL),
77 already_resolved_(false), 79 already_resolved_(false),
78 ast_value_factory_(ast_value_factory), 80 ast_value_factory_(ast_value_factory),
79 zone_(zone) { 81 zone_(zone),
82 consecutive_class_declaration_group_start_(-1) {
80 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), 83 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
81 function_kind); 84 function_kind);
82 // The outermost scope must be a script scope. 85 // The outermost scope must be a script scope.
83 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); 86 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
84 DCHECK(!HasIllegalRedeclaration()); 87 DCHECK(!HasIllegalRedeclaration());
85 } 88 }
86 89
87 90
88 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, 91 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type,
89 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) 92 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory)
90 : inner_scopes_(4, zone), 93 : inner_scopes_(4, zone),
91 variables_(zone), 94 variables_(zone),
92 internals_(4, zone), 95 internals_(4, zone),
93 temps_(4, zone), 96 temps_(4, zone),
94 params_(4, zone), 97 params_(4, zone),
95 unresolved_(16, zone), 98 unresolved_(16, zone),
96 decls_(4, zone), 99 decls_(4, zone),
97 module_descriptor_(NULL), 100 module_descriptor_(NULL),
98 already_resolved_(true), 101 already_resolved_(true),
99 ast_value_factory_(value_factory), 102 ast_value_factory_(value_factory),
100 zone_(zone) { 103 zone_(zone),
104 consecutive_class_declaration_group_start_(-1) {
101 SetDefaults(scope_type, NULL, scope_info); 105 SetDefaults(scope_type, NULL, scope_info);
102 if (!scope_info.is_null()) { 106 if (!scope_info.is_null()) {
103 num_heap_slots_ = scope_info_->ContextLength(); 107 num_heap_slots_ = scope_info_->ContextLength();
104 } 108 }
105 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. 109 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
106 num_heap_slots_ = Max(num_heap_slots_, 110 num_heap_slots_ = Max(num_heap_slots_,
107 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); 111 static_cast<int>(Context::MIN_CONTEXT_SLOTS));
108 AddInnerScope(inner_scope); 112 AddInnerScope(inner_scope);
109 } 113 }
110 114
111 115
112 Scope::Scope(Zone* zone, Scope* inner_scope, 116 Scope::Scope(Zone* zone, Scope* inner_scope,
113 const AstRawString* catch_variable_name, 117 const AstRawString* catch_variable_name,
114 AstValueFactory* value_factory) 118 AstValueFactory* value_factory)
115 : inner_scopes_(1, zone), 119 : inner_scopes_(1, zone),
116 variables_(zone), 120 variables_(zone),
117 internals_(0, zone), 121 internals_(0, zone),
118 temps_(0, zone), 122 temps_(0, zone),
119 params_(0, zone), 123 params_(0, zone),
120 unresolved_(0, zone), 124 unresolved_(0, zone),
121 decls_(0, zone), 125 decls_(0, zone),
122 module_descriptor_(NULL), 126 module_descriptor_(NULL),
123 already_resolved_(true), 127 already_resolved_(true),
124 ast_value_factory_(value_factory), 128 ast_value_factory_(value_factory),
125 zone_(zone) { 129 zone_(zone),
130 consecutive_class_declaration_group_start_(-1) {
126 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); 131 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
127 AddInnerScope(inner_scope); 132 AddInnerScope(inner_scope);
128 ++num_var_or_const_; 133 ++num_var_or_const_;
129 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; 134 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
130 Variable* variable = variables_.Declare(this, 135 Variable* variable = variables_.Declare(this,
131 catch_variable_name, 136 catch_variable_name,
132 VAR, 137 VAR,
133 Variable::NORMAL, 138 Variable::NORMAL,
134 kCreatedInitialized); 139 kCreatedInitialized);
135 AllocateHeapSlot(variable); 140 AllocateHeapSlot(variable);
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 rest_parameter_ = var; 467 rest_parameter_ = var;
463 rest_index_ = num_parameters(); 468 rest_index_ = num_parameters();
464 } 469 }
465 params_.Add(var, zone()); 470 params_.Add(var, zone());
466 return var; 471 return var;
467 } 472 }
468 473
469 474
470 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, 475 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
471 InitializationFlag init_flag, Variable::Kind kind, 476 InitializationFlag init_flag, Variable::Kind kind,
472 MaybeAssignedFlag maybe_assigned_flag) { 477 MaybeAssignedFlag maybe_assigned_flag,
478 int consecutive_declaration_group_start) {
473 DCHECK(!already_resolved()); 479 DCHECK(!already_resolved());
474 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are 480 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
475 // introduces during variable allocation, INTERNAL variables are allocated 481 // introduces during variable allocation, INTERNAL variables are allocated
476 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). 482 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
477 DCHECK(IsDeclaredVariableMode(mode)); 483 DCHECK(IsDeclaredVariableMode(mode));
478 ++num_var_or_const_; 484 ++num_var_or_const_;
479 return variables_.Declare(this, name, mode, kind, init_flag, 485 return variables_.Declare(this, name, mode, kind, init_flag,
480 maybe_assigned_flag); 486 maybe_assigned_flag,
487 consecutive_declaration_group_start);
481 } 488 }
482 489
483 490
484 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { 491 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
485 DCHECK(is_script_scope()); 492 DCHECK(is_script_scope());
486 return variables_.Declare(this, 493 return variables_.Declare(this,
487 name, 494 name,
488 DYNAMIC_GLOBAL, 495 DYNAMIC_GLOBAL,
489 Variable::NORMAL, 496 Variable::NORMAL,
490 kCreatedInitialized); 497 kCreatedInitialized);
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after
1132 1139
1133 // Allow referencing the class name from methods of that class, even though 1140 // Allow referencing the class name from methods of that class, even though
1134 // the initializer position for class names is only after the body. 1141 // the initializer position for class names is only after the body.
1135 Scope* scope = this; 1142 Scope* scope = this;
1136 while (scope) { 1143 while (scope) {
1137 if (scope->ClassVariableForMethod() == var) return true; 1144 if (scope->ClassVariableForMethod() == var) return true;
1138 scope = scope->outer_scope(); 1145 scope = scope->outer_scope();
1139 } 1146 }
1140 1147
1141 // Allow references from methods to classes declared later, if we detect no 1148 // Allow references from methods to classes declared later, if we detect no
1142 // problematic dependency cycles. 1149 // problematic dependency cycles. Note that we can be inside multiple methods
1150 // at the same time, and it's enough if we find one where the reference is
1151 // allowed.
1152 scope = this;
1153 while (scope) {
rossberg 2015/04/21 13:30:02 A couple of observations: - I shouldn't need to lo
marja 2015/04/23 09:52:37 I rewrote the code so that it's closer to what you
1154 Variable* class_var = scope->ClassVariableForMethod();
1155 if (class_var && var->is_class()) {
1156 // A method is referring to some other class, possibly declared
1157 // later. Referring to a class declared earlier is always OK and covered
1158 // by the code outside this if. Here we only need to allow special cases
1159 // for referring to a class which is declared later.
1143 1160
1144 if (ClassVariableForMethod() && var->is_class()) { 1161 // Referring to a class C declared later is OK under the following
1145 // A method is referring to some other class, possibly declared 1162 // circumstances:
1146 // later. Referring to a class declared earlier is always OK and covered by
1147 // the code outside this if. Here we only need to allow special cases for
1148 // referring to a class which is declared later.
1149 1163
1150 // Referring to a class C declared later is OK under the following 1164 // 1. The class declarations are in a consecutive group with no other
1151 // circumstances: 1165 // declarations or statements in between, and
1152 1166
1153 // 1. The class declarations are in a consecutive group with no other 1167 // 2. There is no dependency cycle where the first edge is an
1154 // declarations or statements in between, and 1168 // initialization time dependency (computed property name or extends
1169 // clause) from C to something that depends on this class directly or
1170 // transitively.
1155 1171
1156 // 2. There is no dependency cycle where the first edge is an initialization 1172 // This is needed because a class ("class Name { }") creates two bindings
1157 // time dependency (computed property name or extends clause) from C to 1173 // (one in the outer scope, and one in the class scope). The method is a
1158 // something that depends on this class directly or transitively. 1174 // function scope inside the inner scope (class scope). The consecutive
1175 // class declarations are in the outer scope.
1176 if (class_var->corresponding_outer_class_variable()) {
1177 class_var = class_var->corresponding_outer_class_variable();
1178 }
1159 1179
1160 // TODO(marja,rossberg): implement these checks. Here we undershoot the 1180 // TODO(marja,rossberg): implement the dependency cycle detection. Here we
1161 // target and allow referring to any class. 1181 // undershoot the target and allow referring to any class in the same
1162 return true; 1182 // consectuive declaration group.
1183 if (class_var->consecutive_declaration_group_start() ==
1184 var->consecutive_declaration_group_start() &&
1185 class_var->consecutive_declaration_group_start() >= 0) {
1186 return true;
1187 }
1188 }
1189 scope = scope->outer_scope();
1163 } 1190 }
1164 1191
1165 // If both the use and the declaration are inside an eval scope (possibly 1192 // If both the use and the declaration are inside an eval scope (possibly
1166 // indirectly), or one of them is, we need to check whether they are inside 1193 // indirectly), or one of them is, we need to check whether they are inside
1167 // the same eval scope or different ones. 1194 // the same eval scope or different ones.
1168 1195
1169 // TODO(marja,rossberg): Detect errors across different evals (depends on the 1196 // TODO(marja,rossberg): Detect errors across different evals (depends on the
1170 // future of eval in strong mode). 1197 // future of eval in strong mode).
1171 const Scope* eval_for_use = NearestOuterEvalScope(); 1198 const Scope* eval_for_use = NearestOuterEvalScope();
1172 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); 1199 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope();
1173 1200
1174 if (proxy->position() != RelocInfo::kNoPosition && 1201 if (proxy->position() != RelocInfo::kNoPosition &&
1175 proxy->position() < var->initializer_position() && !var->is_function() && 1202 proxy->position() < var->initializer_position() && !var->is_function() &&
1176 eval_for_use == eval_for_declaration) { 1203 eval_for_use == eval_for_declaration) {
1177 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); 1204 DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
1178 ReportMessage(proxy->position(), proxy->end_position(), 1205 ReportMessage(proxy->position(), proxy->end_position(),
1179 "strong_use_before_declaration", proxy->raw_name()); 1206 "strong_use_before_declaration", proxy->raw_name());
1180 return false; 1207 return false;
1181 } 1208 }
1182 return true; 1209 return true;
1183 } 1210 }
1184 1211
1185 1212
1186 Variable* Scope::ClassVariableForMethod() const { 1213 Variable* Scope::ClassVariableForMethod() const {
1214 // TODO(marja, rossberg): This fails to find a class variable in the following
1215 // cases:
1216 // let A = class { ... }
1217 // It needs to be investigated whether this causes any practical problems.
1187 if (!is_function_scope()) return nullptr; 1218 if (!is_function_scope()) return nullptr;
1188 if (IsInObjectLiteral(function_kind_)) return nullptr; 1219 if (IsInObjectLiteral(function_kind_)) return nullptr;
1189 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && 1220 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) &&
1190 !IsAccessorFunction(function_kind_)) { 1221 !IsAccessorFunction(function_kind_)) {
1191 return nullptr; 1222 return nullptr;
1192 } 1223 }
1193 DCHECK_NOT_NULL(outer_scope_); 1224 DCHECK_NOT_NULL(outer_scope_);
1194 DCHECK(outer_scope_->is_class_scope()); 1225 DCHECK(outer_scope_->is_class_scope());
1195 // The class scope contains at most one variable, the class name. 1226 // The class scope contains at most one variable, the class name.
1196 DCHECK(outer_scope_->variables_.occupancy() <= 1); 1227 DCHECK(outer_scope_->variables_.occupancy() <= 1);
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); 1519 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
1489 } 1520 }
1490 1521
1491 1522
1492 int Scope::ContextLocalCount() const { 1523 int Scope::ContextLocalCount() const {
1493 if (num_heap_slots() == 0) return 0; 1524 if (num_heap_slots() == 0) return 0;
1494 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1525 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
1495 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); 1526 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
1496 } 1527 }
1497 } } // namespace v8::internal 1528 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698