Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
| 6 | 6 |
| 7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/compiler.h" | 8 #include "src/compiler.h" |
| 9 #include "src/interpreter/control-flow-builders.h" | 9 #include "src/interpreter/control-flow-builders.h" |
| 10 #include "src/objects.h" | 10 #include "src/objects.h" |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 | 207 |
| 208 Register NewRegister() { | 208 Register NewRegister() { |
| 209 ExpressionResultScope* current_scope = generator()->execution_result(); | 209 ExpressionResultScope* current_scope = generator()->execution_result(); |
| 210 if ((current_scope == this) || | 210 if ((current_scope == this) || |
| 211 (current_scope->outer() == this && | 211 (current_scope->outer() == this && |
| 212 !current_scope->allocator_.hasConsecutiveAllocations())) { | 212 !current_scope->allocator_.hasConsecutiveAllocations())) { |
| 213 // Regular case - Allocating registers in current or outer context. | 213 // Regular case - Allocating registers in current or outer context. |
| 214 // VisitForRegisterValue allocates register in outer context. | 214 // VisitForRegisterValue allocates register in outer context. |
| 215 return allocator_.NewRegister(); | 215 return allocator_.NewRegister(); |
| 216 } else { | 216 } else { |
| 217 // We need this when allocating registers due to an Assignment hazard. | 217 // Allocating a register other than the current or outer scope: |
| 218 // It might be expensive to walk the full context chain and compute the | 218 // It might be expensive to walk the full context chain and compute the |
| 219 // list of consecutive reservations in the innerscopes. So allocates a | 219 // list of consecutive reservations in the innerscopes. So allocates a |
| 220 // new unallocated temporary register. | 220 // new unallocated temporary register. We needed this in an implementation |
| 221 // of Assignment hazard. | |
| 222 // TODO(mythria): Reevaluate this after we have the new assignment hazard | |
| 223 // implementation. Remove this if not required. | |
|
rmcilroy
2016/01/12 14:43:17
I'd rather just remove this now if it is no longer
mythria
2016/01/12 16:53:21
Done.
| |
| 221 return allocator_.AllocateNewRegister(); | 224 return allocator_.AllocateNewRegister(); |
| 222 } | 225 } |
| 223 } | 226 } |
| 224 | 227 |
| 225 void PrepareForConsecutiveAllocations(size_t count) { | 228 void PrepareForConsecutiveAllocations(size_t count) { |
| 226 allocator_.PrepareForConsecutiveAllocations(count); | 229 allocator_.PrepareForConsecutiveAllocations(count); |
| 227 } | 230 } |
| 228 | 231 |
| 229 Register NextConsecutiveRegister() { | 232 Register NextConsecutiveRegister() { |
| 230 return allocator_.NextConsecutiveRegister(); | 233 return allocator_.NextConsecutiveRegister(); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 305 set_result_identified(); | 308 set_result_identified(); |
| 306 } | 309 } |
| 307 | 310 |
| 308 Register ResultRegister() const { return result_register_; } | 311 Register ResultRegister() const { return result_register_; } |
| 309 | 312 |
| 310 private: | 313 private: |
| 311 Register result_register_; | 314 Register result_register_; |
| 312 }; | 315 }; |
| 313 | 316 |
| 314 | 317 |
| 315 BytecodeGenerator::AssignmentHazardHelper::AssignmentHazardHelper( | |
| 316 BytecodeGenerator* generator) | |
| 317 : generator_(generator), | |
| 318 alias_mappings_(generator->zone()), | |
| 319 aliased_locals_and_parameters_(generator->zone()), | |
| 320 execution_result_(nullptr), | |
| 321 scope_depth_(0) {} | |
| 322 | |
| 323 | |
| 324 void BytecodeGenerator::AssignmentHazardHelper::EnterScope() { | |
| 325 DCHECK_GE(scope_depth_, 0); | |
| 326 if (scope_depth_++ == 0) { | |
| 327 execution_result_ = generator_->execution_result(); | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 | |
| 332 void BytecodeGenerator::AssignmentHazardHelper::LeaveScope() { | |
| 333 DCHECK_GT(scope_depth_, 0); | |
| 334 if (--scope_depth_ == 0) { | |
| 335 DCHECK_EQ(execution_result_, generator_->execution_result()); | |
| 336 RestoreAliasedLocalsAndParameters(); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 | |
| 341 // Returns a register that a load instruction should use when | |
| 342 // loading from |reg|. This allows an alias for a modified version | |
| 343 // of |reg| to be used within a hazard regions. | |
| 344 MUST_USE_RESULT Register | |
| 345 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForLoad(Register reg) { | |
| 346 if (scope_depth_ == 0) { | |
| 347 return reg; | |
| 348 } else { | |
| 349 // A load from |reg| is to be issued. The register is placed in | |
| 350 // the mappings table initially mapping to itself. Future stores | |
| 351 // will update the mapping with temporaries thus preserving the | |
| 352 // original register's value. | |
| 353 // | |
| 354 // NB This insert only updates the table if no mapping exists | |
| 355 // already (std::map::insert semantics). | |
| 356 auto insert_result = | |
| 357 alias_mappings_.insert(std::make_pair(reg.index(), reg.index())); | |
| 358 auto mapping = insert_result.first; | |
| 359 // Return the current alias for reg. | |
| 360 return Register(mapping->second); | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 | |
| 365 // Returns a register that a store instruction should use when | |
| 366 // loading from |reg|. This allows an alias for a modified version | |
| 367 // of |reg| to be used within hazard regions. | |
| 368 MUST_USE_RESULT Register | |
| 369 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForStore(Register reg) { | |
| 370 if (scope_depth_ == 0 || | |
| 371 alias_mappings_.find(reg.index()) == alias_mappings_.end()) { | |
| 372 // If not in a hazard region or a load for this register has not | |
| 373 // occurred no mapping is necessary. | |
| 374 return reg; | |
| 375 } else { | |
| 376 // Storing to a register with 1 or more loads issued. The | |
| 377 // register is mapped to a temporary alias so we don't overwrite | |
| 378 // the lhs value, e.g. y = x + (x = 1); has a register for x on | |
| 379 // the lhs and needs a new register x' for the upcoming store on | |
| 380 // the rhs as the original x is an input to the add operation. | |
| 381 Register alias = execution_result_->NewRegister(); | |
| 382 alias_mappings_[reg.index()] = alias.index(); | |
| 383 if (generator_->builder()->RegisterIsParameterOrLocal(reg)) { | |
| 384 // Keep track of registers that need to be restored on exit | |
| 385 // from the assignment hazard region. | |
| 386 aliased_locals_and_parameters_.insert(reg.index()); | |
| 387 } | |
| 388 return alias; | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 | |
| 393 void BytecodeGenerator::AssignmentHazardHelper:: | |
| 394 RestoreAliasedLocalsAndParameters() { | |
| 395 DCHECK(scope_depth_ == 0); | |
| 396 // Move temporary registers holding values for locals and | |
| 397 // parameters back into their local and parameter registers. | |
| 398 for (auto reg = aliased_locals_and_parameters_.begin(); | |
| 399 reg != aliased_locals_and_parameters_.end(); reg++) { | |
| 400 auto mapping = alias_mappings_.find(*reg); | |
| 401 if (mapping != alias_mappings_.end()) { | |
| 402 generator_->builder()->MoveRegister(Register(mapping->second), | |
| 403 Register(*reg)); | |
| 404 } | |
| 405 } | |
| 406 alias_mappings_.clear(); | |
| 407 aliased_locals_and_parameters_.clear(); | |
| 408 } | |
| 409 | |
| 410 | |
| 411 class BytecodeGenerator::AssignmentHazardScope final { | |
| 412 public: | |
| 413 explicit AssignmentHazardScope(BytecodeGenerator* generator) | |
| 414 : generator_(generator) { | |
| 415 generator_->assignment_hazard_helper()->EnterScope(); | |
| 416 } | |
| 417 | |
| 418 ~AssignmentHazardScope() { | |
| 419 generator_->assignment_hazard_helper()->LeaveScope(); | |
| 420 } | |
| 421 | |
| 422 private: | |
| 423 BytecodeGenerator* generator_; | |
| 424 | |
| 425 DISALLOW_COPY_AND_ASSIGN(AssignmentHazardScope); | |
| 426 }; | |
| 427 | |
| 428 | |
| 429 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 318 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
| 430 : isolate_(isolate), | 319 : isolate_(isolate), |
| 431 zone_(zone), | 320 zone_(zone), |
| 432 builder_(isolate, zone), | 321 builder_(isolate, zone), |
| 433 info_(nullptr), | 322 info_(nullptr), |
| 434 scope_(nullptr), | 323 scope_(nullptr), |
| 435 globals_(0, zone), | 324 globals_(0, zone), |
| 436 execution_control_(nullptr), | 325 execution_control_(nullptr), |
| 437 execution_context_(nullptr), | 326 execution_context_(nullptr), |
| 438 execution_result_(nullptr), | 327 execution_result_(nullptr) { |
| 439 assignment_hazard_helper_(this) { | |
| 440 InitializeAstVisitor(isolate); | 328 InitializeAstVisitor(isolate); |
| 441 } | 329 } |
| 442 | 330 |
| 443 | 331 |
| 444 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 332 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| 445 set_info(info); | 333 set_info(info); |
| 446 set_scope(info->scope()); | 334 set_scope(info->scope()); |
| 447 | 335 |
| 448 // Initialize the incoming context. | 336 // Initialize the incoming context. |
| 449 ContextScope incoming_context(this, scope(), false); | 337 ContextScope incoming_context(this, scope(), false); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 701 builder()->Return(); | 589 builder()->Return(); |
| 702 } | 590 } |
| 703 | 591 |
| 704 | 592 |
| 705 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 593 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
| 706 UNIMPLEMENTED(); | 594 UNIMPLEMENTED(); |
| 707 } | 595 } |
| 708 | 596 |
| 709 | 597 |
| 710 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 598 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 599 // We need this scope because we visit for register values. We have to | |
| 600 // maintain a execution result scope where registers can be allocated. | |
| 601 EffectResultScope switch_result_scope(this); | |
|
rmcilroy
2016/01/12 14:43:17
nit - effect_results_scope
mythria
2016/01/12 16:53:21
Done.
| |
| 711 ZoneList<CaseClause*>* clauses = stmt->cases(); | 602 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 712 SwitchBuilder switch_builder(builder(), clauses->length()); | 603 SwitchBuilder switch_builder(builder(), clauses->length()); |
| 713 ControlScopeForBreakable scope(this, stmt, &switch_builder); | 604 ControlScopeForBreakable scope(this, stmt, &switch_builder); |
| 714 int default_index = -1; | 605 int default_index = -1; |
| 715 | 606 |
| 716 // Keep the switch value in a register until a case matches. | 607 // Keep the switch value in a register until a case matches. |
| 717 Register tag = VisitForRegisterValue(stmt->tag()); | 608 Register tag = VisitForRegisterValue(stmt->tag()); |
| 718 | 609 |
| 719 // Iterate over all cases and create nodes for label comparison. | 610 // Iterate over all cases and create nodes for label comparison. |
| 720 BytecodeLabel done_label; | 611 BytecodeLabel done_label; |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1274 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 1165 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 1275 } | 1166 } |
| 1276 | 1167 |
| 1277 | 1168 |
| 1278 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1169 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 1279 FeedbackVectorSlot slot, | 1170 FeedbackVectorSlot slot, |
| 1280 TypeofMode typeof_mode) { | 1171 TypeofMode typeof_mode) { |
| 1281 switch (variable->location()) { | 1172 switch (variable->location()) { |
| 1282 case VariableLocation::LOCAL: { | 1173 case VariableLocation::LOCAL: { |
| 1283 Register source(Register(variable->index())); | 1174 Register source(Register(variable->index())); |
| 1284 source = assignment_hazard_helper()->GetRegisterForLoad(source); | 1175 builder()->LoadAccumulatorWithRegister(source); |
| 1285 execution_result()->SetResultInRegister(source); | 1176 execution_result()->SetResultInAccumulator(); |
| 1286 break; | 1177 break; |
| 1287 } | 1178 } |
| 1288 case VariableLocation::PARAMETER: { | 1179 case VariableLocation::PARAMETER: { |
| 1289 // The parameter indices are shifted by 1 (receiver is variable | 1180 // The parameter indices are shifted by 1 (receiver is variable |
| 1290 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1181 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1291 Register source = builder()->Parameter(variable->index() + 1); | 1182 Register source = builder()->Parameter(variable->index() + 1); |
| 1292 source = assignment_hazard_helper()->GetRegisterForLoad(source); | 1183 builder()->LoadAccumulatorWithRegister(source); |
| 1293 execution_result()->SetResultInRegister(source); | 1184 execution_result()->SetResultInAccumulator(); |
| 1294 break; | 1185 break; |
| 1295 } | 1186 } |
| 1296 case VariableLocation::GLOBAL: | 1187 case VariableLocation::GLOBAL: |
| 1297 case VariableLocation::UNALLOCATED: { | 1188 case VariableLocation::UNALLOCATED: { |
| 1298 builder()->LoadGlobal(variable->name(), feedback_index(slot), | 1189 builder()->LoadGlobal(variable->name(), feedback_index(slot), |
| 1299 language_mode(), typeof_mode); | 1190 language_mode(), typeof_mode); |
| 1300 execution_result()->SetResultInAccumulator(); | 1191 execution_result()->SetResultInAccumulator(); |
| 1301 break; | 1192 break; |
| 1302 } | 1193 } |
| 1303 case VariableLocation::CONTEXT: { | 1194 case VariableLocation::CONTEXT: { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1351 return register_scope.ResultRegister(); | 1242 return register_scope.ResultRegister(); |
| 1352 } | 1243 } |
| 1353 | 1244 |
| 1354 | 1245 |
| 1355 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 1246 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| 1356 FeedbackVectorSlot slot) { | 1247 FeedbackVectorSlot slot) { |
| 1357 switch (variable->location()) { | 1248 switch (variable->location()) { |
| 1358 case VariableLocation::LOCAL: { | 1249 case VariableLocation::LOCAL: { |
| 1359 // TODO(rmcilroy): support const mode initialization. | 1250 // TODO(rmcilroy): support const mode initialization. |
| 1360 Register destination(variable->index()); | 1251 Register destination(variable->index()); |
| 1361 destination = | |
| 1362 assignment_hazard_helper()->GetRegisterForStore(destination); | |
| 1363 builder()->StoreAccumulatorInRegister(destination); | 1252 builder()->StoreAccumulatorInRegister(destination); |
| 1364 break; | 1253 break; |
| 1365 } | 1254 } |
| 1366 case VariableLocation::PARAMETER: { | 1255 case VariableLocation::PARAMETER: { |
| 1367 // The parameter indices are shifted by 1 (receiver is variable | 1256 // The parameter indices are shifted by 1 (receiver is variable |
| 1368 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1257 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1369 Register destination(builder()->Parameter(variable->index() + 1)); | 1258 Register destination(builder()->Parameter(variable->index() + 1)); |
| 1370 destination = | |
| 1371 assignment_hazard_helper()->GetRegisterForStore(destination); | |
| 1372 | |
| 1373 builder()->StoreAccumulatorInRegister(destination); | 1259 builder()->StoreAccumulatorInRegister(destination); |
| 1374 break; | 1260 break; |
| 1375 } | 1261 } |
| 1376 case VariableLocation::GLOBAL: | 1262 case VariableLocation::GLOBAL: |
| 1377 case VariableLocation::UNALLOCATED: { | 1263 case VariableLocation::UNALLOCATED: { |
| 1378 builder()->StoreGlobal(variable->name(), feedback_index(slot), | 1264 builder()->StoreGlobal(variable->name(), feedback_index(slot), |
| 1379 language_mode()); | 1265 language_mode()); |
| 1380 break; | 1266 break; |
| 1381 } | 1267 } |
| 1382 case VariableLocation::CONTEXT: { | 1268 case VariableLocation::CONTEXT: { |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1963 VisitLogicalAndExpression(binop); | 1849 VisitLogicalAndExpression(binop); |
| 1964 break; | 1850 break; |
| 1965 default: | 1851 default: |
| 1966 VisitArithmeticExpression(binop); | 1852 VisitArithmeticExpression(binop); |
| 1967 break; | 1853 break; |
| 1968 } | 1854 } |
| 1969 } | 1855 } |
| 1970 | 1856 |
| 1971 | 1857 |
| 1972 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1858 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 1973 // The evaluation of binary comparison expressions has an assignment | |
| 1974 // hazard because the lhs may be a variable that evaluates to a | |
| 1975 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) | |
| 1976 // To get a correct result the generator treats the inner assigment | |
| 1977 // as being made to a temporary x' that is spilled on exit of the | |
| 1978 // assignment hazard. | |
| 1979 AssignmentHazardScope assignment_hazard_scope(this); | |
| 1980 | |
| 1981 Register lhs = VisitForRegisterValue(expr->left()); | 1859 Register lhs = VisitForRegisterValue(expr->left()); |
| 1982 VisitForAccumulatorValue(expr->right()); | 1860 VisitForAccumulatorValue(expr->right()); |
| 1983 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); | 1861 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); |
| 1984 execution_result()->SetResultInAccumulator(); | 1862 execution_result()->SetResultInAccumulator(); |
| 1985 } | 1863 } |
| 1986 | 1864 |
| 1987 | 1865 |
| 1988 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { | 1866 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
| 1989 // The evaluation of binary arithmetic expressions has an assignment | |
| 1990 // hazard because the lhs may be a variable that evaluates to a | |
| 1991 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) | |
| 1992 // To get a correct result the generator treats the inner assigment | |
| 1993 // as being made to a temporary x' that is spilled on exit of the | |
| 1994 // assignment hazard. | |
| 1995 AssignmentHazardScope assignment_hazard_scope(this); | |
| 1996 | |
| 1997 Register lhs = VisitForRegisterValue(expr->left()); | 1867 Register lhs = VisitForRegisterValue(expr->left()); |
| 1998 VisitForAccumulatorValue(expr->right()); | 1868 VisitForAccumulatorValue(expr->right()); |
| 1999 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); | 1869 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); |
| 2000 execution_result()->SetResultInAccumulator(); | 1870 execution_result()->SetResultInAccumulator(); |
| 2001 } | 1871 } |
| 2002 | 1872 |
| 2003 | 1873 |
| 2004 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } | 1874 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } |
| 2005 | 1875 |
| 2006 | 1876 |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2281 } | 2151 } |
| 2282 | 2152 |
| 2283 | 2153 |
| 2284 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2154 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 2285 return info()->feedback_vector()->GetIndex(slot); | 2155 return info()->feedback_vector()->GetIndex(slot); |
| 2286 } | 2156 } |
| 2287 | 2157 |
| 2288 } // namespace interpreter | 2158 } // namespace interpreter |
| 2289 } // namespace internal | 2159 } // namespace internal |
| 2290 } // namespace v8 | 2160 } // namespace v8 |
| OLD | NEW |