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/compiler.h" | 7 #include "src/compiler.h" |
8 #include "src/interpreter/control-flow-builders.h" | 8 #include "src/interpreter/control-flow-builders.h" |
9 #include "src/objects.h" | 9 #include "src/objects.h" |
10 #include "src/parser.h" | 10 #include "src/parser.h" |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 ExpressionResultScope* outer_; | 231 ExpressionResultScope* outer_; |
232 TemporaryRegisterScope allocator_; | 232 TemporaryRegisterScope allocator_; |
233 bool result_identified_; | 233 bool result_identified_; |
234 | 234 |
235 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); | 235 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); |
236 }; | 236 }; |
237 | 237 |
238 | 238 |
239 // Scoped class used when the result of the current expression is not | 239 // Scoped class used when the result of the current expression is not |
240 // expected to produce a result. | 240 // expected to produce a result. |
241 class BytecodeGenerator::EffectResultScope final | 241 class BytecodeGenerator::EffectResultScope : public ExpressionResultScope { |
rmcilroy
2015/11/05 16:34:51
Make final again
oth
2015/11/12 11:32:15
Done.
| |
242 : public ExpressionResultScope { | |
243 public: | 242 public: |
244 explicit EffectResultScope(BytecodeGenerator* generator) | 243 explicit EffectResultScope(BytecodeGenerator* generator) |
245 : ExpressionResultScope(generator, Expression::kEffect) { | 244 : ExpressionResultScope(generator, Expression::kEffect) { |
246 set_result_identified(); | 245 set_result_identified(); |
247 } | 246 } |
248 | 247 |
249 virtual void SetResultInAccumulator() {} | 248 virtual void SetResultInAccumulator() {} |
250 virtual void SetResultInRegister(Register reg) {} | 249 virtual void SetResultInRegister(Register reg) {} |
251 }; | 250 }; |
252 | 251 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 set_result_identified(); | 289 set_result_identified(); |
291 } | 290 } |
292 | 291 |
293 Register ResultRegister() const { return result_register_; } | 292 Register ResultRegister() const { return result_register_; } |
294 | 293 |
295 private: | 294 private: |
296 Register result_register_; | 295 Register result_register_; |
297 }; | 296 }; |
298 | 297 |
299 | 298 |
299 // Scope providing protection against potentially conflicting patterns | |
300 // of variable loads and stores in binary expressions. | |
301 class BytecodeGenerator::AssignmentHazardScope final BASE_EMBEDDED { | |
302 public: | |
303 explicit AssignmentHazardScope(BytecodeGenerator* generator) | |
304 : alias_mappings_(generator->zone()), | |
305 aliased_locals_and_parameters_(generator->zone()), | |
306 register_scope_(generator->builder()) { | |
307 if (generator->assignment_hazard_scope() == nullptr) { | |
308 // Set self as the assignment_hazard_scope if one doesn't | |
309 // exist. Only the outermost participates in register remapping. | |
310 generator_ = generator; | |
311 generator->set_assignment_hazard_scope(this); | |
rmcilroy
2015/11/05 16:34:51
Rather than creating a map and set for each Assign
oth
2015/11/12 11:32:15
Okay, the helper class an inner class of BytecodeG
| |
312 } else { | |
313 generator_ = nullptr; | |
314 } | |
315 } | |
316 | |
317 ~AssignmentHazardScope() { | |
318 if (is_outermost_scope()) { | |
319 RestoreAliasedLocalsAndParameters(); | |
320 generator()->set_assignment_hazard_scope(nullptr); | |
321 } | |
322 } | |
323 | |
324 // Returns a register that a load instruction should use when | |
325 // loading from |reg|. This allows an alias for a modified version | |
326 // of |reg| to be used within a hazard regions. | |
327 MUST_USE_RESULT Register GetRegisterForLoad(Register reg) { | |
328 DCHECK(is_outermost_scope()); | |
329 // A load from |reg| is to be issued. The register is placed in | |
330 // the mappings table initially mapping to itself. Future stores | |
331 // will update the mapping with temporaries thus preserving the | |
332 // original register's value. | |
333 // | |
334 // NB This insert only updates the table if no mapping exists | |
335 // already (std::map::insert semantics). | |
336 auto insert_result = | |
337 alias_mappings_.insert(std::make_pair(reg.index(), reg.index())); | |
338 auto mapping = insert_result.first; | |
339 // Return the current alias for reg. | |
340 return Register(mapping->second); | |
341 } | |
342 | |
343 // Returns a register that a store instruction should use when | |
344 // loading from |reg|. This allows an alias for a modified version | |
345 // of |reg| to be used within hazard regions. | |
346 MUST_USE_RESULT Register GetRegisterForStore(Register reg) { | |
347 DCHECK(is_outermost_scope()); | |
348 if (alias_mappings_.find(reg.index()) == alias_mappings_.end()) { | |
349 // If not in a hazard region or a load for this register has not | |
350 // occurred no mapping is necessary. | |
351 return reg; | |
352 } else { | |
353 // Storing to a register with 1 or more loads issued. The | |
354 // register is mapped to a temporary alias so we don't overwrite | |
355 // the lhs value, e.g. y = x + (x = 1); has a register for x on | |
356 // the lhs and needs a new register x' for the upcoming store on | |
357 // the rhs as the original x is an input to the add operation. | |
358 Register alias = register_scope_.NewRegister(); | |
359 alias_mappings_[reg.index()] = alias.index(); | |
360 if (generator()->builder()->RegisterIsParameterOrLocal(reg)) { | |
361 // Keep track of registers that need to be restored on exit | |
362 // from the assignment hazard region. | |
363 aliased_locals_and_parameters_.insert(reg.index()); | |
364 } | |
365 return alias; | |
366 } | |
367 } | |
368 | |
369 private: | |
370 void RestoreAliasedLocalsAndParameters() { | |
371 // Move temporary registers holding values for locals and | |
372 // parameters back into their local and parameter registers. | |
373 for (auto reg = aliased_locals_and_parameters_.begin(); | |
374 reg != aliased_locals_and_parameters_.end(); reg++) { | |
375 auto mapping = alias_mappings_.find(*reg); | |
376 if (mapping != alias_mappings_.end()) { | |
377 builder()->MoveRegister(Register(mapping->second), Register(*reg)); | |
378 } | |
379 } | |
380 alias_mappings_.clear(); | |
381 aliased_locals_and_parameters_.clear(); | |
382 } | |
383 | |
384 BytecodeArrayBuilder* builder() const { return generator()->builder(); } | |
385 BytecodeGenerator* generator() const { return generator_; } | |
386 bool is_outermost_scope() const { return generator_ != nullptr; } | |
387 | |
388 BytecodeGenerator* generator_; | |
389 ZoneMap<int, int> alias_mappings_; | |
390 ZoneSet<int> aliased_locals_and_parameters_; | |
391 TemporaryRegisterScope register_scope_; | |
392 | |
393 DISALLOW_COPY_AND_ASSIGN(AssignmentHazardScope); | |
394 }; | |
395 | |
396 | |
300 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 397 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
301 : isolate_(isolate), | 398 : isolate_(isolate), |
302 zone_(zone), | 399 zone_(zone), |
303 builder_(isolate, zone), | 400 builder_(isolate, zone), |
304 info_(nullptr), | 401 info_(nullptr), |
305 scope_(nullptr), | 402 scope_(nullptr), |
306 globals_(0, zone), | 403 globals_(0, zone), |
307 execution_control_(nullptr), | 404 execution_control_(nullptr), |
308 execution_context_(nullptr), | 405 execution_context_(nullptr), |
309 execution_result_(nullptr), | 406 execution_result_(nullptr), |
310 binary_expression_depth_(0), | 407 assignment_hazard_scope_(nullptr) { |
311 binary_expression_hazard_set_(zone) { | |
312 InitializeAstVisitor(isolate); | 408 InitializeAstVisitor(isolate); |
313 } | 409 } |
314 | 410 |
315 | 411 |
316 BytecodeGenerator::~BytecodeGenerator() {} | 412 BytecodeGenerator::~BytecodeGenerator() {} |
317 | 413 |
318 | 414 |
319 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 415 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
320 set_info(info); | 416 set_info(info); |
321 set_scope(info->scope()); | 417 set_scope(info->scope()); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
499 builder()->LoadLiteral(Smi::FromInt(encoded_flags)); | 595 builder()->LoadLiteral(Smi::FromInt(encoded_flags)); |
500 builder()->StoreAccumulatorInRegister(flags); | 596 builder()->StoreAccumulatorInRegister(flags); |
501 DCHECK(flags.index() == pairs.index() + 1); | 597 DCHECK(flags.index() == pairs.index() + 1); |
502 | 598 |
503 builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2); | 599 builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2); |
504 globals()->clear(); | 600 globals()->clear(); |
505 } | 601 } |
506 | 602 |
507 | 603 |
508 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 604 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
509 // TODO(rmcilroy): Replace this with a StatementResultScope when it exists. | 605 EffectResultScope statement_result_scope(this); |
510 EffectResultScope effect_scope(this); | |
511 VisitForEffect(stmt->expression()); | 606 VisitForEffect(stmt->expression()); |
512 } | 607 } |
513 | 608 |
514 | 609 |
515 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | 610 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
516 } | 611 } |
517 | 612 |
518 | 613 |
519 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { | 614 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { |
520 BytecodeLabel else_label, end_label; | 615 BytecodeLabel else_label, end_label; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
552 execution_control()->Continue(stmt->target()); | 647 execution_control()->Continue(stmt->target()); |
553 } | 648 } |
554 | 649 |
555 | 650 |
556 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 651 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
557 execution_control()->Break(stmt->target()); | 652 execution_control()->Break(stmt->target()); |
558 } | 653 } |
559 | 654 |
560 | 655 |
561 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 656 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
562 EffectResultScope effect_scope(this); | 657 EffectResultScope statement_result_scope(this); |
563 VisitForAccumulatorValue(stmt->expression()); | 658 VisitForAccumulatorValue(stmt->expression()); |
564 builder()->Return(); | 659 builder()->Return(); |
565 } | 660 } |
566 | 661 |
567 | 662 |
568 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 663 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
569 UNIMPLEMENTED(); | 664 UNIMPLEMENTED(); |
570 } | 665 } |
571 | 666 |
572 | 667 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { | 716 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { |
622 // Handled entirely in VisitSwitchStatement. | 717 // Handled entirely in VisitSwitchStatement. |
623 UNREACHABLE(); | 718 UNREACHABLE(); |
624 } | 719 } |
625 | 720 |
626 | 721 |
627 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 722 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
628 LoopBuilder loop_builder(builder()); | 723 LoopBuilder loop_builder(builder()); |
629 ControlScopeForIteration execution_control(this, stmt, &loop_builder); | 724 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
630 BytecodeLabel body_label, condition_label, done_label; | 725 BytecodeLabel body_label, condition_label, done_label; |
631 | |
632 if (stmt->cond()->ToBooleanIsFalse()) { | 726 if (stmt->cond()->ToBooleanIsFalse()) { |
633 Visit(stmt->body()); | 727 Visit(stmt->body()); |
634 // Bind condition_label and done_label for processing continue and break. | 728 // Bind condition_label and done_label for processing continue and break. |
635 builder()->Bind(&condition_label); | 729 builder()->Bind(&condition_label); |
636 builder()->Bind(&done_label); | 730 builder()->Bind(&done_label); |
637 } else { | 731 } else { |
638 builder()->Bind(&body_label); | 732 builder()->Bind(&body_label); |
639 Visit(stmt->body()); | 733 Visit(stmt->body()); |
640 | 734 |
641 builder()->Bind(&condition_label); | 735 builder()->Bind(&condition_label); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
757 break; | 851 break; |
758 } | 852 } |
759 case NAMED_SUPER_PROPERTY: | 853 case NAMED_SUPER_PROPERTY: |
760 case KEYED_SUPER_PROPERTY: | 854 case KEYED_SUPER_PROPERTY: |
761 UNIMPLEMENTED(); | 855 UNIMPLEMENTED(); |
762 } | 856 } |
763 } | 857 } |
764 | 858 |
765 | 859 |
766 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 860 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
767 // TODO(oth): For now we need a parent scope for paths that end up | 861 EffectResultScope statement_result_scope(this); |
768 // in VisitLiteral which can allocate in the parent scope. A future | |
769 // CL in preparation will add a StatementResultScope that will | |
770 // remove the need for this EffectResultScope. | |
771 EffectResultScope result_scope(this); | |
772 | 862 |
773 if (stmt->subject()->IsNullLiteral() || | 863 if (stmt->subject()->IsNullLiteral() || |
774 stmt->subject()->IsUndefinedLiteral(isolate())) { | 864 stmt->subject()->IsUndefinedLiteral(isolate())) { |
775 // ForIn generates lots of code, skip if it wouldn't produce any effects. | 865 // ForIn generates lots of code, skip if it wouldn't produce any effects. |
776 return; | 866 return; |
777 } | 867 } |
778 | 868 |
779 LoopBuilder loop_builder(builder()); | 869 LoopBuilder loop_builder(builder()); |
780 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 870 ControlScopeForIteration control_scope(this, stmt, &loop_builder); |
781 | 871 |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1191 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 1281 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
1192 } | 1282 } |
1193 | 1283 |
1194 | 1284 |
1195 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1285 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
1196 FeedbackVectorSlot slot, | 1286 FeedbackVectorSlot slot, |
1197 TypeofMode typeof_mode) { | 1287 TypeofMode typeof_mode) { |
1198 switch (variable->location()) { | 1288 switch (variable->location()) { |
1199 case VariableLocation::LOCAL: { | 1289 case VariableLocation::LOCAL: { |
1200 Register source(Register(variable->index())); | 1290 Register source(Register(variable->index())); |
1291 if (assignment_hazard_scope()) { | |
1292 source = assignment_hazard_scope()->GetRegisterForLoad(source); | |
1293 } | |
1201 execution_result()->SetResultInRegister(source); | 1294 execution_result()->SetResultInRegister(source); |
1202 break; | 1295 break; |
1203 } | 1296 } |
1204 case VariableLocation::PARAMETER: { | 1297 case VariableLocation::PARAMETER: { |
1205 // The parameter indices are shifted by 1 (receiver is variable | 1298 // The parameter indices are shifted by 1 (receiver is variable |
1206 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1299 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
1207 Register source = builder()->Parameter(variable->index() + 1); | 1300 Register source = builder()->Parameter(variable->index() + 1); |
1301 if (assignment_hazard_scope()) { | |
1302 source = assignment_hazard_scope()->GetRegisterForLoad(source); | |
1303 } | |
1208 execution_result()->SetResultInRegister(source); | 1304 execution_result()->SetResultInRegister(source); |
1209 break; | 1305 break; |
1210 } | 1306 } |
1211 case VariableLocation::GLOBAL: | 1307 case VariableLocation::GLOBAL: |
1212 case VariableLocation::UNALLOCATED: { | 1308 case VariableLocation::UNALLOCATED: { |
1213 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); | 1309 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); |
1214 builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(), | 1310 builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(), |
1215 typeof_mode); | 1311 typeof_mode); |
1216 execution_result()->SetResultInAccumulator(); | 1312 execution_result()->SetResultInAccumulator(); |
1217 break; | 1313 break; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1262 return register_scope.ResultRegister(); | 1358 return register_scope.ResultRegister(); |
1263 } | 1359 } |
1264 | 1360 |
1265 | 1361 |
1266 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 1362 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
1267 FeedbackVectorSlot slot) { | 1363 FeedbackVectorSlot slot) { |
1268 switch (variable->location()) { | 1364 switch (variable->location()) { |
1269 case VariableLocation::LOCAL: { | 1365 case VariableLocation::LOCAL: { |
1270 // TODO(rmcilroy): support const mode initialization. | 1366 // TODO(rmcilroy): support const mode initialization. |
1271 Register destination(variable->index()); | 1367 Register destination(variable->index()); |
1368 if (assignment_hazard_scope()) { | |
1369 destination = | |
1370 assignment_hazard_scope()->GetRegisterForStore(destination); | |
1371 } | |
1272 builder()->StoreAccumulatorInRegister(destination); | 1372 builder()->StoreAccumulatorInRegister(destination); |
1273 RecordStoreToRegister(destination); | |
1274 break; | 1373 break; |
1275 } | 1374 } |
1276 case VariableLocation::PARAMETER: { | 1375 case VariableLocation::PARAMETER: { |
1277 // The parameter indices are shifted by 1 (receiver is variable | 1376 // The parameter indices are shifted by 1 (receiver is variable |
1278 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1377 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
1279 Register destination(builder()->Parameter(variable->index() + 1)); | 1378 Register destination(builder()->Parameter(variable->index() + 1)); |
1379 if (assignment_hazard_scope()) { | |
1380 destination = | |
1381 assignment_hazard_scope()->GetRegisterForStore(destination); | |
1382 } | |
1280 builder()->StoreAccumulatorInRegister(destination); | 1383 builder()->StoreAccumulatorInRegister(destination); |
1281 RecordStoreToRegister(destination); | |
1282 break; | 1384 break; |
1283 } | 1385 } |
1284 case VariableLocation::GLOBAL: | 1386 case VariableLocation::GLOBAL: |
1285 case VariableLocation::UNALLOCATED: { | 1387 case VariableLocation::UNALLOCATED: { |
1286 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); | 1388 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); |
1287 builder()->StoreGlobal(name_index, feedback_index(slot), language_mode()); | 1389 builder()->StoreGlobal(name_index, feedback_index(slot), language_mode()); |
1288 break; | 1390 break; |
1289 } | 1391 } |
1290 case VariableLocation::CONTEXT: { | 1392 case VariableLocation::CONTEXT: { |
1291 // TODO(rmcilroy): support const mode initialization. | 1393 // TODO(rmcilroy): support const mode initialization. |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1818 VisitLogicalAndExpression(binop); | 1920 VisitLogicalAndExpression(binop); |
1819 break; | 1921 break; |
1820 default: | 1922 default: |
1821 VisitArithmeticExpression(binop); | 1923 VisitArithmeticExpression(binop); |
1822 break; | 1924 break; |
1823 } | 1925 } |
1824 } | 1926 } |
1825 | 1927 |
1826 | 1928 |
1827 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1929 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
1828 // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression | 1930 // The evaluation of binary comparison expressions has an assignment |
1829 // once we have StatementScope that tracks hazardous loads/stores. | 1931 // hazard because the lhs may be a variable that evaluates to a |
1830 PrepareForBinaryExpression(); | 1932 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) |
1933 // To get a correct result the generator treats the inner assigment | |
1934 // as being made to a temporary x' that is spilled on exit of the | |
1935 // assignment hazard. | |
1936 AssignmentHazardScope assignment_hazard_scope(this); | |
1937 | |
1831 Register lhs = VisitForRegisterValue(expr->left()); | 1938 Register lhs = VisitForRegisterValue(expr->left()); |
1832 if (builder()->RegisterIsParameterOrLocal(lhs)) { | |
1833 // Result was returned in an existing local or parameter. See if | |
1834 // it needs to be moved to a temporary. | |
1835 // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). | |
1836 lhs = LoadFromAliasedRegister(lhs); | |
1837 } | |
1838 VisitForAccumulatorValue(expr->right()); | 1939 VisitForAccumulatorValue(expr->right()); |
1839 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); | 1940 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); |
1840 CompleteBinaryExpression(); | |
1841 execution_result()->SetResultInAccumulator(); | 1941 execution_result()->SetResultInAccumulator(); |
1842 } | 1942 } |
1843 | 1943 |
1844 | 1944 |
1845 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { | 1945 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
1846 // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression | 1946 // The evaluation of binary arithmetic expressions has an assignment |
1847 // once we have StatementScope that tracks hazardous loads/stores. | 1947 // hazard because the lhs may be a variable that evaluates to a |
1848 PrepareForBinaryExpression(); | 1948 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) |
1949 // To get a correct result the generator treats the inner assigment | |
1950 // as being made to a temporary x' that is spilled on exit of the | |
1951 // assignment hazard. | |
1952 AssignmentHazardScope assignment_hazard_scope(this); | |
1953 | |
1849 Register lhs = VisitForRegisterValue(expr->left()); | 1954 Register lhs = VisitForRegisterValue(expr->left()); |
1850 if (builder()->RegisterIsParameterOrLocal(lhs)) { | |
1851 // Result was returned in an existing local or parameter. See if | |
1852 // it needs to be moved to a temporary. | |
1853 // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). | |
1854 lhs = LoadFromAliasedRegister(lhs); | |
1855 } | |
1856 VisitForAccumulatorValue(expr->right()); | 1955 VisitForAccumulatorValue(expr->right()); |
1857 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); | 1956 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); |
1858 CompleteBinaryExpression(); | |
1859 execution_result()->SetResultInAccumulator(); | 1957 execution_result()->SetResultInAccumulator(); |
1860 } | 1958 } |
1861 | 1959 |
1862 | 1960 |
1863 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } | 1961 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } |
1864 | 1962 |
1865 | 1963 |
1866 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { | 1964 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
1867 UNREACHABLE(); | 1965 UNREACHABLE(); |
1868 } | 1966 } |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2069 // Pass a SMI sentinel and let the runtime look up the empty function. | 2167 // Pass a SMI sentinel and let the runtime look up the empty function. |
2070 builder()->LoadLiteral(Smi::FromInt(0)); | 2168 builder()->LoadLiteral(Smi::FromInt(0)); |
2071 } else { | 2169 } else { |
2072 DCHECK(closure_scope->is_function_scope()); | 2170 DCHECK(closure_scope->is_function_scope()); |
2073 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | 2171 builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
2074 } | 2172 } |
2075 execution_result()->SetResultInAccumulator(); | 2173 execution_result()->SetResultInAccumulator(); |
2076 } | 2174 } |
2077 | 2175 |
2078 | 2176 |
2079 void BytecodeGenerator::PrepareForBinaryExpression() { | |
2080 if (binary_expression_depth_++ == 0) { | |
2081 binary_expression_hazard_set_.clear(); | |
2082 } | |
2083 } | |
2084 | |
2085 | |
2086 // Visits the expression |expr| and places the result in the accumulator. | 2177 // Visits the expression |expr| and places the result in the accumulator. |
2087 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { | 2178 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { |
2088 AccumulatorResultScope accumulator_scope(this); | 2179 AccumulatorResultScope accumulator_scope(this); |
2089 Visit(expr); | 2180 Visit(expr); |
2090 } | 2181 } |
2091 | 2182 |
2092 | 2183 |
2093 // Visits the expression |expr| and discards the result. | 2184 // Visits the expression |expr| and discards the result. |
2094 void BytecodeGenerator::VisitForEffect(Expression* expr) { | 2185 void BytecodeGenerator::VisitForEffect(Expression* expr) { |
2095 EffectResultScope effect_scope(this); | 2186 EffectResultScope effect_scope(this); |
2096 Visit(expr); | 2187 Visit(expr); |
2097 } | 2188 } |
2098 | 2189 |
2099 | 2190 |
2100 // Visits the expression |expr| and returns the register containing | 2191 // Visits the expression |expr| and returns the register containing |
2101 // the expression result. | 2192 // the expression result. |
2102 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { | 2193 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { |
2103 RegisterResultScope register_scope(this); | 2194 RegisterResultScope register_scope(this); |
2104 Visit(expr); | 2195 Visit(expr); |
2105 return register_scope.ResultRegister(); | 2196 return register_scope.ResultRegister(); |
2106 } | 2197 } |
2107 | 2198 |
2108 | 2199 |
2109 Register BytecodeGenerator::LoadFromAliasedRegister(Register reg) { | |
2110 // TODO(oth): Follow on CL to load from re-map here. | |
2111 DCHECK(builder()->RegisterIsParameterOrLocal(reg)); | |
2112 if (binary_expression_depth_ > 0) { | |
2113 binary_expression_hazard_set_.insert(reg.index()); | |
2114 } | |
2115 return reg; | |
2116 } | |
2117 | |
2118 | |
2119 void BytecodeGenerator::RecordStoreToRegister(Register reg) { | |
2120 DCHECK(builder()->RegisterIsParameterOrLocal(reg)); | |
2121 if (binary_expression_depth_ > 0) { | |
2122 // TODO(oth): a store to a register that's be loaded needs to be | |
2123 // remapped. | |
2124 DCHECK(binary_expression_hazard_set_.find(reg.index()) == | |
2125 binary_expression_hazard_set_.end()); | |
2126 } | |
2127 } | |
2128 | |
2129 | |
2130 void BytecodeGenerator::CompleteBinaryExpression() { | |
2131 DCHECK(binary_expression_depth_ > 0); | |
2132 binary_expression_depth_ -= 1; | |
2133 // TODO(oth): spill remapped registers into origins. | |
2134 // TODO(oth): make statement/top-level. | |
2135 } | |
2136 | |
2137 | |
2138 Register BytecodeGenerator::NextContextRegister() const { | 2200 Register BytecodeGenerator::NextContextRegister() const { |
2139 if (execution_context() == nullptr) { | 2201 if (execution_context() == nullptr) { |
2140 // Return the incoming function context for the outermost execution context. | 2202 // Return the incoming function context for the outermost execution context. |
2141 return Register::function_context(); | 2203 return Register::function_context(); |
2142 } | 2204 } |
2143 Register previous = execution_context()->reg(); | 2205 Register previous = execution_context()->reg(); |
2144 if (previous == Register::function_context()) { | 2206 if (previous == Register::function_context()) { |
2145 // If the previous context was the incoming function context, then the next | 2207 // If the previous context was the incoming function context, then the next |
2146 // context register is the first local context register. | 2208 // context register is the first local context register. |
2147 return builder_.first_context_register(); | 2209 return builder_.first_context_register(); |
(...skipping 15 matching lines...) Expand all Loading... | |
2163 } | 2225 } |
2164 | 2226 |
2165 | 2227 |
2166 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2228 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
2167 return info()->feedback_vector()->GetIndex(slot); | 2229 return info()->feedback_vector()->GetIndex(slot); |
2168 } | 2230 } |
2169 | 2231 |
2170 } // namespace interpreter | 2232 } // namespace interpreter |
2171 } // namespace internal | 2233 } // namespace internal |
2172 } // namespace v8 | 2234 } // namespace v8 |
OLD | NEW |