| 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/compile-time-value.h" | 7 #include "src/ast/compile-time-value.h" |
| 8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
| 9 #include "src/builtins/builtins-constructor.h" | 9 #include "src/builtins/builtins-constructor.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 | 183 |
| 184 // Applies all recorded control-flow commands after the finally-block again. | 184 // Applies all recorded control-flow commands after the finally-block again. |
| 185 // This generates a dynamic dispatch on the token from the entry point. | 185 // This generates a dynamic dispatch on the token from the entry point. |
| 186 void ApplyDeferredCommands() { | 186 void ApplyDeferredCommands() { |
| 187 // The fall-through path is covered by the default case, hence +1 here. | 187 // The fall-through path is covered by the default case, hence +1 here. |
| 188 SwitchBuilder dispatch(builder(), static_cast<int>(deferred_.size() + 1)); | 188 SwitchBuilder dispatch(builder(), static_cast<int>(deferred_.size() + 1)); |
| 189 for (size_t i = 0; i < deferred_.size(); ++i) { | 189 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 190 Entry& entry = deferred_[i]; | 190 Entry& entry = deferred_[i]; |
| 191 builder()->LoadLiteral(Smi::FromInt(entry.token)); | 191 builder()->LoadLiteral(Smi::FromInt(entry.token)); |
| 192 builder()->CompareOperation(Token::EQ_STRICT, token_register_); | 192 builder()->CompareOperation(Token::EQ_STRICT, token_register_); |
| 193 dispatch.Case(static_cast<int>(i)); | 193 dispatch.Case(ToBooleanMode::kAlreadyBoolean, static_cast<int>(i)); |
| 194 } | 194 } |
| 195 dispatch.DefaultAt(static_cast<int>(deferred_.size())); | 195 dispatch.DefaultAt(static_cast<int>(deferred_.size())); |
| 196 for (size_t i = 0; i < deferred_.size(); ++i) { | 196 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 197 Entry& entry = deferred_[i]; | 197 Entry& entry = deferred_[i]; |
| 198 dispatch.SetCaseTarget(static_cast<int>(i)); | 198 dispatch.SetCaseTarget(static_cast<int>(i)); |
| 199 builder()->LoadAccumulatorWithRegister(result_register_); | 199 builder()->LoadAccumulatorWithRegister(result_register_); |
| 200 execution_control()->PerformCommand(entry.command, entry.statement); | 200 execution_control()->PerformCommand(entry.command, entry.statement); |
| 201 } | 201 } |
| 202 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); | 202 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); |
| 203 } | 203 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 | 404 |
| 405 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); | 405 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); |
| 406 }; | 406 }; |
| 407 | 407 |
| 408 // Scoped base class for determining how the result of an expression will be | 408 // Scoped base class for determining how the result of an expression will be |
| 409 // used. | 409 // used. |
| 410 class BytecodeGenerator::ExpressionResultScope { | 410 class BytecodeGenerator::ExpressionResultScope { |
| 411 public: | 411 public: |
| 412 ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) | 412 ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) |
| 413 : generator_(generator), | 413 : generator_(generator), |
| 414 outer_(generator->execution_result()), |
| 415 allocator_(generator), |
| 414 kind_(kind), | 416 kind_(kind), |
| 415 outer_(generator->execution_result()), | 417 type_hint_(TypeHint::kAny) { |
| 416 allocator_(generator) { | |
| 417 generator_->set_execution_result(this); | 418 generator_->set_execution_result(this); |
| 418 } | 419 } |
| 419 | 420 |
| 420 virtual ~ExpressionResultScope() { | 421 virtual ~ExpressionResultScope() { |
| 421 generator_->set_execution_result(outer_); | 422 generator_->set_execution_result(outer_); |
| 422 } | 423 } |
| 423 | 424 |
| 424 bool IsEffect() const { return kind_ == Expression::kEffect; } | 425 bool IsEffect() const { return kind_ == Expression::kEffect; } |
| 425 bool IsValue() const { return kind_ == Expression::kValue; } | 426 bool IsValue() const { return kind_ == Expression::kValue; } |
| 426 bool IsTest() const { return kind_ == Expression::kTest; } | 427 bool IsTest() const { return kind_ == Expression::kTest; } |
| 427 | 428 |
| 428 TestResultScope* AsTest() { | 429 TestResultScope* AsTest() { |
| 429 DCHECK(IsTest()); | 430 DCHECK(IsTest()); |
| 430 return reinterpret_cast<TestResultScope*>(this); | 431 return reinterpret_cast<TestResultScope*>(this); |
| 431 } | 432 } |
| 432 | 433 |
| 434 // Specify expression always returns a Boolean result value. |
| 435 void SetResultIsBoolean() { |
| 436 DCHECK(type_hint_ == TypeHint::kAny); |
| 437 type_hint_ = TypeHint::kBoolean; |
| 438 } |
| 439 |
| 440 TypeHint type_hint() const { return type_hint_; } |
| 441 |
| 433 private: | 442 private: |
| 434 BytecodeGenerator* generator_; | 443 BytecodeGenerator* generator_; |
| 435 Expression::Context kind_; | |
| 436 ExpressionResultScope* outer_; | 444 ExpressionResultScope* outer_; |
| 437 RegisterAllocationScope allocator_; | 445 RegisterAllocationScope allocator_; |
| 446 Expression::Context kind_; |
| 447 TypeHint type_hint_; |
| 438 | 448 |
| 439 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); | 449 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); |
| 440 }; | 450 }; |
| 441 | 451 |
| 442 // Scoped class used when the result of the current expression is not | 452 // Scoped class used when the result of the current expression is not |
| 443 // expected to produce a result. | 453 // expected to produce a result. |
| 444 class BytecodeGenerator::EffectResultScope final | 454 class BytecodeGenerator::EffectResultScope final |
| 445 : public ExpressionResultScope { | 455 : public ExpressionResultScope { |
| 446 public: | 456 public: |
| 447 explicit EffectResultScope(BytecodeGenerator* generator) | 457 explicit EffectResultScope(BytecodeGenerator* generator) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 466 then_labels_(then_labels), | 476 then_labels_(then_labels), |
| 467 else_labels_(else_labels), | 477 else_labels_(else_labels), |
| 468 fallthrough_(fallthrough), | 478 fallthrough_(fallthrough), |
| 469 result_consumed_by_test_(false) {} | 479 result_consumed_by_test_(false) {} |
| 470 | 480 |
| 471 // Used when code special cases for TestResultScope and consumes any | 481 // Used when code special cases for TestResultScope and consumes any |
| 472 // possible value by testing and jumping to a then/else label. | 482 // possible value by testing and jumping to a then/else label. |
| 473 void SetResultConsumedByTest() { | 483 void SetResultConsumedByTest() { |
| 474 result_consumed_by_test_ = true; | 484 result_consumed_by_test_ = true; |
| 475 } | 485 } |
| 476 | 486 bool result_consumed_by_test() { return result_consumed_by_test_; } |
| 477 bool ResultConsumedByTest() { return result_consumed_by_test_; } | |
| 478 | 487 |
| 479 BytecodeLabel* NewThenLabel() { return then_labels_->New(); } | 488 BytecodeLabel* NewThenLabel() { return then_labels_->New(); } |
| 480 BytecodeLabel* NewElseLabel() { return else_labels_->New(); } | 489 BytecodeLabel* NewElseLabel() { return else_labels_->New(); } |
| 481 | 490 |
| 482 BytecodeLabels* then_labels() const { return then_labels_; } | 491 BytecodeLabels* then_labels() const { return then_labels_; } |
| 483 BytecodeLabels* else_labels() const { return else_labels_; } | 492 BytecodeLabels* else_labels() const { return else_labels_; } |
| 484 | 493 |
| 485 TestFallthrough fallthrough() const { return fallthrough_; } | 494 TestFallthrough fallthrough() const { return fallthrough_; } |
| 486 TestFallthrough inverted_fallthrough() const { | 495 TestFallthrough inverted_fallthrough() const { |
| 487 switch (fallthrough_) { | 496 switch (fallthrough_) { |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 | 796 |
| 788 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, | 797 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
| 789 size_t size, | 798 size_t size, |
| 790 ZoneVector<BytecodeLabel>& targets) { | 799 ZoneVector<BytecodeLabel>& targets) { |
| 791 // TODO(neis): Optimize this by using a proper jump table. | 800 // TODO(neis): Optimize this by using a proper jump table. |
| 792 DCHECK_LE(start_index + size, targets.size()); | 801 DCHECK_LE(start_index + size, targets.size()); |
| 793 for (size_t i = start_index; i < start_index + size; i++) { | 802 for (size_t i = start_index; i < start_index + size; i++) { |
| 794 builder() | 803 builder() |
| 795 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) | 804 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) |
| 796 .CompareOperation(Token::Value::EQ_STRICT, index) | 805 .CompareOperation(Token::Value::EQ_STRICT, index) |
| 797 .JumpIfTrue(&(targets[i])); | 806 .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &(targets[i])); |
| 798 } | 807 } |
| 799 BuildAbort(BailoutReason::kInvalidJumpTableIndex); | 808 BuildAbort(BailoutReason::kInvalidJumpTableIndex); |
| 800 } | 809 } |
| 801 | 810 |
| 802 void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, | 811 void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, |
| 803 LoopBuilder* loop_builder) { | 812 LoopBuilder* loop_builder) { |
| 804 // Recall that stmt->yield_count() is always zero inside ordinary | 813 // Recall that stmt->yield_count() is always zero inside ordinary |
| 805 // (i.e. non-generator) functions. | 814 // (i.e. non-generator) functions. |
| 806 if (stmt->suspend_count() == 0) { | 815 if (stmt->suspend_count() == 0) { |
| 807 loop_builder->LoopHeader(); | 816 loop_builder->LoopHeader(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 821 } | 830 } |
| 822 | 831 |
| 823 loop_builder->LoopHeader(&resume_points_in_loop); | 832 loop_builder->LoopHeader(&resume_points_in_loop); |
| 824 | 833 |
| 825 // If we are not resuming, fall through to loop body. | 834 // If we are not resuming, fall through to loop body. |
| 826 // If we are resuming, perform state dispatch. | 835 // If we are resuming, perform state dispatch. |
| 827 BytecodeLabel not_resuming; | 836 BytecodeLabel not_resuming; |
| 828 builder() | 837 builder() |
| 829 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 838 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
| 830 .CompareOperation(Token::Value::EQ_STRICT, generator_state_) | 839 .CompareOperation(Token::Value::EQ_STRICT, generator_state_) |
| 831 .JumpIfTrue(¬_resuming); | 840 .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, ¬_resuming); |
| 832 BuildIndexedJump(generator_state_, first_yield, stmt->suspend_count(), | 841 BuildIndexedJump(generator_state_, first_yield, stmt->suspend_count(), |
| 833 generator_resume_points_); | 842 generator_resume_points_); |
| 834 builder()->Bind(¬_resuming); | 843 builder()->Bind(¬_resuming); |
| 835 } | 844 } |
| 836 } | 845 } |
| 837 | 846 |
| 838 void BytecodeGenerator::VisitGeneratorPrologue() { | 847 void BytecodeGenerator::VisitGeneratorPrologue() { |
| 839 // The generator resume trampoline abuses the new.target register both to | 848 // The generator resume trampoline abuses the new.target register both to |
| 840 // indicate that this is a resume call and to pass in the generator object. | 849 // indicate that this is a resume call and to pass in the generator object. |
| 841 // In ordinary calls, new.target is always undefined because generator | 850 // In ordinary calls, new.target is always undefined because generator |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1135 if (clause->is_default()) { | 1144 if (clause->is_default()) { |
| 1136 default_index = i; | 1145 default_index = i; |
| 1137 continue; | 1146 continue; |
| 1138 } | 1147 } |
| 1139 | 1148 |
| 1140 // Perform label comparison as if via '===' with tag. | 1149 // Perform label comparison as if via '===' with tag. |
| 1141 VisitForAccumulatorValue(clause->label()); | 1150 VisitForAccumulatorValue(clause->label()); |
| 1142 builder()->CompareOperation( | 1151 builder()->CompareOperation( |
| 1143 Token::Value::EQ_STRICT, tag, | 1152 Token::Value::EQ_STRICT, tag, |
| 1144 feedback_index(clause->CompareOperationFeedbackSlot())); | 1153 feedback_index(clause->CompareOperationFeedbackSlot())); |
| 1145 switch_builder.Case(i); | 1154 switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i); |
| 1146 } | 1155 } |
| 1147 | 1156 |
| 1148 if (default_index >= 0) { | 1157 if (default_index >= 0) { |
| 1149 // Emit default jump if there is a default case. | 1158 // Emit default jump if there is a default case. |
| 1150 switch_builder.DefaultAt(default_index); | 1159 switch_builder.DefaultAt(default_index); |
| 1151 } else { | 1160 } else { |
| 1152 // Otherwise if we have reached here none of the cases matched, so jump to | 1161 // Otherwise if we have reached here none of the cases matched, so jump to |
| 1153 // the end. | 1162 // the end. |
| 1154 switch_builder.Break(); | 1163 switch_builder.Break(); |
| 1155 } | 1164 } |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1337 | 1346 |
| 1338 // Set up loop counter | 1347 // Set up loop counter |
| 1339 Register index = register_allocator()->NewRegister(); | 1348 Register index = register_allocator()->NewRegister(); |
| 1340 builder()->LoadLiteral(Smi::kZero); | 1349 builder()->LoadLiteral(Smi::kZero); |
| 1341 builder()->StoreAccumulatorInRegister(index); | 1350 builder()->StoreAccumulatorInRegister(index); |
| 1342 | 1351 |
| 1343 // The loop | 1352 // The loop |
| 1344 VisitIterationHeader(stmt, &loop_builder); | 1353 VisitIterationHeader(stmt, &loop_builder); |
| 1345 builder()->SetExpressionAsStatementPosition(stmt->each()); | 1354 builder()->SetExpressionAsStatementPosition(stmt->each()); |
| 1346 builder()->ForInContinue(index, cache_length); | 1355 builder()->ForInContinue(index, cache_length); |
| 1347 loop_builder.BreakIfFalse(); | 1356 loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean); |
| 1348 FeedbackSlot slot = stmt->ForInFeedbackSlot(); | 1357 FeedbackSlot slot = stmt->ForInFeedbackSlot(); |
| 1349 builder()->ForInNext(receiver, index, triple.Truncate(2), | 1358 builder()->ForInNext(receiver, index, triple.Truncate(2), |
| 1350 feedback_index(slot)); | 1359 feedback_index(slot)); |
| 1351 loop_builder.ContinueIfUndefined(); | 1360 loop_builder.ContinueIfUndefined(); |
| 1352 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); | 1361 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); |
| 1353 VisitIterationBody(stmt, &loop_builder); | 1362 VisitIterationBody(stmt, &loop_builder); |
| 1354 builder()->ForInStep(index); | 1363 builder()->ForInStep(index); |
| 1355 builder()->StoreAccumulatorInRegister(index); | 1364 builder()->StoreAccumulatorInRegister(index); |
| 1356 loop_builder.JumpToHeader(loop_depth_); | 1365 loop_builder.JumpToHeader(loop_depth_); |
| 1357 loop_builder.EndLoop(); | 1366 loop_builder.EndLoop(); |
| 1358 builder()->Bind(&subject_null_label); | 1367 builder()->Bind(&subject_null_label); |
| 1359 builder()->Bind(&subject_undefined_label); | 1368 builder()->Bind(&subject_undefined_label); |
| 1360 } | 1369 } |
| 1361 | 1370 |
| 1362 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { | 1371 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { |
| 1363 LoopBuilder loop_builder(builder()); | 1372 LoopBuilder loop_builder(builder()); |
| 1364 | 1373 |
| 1365 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); | 1374 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); |
| 1366 VisitForEffect(stmt->assign_iterator()); | 1375 VisitForEffect(stmt->assign_iterator()); |
| 1367 | 1376 |
| 1368 VisitIterationHeader(stmt, &loop_builder); | 1377 VisitIterationHeader(stmt, &loop_builder); |
| 1369 builder()->SetExpressionAsStatementPosition(stmt->next_result()); | 1378 builder()->SetExpressionAsStatementPosition(stmt->next_result()); |
| 1370 VisitForEffect(stmt->next_result()); | 1379 VisitForEffect(stmt->next_result()); |
| 1371 VisitForAccumulatorValue(stmt->result_done()); | 1380 TypeHint type_hint = VisitForAccumulatorValue(stmt->result_done()); |
| 1372 loop_builder.BreakIfTrue(); | 1381 loop_builder.BreakIfTrue(ToBooleanModeFromTypeHint(type_hint)); |
| 1373 | 1382 |
| 1374 VisitForEffect(stmt->assign_each()); | 1383 VisitForEffect(stmt->assign_each()); |
| 1375 VisitIterationBody(stmt, &loop_builder); | 1384 VisitIterationBody(stmt, &loop_builder); |
| 1376 loop_builder.JumpToHeader(loop_depth_); | 1385 loop_builder.JumpToHeader(loop_depth_); |
| 1377 loop_builder.EndLoop(); | 1386 loop_builder.EndLoop(); |
| 1378 } | 1387 } |
| 1379 | 1388 |
| 1380 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1389 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 1381 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1390 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); |
| 1382 | 1391 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1555 | 1564 |
| 1556 if (property->is_static() && property->is_computed_name()) { | 1565 if (property->is_static() && property->is_computed_name()) { |
| 1557 // The static prototype property is read only. We handle the non computed | 1566 // The static prototype property is read only. We handle the non computed |
| 1558 // property name case in the parser. Since this is the only case where we | 1567 // property name case in the parser. Since this is the only case where we |
| 1559 // need to check for an own read only property we special case this so we | 1568 // need to check for an own read only property we special case this so we |
| 1560 // do not need to do this for every property. | 1569 // do not need to do this for every property. |
| 1561 BytecodeLabel done; | 1570 BytecodeLabel done; |
| 1562 builder() | 1571 builder() |
| 1563 ->LoadLiteral(ast_string_constants()->prototype_string()) | 1572 ->LoadLiteral(ast_string_constants()->prototype_string()) |
| 1564 .CompareOperation(Token::Value::EQ_STRICT, key) | 1573 .CompareOperation(Token::Value::EQ_STRICT, key) |
| 1565 .JumpIfFalse(&done) | 1574 .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done) |
| 1566 .CallRuntime(Runtime::kThrowStaticPrototypeError) | 1575 .CallRuntime(Runtime::kThrowStaticPrototypeError) |
| 1567 .Bind(&done); | 1576 .Bind(&done); |
| 1568 } | 1577 } |
| 1569 | 1578 |
| 1570 VisitForRegisterValue(property->value(), value); | 1579 VisitForRegisterValue(property->value(), value); |
| 1571 VisitSetHomeObject(value, receiver, property); | 1580 VisitSetHomeObject(value, receiver, property); |
| 1572 | 1581 |
| 1573 if (!attr_assigned) { | 1582 if (!attr_assigned) { |
| 1574 builder() | 1583 builder() |
| 1575 ->LoadLiteral(Smi::FromInt(DONT_ENUM)) | 1584 ->LoadLiteral(Smi::FromInt(DONT_ENUM)) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 else_labels.Bind(builder()); | 1664 else_labels.Bind(builder()); |
| 1656 VisitForAccumulatorValue(expr->else_expression()); | 1665 VisitForAccumulatorValue(expr->else_expression()); |
| 1657 builder()->Bind(&end_label); | 1666 builder()->Bind(&end_label); |
| 1658 } | 1667 } |
| 1659 } | 1668 } |
| 1660 | 1669 |
| 1661 void BytecodeGenerator::VisitLiteral(Literal* expr) { | 1670 void BytecodeGenerator::VisitLiteral(Literal* expr) { |
| 1662 if (!execution_result()->IsEffect()) { | 1671 if (!execution_result()->IsEffect()) { |
| 1663 const AstValue* raw_value = expr->raw_value(); | 1672 const AstValue* raw_value = expr->raw_value(); |
| 1664 builder()->LoadLiteral(raw_value); | 1673 builder()->LoadLiteral(raw_value); |
| 1674 if (raw_value->IsTrue() || raw_value->IsFalse()) { |
| 1675 execution_result()->SetResultIsBoolean(); |
| 1676 } |
| 1665 } | 1677 } |
| 1666 } | 1678 } |
| 1667 | 1679 |
| 1668 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1680 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1669 // Materialize a regular expression literal. | 1681 // Materialize a regular expression literal. |
| 1670 builder()->CreateRegExpLiteral( | 1682 builder()->CreateRegExpLiteral( |
| 1671 expr->raw_pattern(), feedback_index(expr->literal_slot()), expr->flags()); | 1683 expr->raw_pattern(), feedback_index(expr->literal_slot()), expr->flags()); |
| 1672 } | 1684 } |
| 1673 | 1685 |
| 1674 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 1686 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| (...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2443 | 2455 |
| 2444 // Now dispatch on resume mode. | 2456 // Now dispatch on resume mode. |
| 2445 | 2457 |
| 2446 BytecodeLabel resume_with_next; | 2458 BytecodeLabel resume_with_next; |
| 2447 BytecodeLabel resume_with_return; | 2459 BytecodeLabel resume_with_return; |
| 2448 BytecodeLabel resume_with_throw; | 2460 BytecodeLabel resume_with_throw; |
| 2449 | 2461 |
| 2450 builder() | 2462 builder() |
| 2451 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) | 2463 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) |
| 2452 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2464 .CompareOperation(Token::EQ_STRICT, resume_mode) |
| 2453 .JumpIfTrue(&resume_with_next) | 2465 .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_next) |
| 2454 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) | 2466 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) |
| 2455 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2467 .CompareOperation(Token::EQ_STRICT, resume_mode) |
| 2456 .JumpIfTrue(&resume_with_throw) | 2468 .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_throw) |
| 2457 .Jump(&resume_with_return); | 2469 .Jump(&resume_with_return); |
| 2458 | 2470 |
| 2459 builder()->Bind(&resume_with_return); | 2471 builder()->Bind(&resume_with_return); |
| 2460 { | 2472 { |
| 2461 if (expr->is_async_generator()) { | 2473 if (expr->is_async_generator()) { |
| 2462 // Async generator methods will produce the iter result object. | 2474 // Async generator methods will produce the iter result object. |
| 2463 builder()->LoadAccumulatorWithRegister(input); | 2475 builder()->LoadAccumulatorWithRegister(input); |
| 2464 execution_control()->AsyncReturnAccumulator(); | 2476 execution_control()->AsyncReturnAccumulator(); |
| 2465 } else { | 2477 } else { |
| 2466 RegisterList args = register_allocator()->NewRegisterList(2); | 2478 RegisterList args = register_allocator()->NewRegisterList(2); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2807 VisitForEffect(expr->expression()); | 2819 VisitForEffect(expr->expression()); |
| 2808 } else if (execution_result()->IsTest()) { | 2820 } else if (execution_result()->IsTest()) { |
| 2809 TestResultScope* test_result = execution_result()->AsTest(); | 2821 TestResultScope* test_result = execution_result()->AsTest(); |
| 2810 // No actual logical negation happening, we just swap the control flow by | 2822 // No actual logical negation happening, we just swap the control flow by |
| 2811 // swapping the target labels and the fallthrough branch. | 2823 // swapping the target labels and the fallthrough branch. |
| 2812 VisitForTest(expr->expression(), test_result->else_labels(), | 2824 VisitForTest(expr->expression(), test_result->else_labels(), |
| 2813 test_result->then_labels(), | 2825 test_result->then_labels(), |
| 2814 test_result->inverted_fallthrough()); | 2826 test_result->inverted_fallthrough()); |
| 2815 test_result->SetResultConsumedByTest(); | 2827 test_result->SetResultConsumedByTest(); |
| 2816 } else { | 2828 } else { |
| 2817 VisitForAccumulatorValue(expr->expression()); | 2829 TypeHint type_hint = VisitForAccumulatorValue(expr->expression()); |
| 2818 builder()->LogicalNot(); | 2830 builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint)); |
| 2819 } | 2831 } |
| 2832 // Always returns a boolean value. |
| 2833 execution_result()->SetResultIsBoolean(); |
| 2820 } | 2834 } |
| 2821 | 2835 |
| 2822 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 2836 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 2823 switch (expr->op()) { | 2837 switch (expr->op()) { |
| 2824 case Token::Value::NOT: | 2838 case Token::Value::NOT: |
| 2825 VisitNot(expr); | 2839 VisitNot(expr); |
| 2826 break; | 2840 break; |
| 2827 case Token::Value::TYPEOF: | 2841 case Token::Value::TYPEOF: |
| 2828 VisitTypeOf(expr); | 2842 VisitTypeOf(expr); |
| 2829 break; | 2843 break; |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3088 Register lhs = VisitForRegisterValue(expr->left()); | 3102 Register lhs = VisitForRegisterValue(expr->left()); |
| 3089 VisitForAccumulatorValue(expr->right()); | 3103 VisitForAccumulatorValue(expr->right()); |
| 3090 builder()->SetExpressionPosition(expr); | 3104 builder()->SetExpressionPosition(expr); |
| 3091 FeedbackSlot slot = expr->CompareOperationFeedbackSlot(); | 3105 FeedbackSlot slot = expr->CompareOperationFeedbackSlot(); |
| 3092 if (slot.IsInvalid()) { | 3106 if (slot.IsInvalid()) { |
| 3093 builder()->CompareOperation(expr->op(), lhs); | 3107 builder()->CompareOperation(expr->op(), lhs); |
| 3094 } else { | 3108 } else { |
| 3095 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); | 3109 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); |
| 3096 } | 3110 } |
| 3097 } | 3111 } |
| 3112 // Always returns a boolean value. |
| 3113 execution_result()->SetResultIsBoolean(); |
| 3098 } | 3114 } |
| 3099 | 3115 |
| 3100 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { | 3116 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
| 3101 // TODO(rmcilroy): Special case "x * 1.0" and "x * -1" which are generated for | 3117 // TODO(rmcilroy): Special case "x * 1.0" and "x * -1" which are generated for |
| 3102 // +x and -x by the parser. | 3118 // +x and -x by the parser. |
| 3103 Register lhs = VisitForRegisterValue(expr->left()); | 3119 Register lhs = VisitForRegisterValue(expr->left()); |
| 3104 VisitForAccumulatorValue(expr->right()); | 3120 VisitForAccumulatorValue(expr->right()); |
| 3105 FeedbackSlot slot = expr->BinaryOperationFeedbackSlot(); | 3121 FeedbackSlot slot = expr->BinaryOperationFeedbackSlot(); |
| 3106 builder()->SetExpressionPosition(expr); | 3122 builder()->SetExpressionPosition(expr); |
| 3107 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); | 3123 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3222 test_result->else_labels(), test_result->fallthrough()); | 3238 test_result->else_labels(), test_result->fallthrough()); |
| 3223 } | 3239 } |
| 3224 test_result->SetResultConsumedByTest(); | 3240 test_result->SetResultConsumedByTest(); |
| 3225 } else { | 3241 } else { |
| 3226 if (left->ToBooleanIsTrue()) { | 3242 if (left->ToBooleanIsTrue()) { |
| 3227 VisitForAccumulatorValue(left); | 3243 VisitForAccumulatorValue(left); |
| 3228 } else if (left->ToBooleanIsFalse()) { | 3244 } else if (left->ToBooleanIsFalse()) { |
| 3229 VisitForAccumulatorValue(right); | 3245 VisitForAccumulatorValue(right); |
| 3230 } else { | 3246 } else { |
| 3231 BytecodeLabel end_label; | 3247 BytecodeLabel end_label; |
| 3232 VisitForAccumulatorValue(left); | 3248 TypeHint type_hint = VisitForAccumulatorValue(left); |
| 3233 builder()->JumpIfTrue(&end_label); | 3249 builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), &end_label); |
| 3234 VisitForAccumulatorValue(right); | 3250 VisitForAccumulatorValue(right); |
| 3235 builder()->Bind(&end_label); | 3251 builder()->Bind(&end_label); |
| 3236 } | 3252 } |
| 3237 } | 3253 } |
| 3238 } | 3254 } |
| 3239 | 3255 |
| 3240 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { | 3256 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { |
| 3241 Expression* left = binop->left(); | 3257 Expression* left = binop->left(); |
| 3242 Expression* right = binop->right(); | 3258 Expression* right = binop->right(); |
| 3243 | 3259 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3257 test_result->else_labels(), test_result->fallthrough()); | 3273 test_result->else_labels(), test_result->fallthrough()); |
| 3258 } | 3274 } |
| 3259 test_result->SetResultConsumedByTest(); | 3275 test_result->SetResultConsumedByTest(); |
| 3260 } else { | 3276 } else { |
| 3261 if (left->ToBooleanIsFalse()) { | 3277 if (left->ToBooleanIsFalse()) { |
| 3262 VisitForAccumulatorValue(left); | 3278 VisitForAccumulatorValue(left); |
| 3263 } else if (left->ToBooleanIsTrue()) { | 3279 } else if (left->ToBooleanIsTrue()) { |
| 3264 VisitForAccumulatorValue(right); | 3280 VisitForAccumulatorValue(right); |
| 3265 } else { | 3281 } else { |
| 3266 BytecodeLabel end_label; | 3282 BytecodeLabel end_label; |
| 3267 VisitForAccumulatorValue(left); | 3283 TypeHint type_hint = VisitForAccumulatorValue(left); |
| 3268 builder()->JumpIfFalse(&end_label); | 3284 builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), &end_label); |
| 3269 VisitForAccumulatorValue(right); | 3285 VisitForAccumulatorValue(right); |
| 3270 builder()->Bind(&end_label); | 3286 builder()->Bind(&end_label); |
| 3271 } | 3287 } |
| 3272 } | 3288 } |
| 3273 } | 3289 } |
| 3274 | 3290 |
| 3275 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { | 3291 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { |
| 3276 Visit(expr->expression()); | 3292 Visit(expr->expression()); |
| 3277 } | 3293 } |
| 3278 | 3294 |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3478 Context::CLOSURE_INDEX, 0, | 3494 Context::CLOSURE_INDEX, 0, |
| 3479 BytecodeArrayBuilder::kImmutableSlot); | 3495 BytecodeArrayBuilder::kImmutableSlot); |
| 3480 } else { | 3496 } else { |
| 3481 DCHECK(closure_scope()->is_function_scope() || | 3497 DCHECK(closure_scope()->is_function_scope() || |
| 3482 closure_scope()->is_module_scope()); | 3498 closure_scope()->is_module_scope()); |
| 3483 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | 3499 builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
| 3484 } | 3500 } |
| 3485 } | 3501 } |
| 3486 | 3502 |
| 3487 // Visits the expression |expr| and places the result in the accumulator. | 3503 // Visits the expression |expr| and places the result in the accumulator. |
| 3488 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { | 3504 BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue( |
| 3505 Expression* expr) { |
| 3489 ValueResultScope accumulator_scope(this); | 3506 ValueResultScope accumulator_scope(this); |
| 3490 Visit(expr); | 3507 Visit(expr); |
| 3508 return accumulator_scope.type_hint(); |
| 3491 } | 3509 } |
| 3492 | 3510 |
| 3493 void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { | 3511 void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { |
| 3494 if (expr == nullptr) { | 3512 if (expr == nullptr) { |
| 3495 builder()->LoadTheHole(); | 3513 builder()->LoadTheHole(); |
| 3496 } else { | 3514 } else { |
| 3497 VisitForAccumulatorValue(expr); | 3515 VisitForAccumulatorValue(expr); |
| 3498 } | 3516 } |
| 3499 } | 3517 } |
| 3500 | 3518 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3544 builder()->LoadUndefined().StoreAccumulatorInRegister(reg); | 3562 builder()->LoadUndefined().StoreAccumulatorInRegister(reg); |
| 3545 } | 3563 } |
| 3546 | 3564 |
| 3547 // Visits the expression |expr| for testing its boolean value and jumping to the | 3565 // Visits the expression |expr| for testing its boolean value and jumping to the |
| 3548 // |then| or |other| label depending on value and short-circuit semantics | 3566 // |then| or |other| label depending on value and short-circuit semantics |
| 3549 void BytecodeGenerator::VisitForTest(Expression* expr, | 3567 void BytecodeGenerator::VisitForTest(Expression* expr, |
| 3550 BytecodeLabels* then_labels, | 3568 BytecodeLabels* then_labels, |
| 3551 BytecodeLabels* else_labels, | 3569 BytecodeLabels* else_labels, |
| 3552 TestFallthrough fallthrough) { | 3570 TestFallthrough fallthrough) { |
| 3553 bool result_consumed; | 3571 bool result_consumed; |
| 3572 TypeHint type_hint; |
| 3554 { | 3573 { |
| 3555 // To make sure that all temporary registers are returned before generating | 3574 // To make sure that all temporary registers are returned before generating |
| 3556 // jumps below, we ensure that the result scope is deleted before doing so. | 3575 // jumps below, we ensure that the result scope is deleted before doing so. |
| 3557 // Dead registers might be materialized otherwise. | 3576 // Dead registers might be materialized otherwise. |
| 3558 TestResultScope test_result(this, then_labels, else_labels, fallthrough); | 3577 TestResultScope test_result(this, then_labels, else_labels, fallthrough); |
| 3559 Visit(expr); | 3578 Visit(expr); |
| 3560 result_consumed = test_result.ResultConsumedByTest(); | 3579 result_consumed = test_result.result_consumed_by_test(); |
| 3580 type_hint = test_result.type_hint(); |
| 3561 } | 3581 } |
| 3562 if (!result_consumed) { | 3582 if (!result_consumed) { |
| 3583 ToBooleanMode mode(ToBooleanModeFromTypeHint(type_hint)); |
| 3563 switch (fallthrough) { | 3584 switch (fallthrough) { |
| 3564 case TestFallthrough::kThen: | 3585 case TestFallthrough::kThen: |
| 3565 builder()->JumpIfFalse(else_labels->New()); | 3586 builder()->JumpIfFalse(mode, else_labels->New()); |
| 3566 break; | 3587 break; |
| 3567 case TestFallthrough::kElse: | 3588 case TestFallthrough::kElse: |
| 3568 builder()->JumpIfTrue(then_labels->New()); | 3589 builder()->JumpIfTrue(mode, then_labels->New()); |
| 3569 break; | 3590 break; |
| 3570 case TestFallthrough::kNone: | 3591 case TestFallthrough::kNone: |
| 3571 builder()->JumpIfTrue(then_labels->New()); | 3592 builder()->JumpIfTrue(mode, then_labels->New()); |
| 3572 builder()->Jump(else_labels->New()); | 3593 builder()->Jump(else_labels->New()); |
| 3573 } | 3594 } |
| 3574 } | 3595 } |
| 3575 } | 3596 } |
| 3576 | 3597 |
| 3577 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { | 3598 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { |
| 3578 DCHECK(scope->declarations()->is_empty()); | 3599 DCHECK(scope->declarations()->is_empty()); |
| 3579 CurrentScope current_scope(this, scope); | 3600 CurrentScope current_scope(this, scope); |
| 3580 ContextScope context_scope(this, scope); | 3601 ContextScope context_scope(this, scope); |
| 3581 Visit(stmt); | 3602 Visit(stmt); |
| 3582 } | 3603 } |
| 3583 | 3604 |
| 3605 BytecodeArrayBuilder::ToBooleanMode |
| 3606 BytecodeGenerator::ToBooleanModeFromTypeHint(TypeHint type_hint) { |
| 3607 return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean |
| 3608 : ToBooleanMode::kConvertToBoolean; |
| 3609 } |
| 3610 |
| 3584 LanguageMode BytecodeGenerator::language_mode() const { | 3611 LanguageMode BytecodeGenerator::language_mode() const { |
| 3585 return current_scope()->language_mode(); | 3612 return current_scope()->language_mode(); |
| 3586 } | 3613 } |
| 3587 | 3614 |
| 3588 int BytecodeGenerator::feedback_index(FeedbackSlot slot) const { | 3615 int BytecodeGenerator::feedback_index(FeedbackSlot slot) const { |
| 3589 return FeedbackVector::GetIndex(slot); | 3616 return FeedbackVector::GetIndex(slot); |
| 3590 } | 3617 } |
| 3591 | 3618 |
| 3592 Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() { | 3619 Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() { |
| 3593 return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict | 3620 return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict |
| 3594 : Runtime::kStoreToSuper_Sloppy; | 3621 : Runtime::kStoreToSuper_Sloppy; |
| 3595 } | 3622 } |
| 3596 | 3623 |
| 3597 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3624 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
| 3598 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3625 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
| 3599 : Runtime::kStoreKeyedToSuper_Sloppy; | 3626 : Runtime::kStoreKeyedToSuper_Sloppy; |
| 3600 } | 3627 } |
| 3601 | 3628 |
| 3602 } // namespace interpreter | 3629 } // namespace interpreter |
| 3603 } // namespace internal | 3630 } // namespace internal |
| 3604 } // namespace v8 | 3631 } // namespace v8 |
| OLD | NEW |