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/bytecode-register-allocator.h" | 9 #include "src/interpreter/bytecode-register-allocator.h" |
| 10 #include "src/interpreter/control-flow-builders.h" | 10 #include "src/interpreter/control-flow-builders.h" |
| (...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 decl->fun(), info()->script(), info()); | 711 decl->fun(), info()->script(), info()); |
| 712 // Check for stack-overflow exception. | 712 // Check for stack-overflow exception. |
| 713 if (function.is_null()) return SetStackOverflow(); | 713 if (function.is_null()) return SetStackOverflow(); |
| 714 globals()->push_back(variable->name()); | 714 globals()->push_back(variable->name()); |
| 715 globals()->push_back(function); | 715 globals()->push_back(function); |
| 716 break; | 716 break; |
| 717 } | 717 } |
| 718 case VariableLocation::PARAMETER: | 718 case VariableLocation::PARAMETER: |
| 719 case VariableLocation::LOCAL: { | 719 case VariableLocation::LOCAL: { |
| 720 VisitForAccumulatorValue(decl->fun()); | 720 VisitForAccumulatorValue(decl->fun()); |
| 721 VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); | 721 DCHECK(variable->mode() == LET || variable->mode() == VAR); |
| 722 VisitVariableAssignment(variable, Token::INIT, | |
| 723 FeedbackVectorSlot::Invalid()); | |
| 722 break; | 724 break; |
| 723 } | 725 } |
| 724 case VariableLocation::CONTEXT: { | 726 case VariableLocation::CONTEXT: { |
| 725 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); | 727 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); |
| 726 VisitForAccumulatorValue(decl->fun()); | 728 VisitForAccumulatorValue(decl->fun()); |
| 727 builder()->StoreContextSlot(execution_context()->reg(), | 729 builder()->StoreContextSlot(execution_context()->reg(), |
| 728 variable->index()); | 730 variable->index()); |
| 729 break; | 731 break; |
| 730 } | 732 } |
| 731 case VariableLocation::LOOKUP: { | 733 case VariableLocation::LOOKUP: { |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 FeedbackVectorSlot slot) { | 995 FeedbackVectorSlot slot) { |
| 994 DCHECK(expr->IsValidReferenceExpression()); | 996 DCHECK(expr->IsValidReferenceExpression()); |
| 995 | 997 |
| 996 // Evaluate assignment starting with the value to be stored in the | 998 // Evaluate assignment starting with the value to be stored in the |
| 997 // accumulator. | 999 // accumulator. |
| 998 Property* property = expr->AsProperty(); | 1000 Property* property = expr->AsProperty(); |
| 999 LhsKind assign_type = Property::GetAssignType(property); | 1001 LhsKind assign_type = Property::GetAssignType(property); |
| 1000 switch (assign_type) { | 1002 switch (assign_type) { |
| 1001 case VARIABLE: { | 1003 case VARIABLE: { |
| 1002 Variable* variable = expr->AsVariableProxy()->var(); | 1004 Variable* variable = expr->AsVariableProxy()->var(); |
| 1003 VisitVariableAssignment(variable, slot); | 1005 VisitVariableAssignment(variable, Token::ASSIGN, slot); |
| 1004 break; | 1006 break; |
| 1005 } | 1007 } |
| 1006 case NAMED_PROPERTY: { | 1008 case NAMED_PROPERTY: { |
| 1007 RegisterAllocationScope register_scope(this); | 1009 RegisterAllocationScope register_scope(this); |
| 1008 Register value = register_allocator()->NewRegister(); | 1010 Register value = register_allocator()->NewRegister(); |
| 1009 builder()->StoreAccumulatorInRegister(value); | 1011 builder()->StoreAccumulatorInRegister(value); |
| 1010 Register object = VisitForRegisterValue(property->obj()); | 1012 Register object = VisitForRegisterValue(property->obj()); |
| 1011 Handle<String> name = property->key()->AsLiteral()->AsPropertyName(); | 1013 Handle<String> name = property->key()->AsLiteral()->AsPropertyName(); |
| 1012 builder()->LoadAccumulatorWithRegister(value); | 1014 builder()->LoadAccumulatorWithRegister(value); |
| 1013 builder()->StoreNamedProperty(object, name, feedback_index(slot), | 1015 builder()->StoreNamedProperty(object, name, feedback_index(slot), |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1497 builder()->LoadAccumulatorWithRegister(literal); | 1499 builder()->LoadAccumulatorWithRegister(literal); |
| 1498 } | 1500 } |
| 1499 execution_result()->SetResultInAccumulator(); | 1501 execution_result()->SetResultInAccumulator(); |
| 1500 } | 1502 } |
| 1501 | 1503 |
| 1502 | 1504 |
| 1503 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { | 1505 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { |
| 1504 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 1506 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 1505 } | 1507 } |
| 1506 | 1508 |
| 1509 void BytecodeGenerator::BuildHoleCheckForVariableLoad(VariableMode mode, | |
| 1510 Handle<String> name) { | |
| 1511 if (mode == CONST_LEGACY) { | |
| 1512 BytecodeLabel end_label; | |
| 1513 builder()->JumpIfNotHole(&end_label).LoadUndefined().Bind(&end_label); | |
|
rmcilroy
2016/01/26 14:37:28
Newlines between builder operations (throughout).
mythria
2016/02/01 10:02:18
I added newlines. cl format removes them. Shall I
rmcilroy
2016/02/03 12:28:25
I think we should override this if possible, it is
| |
| 1514 } else if (mode == LET || mode == CONST) { | |
| 1515 BuildThrowIfHole(name); | |
| 1516 } | |
| 1517 } | |
| 1507 | 1518 |
| 1508 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1519 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 1509 FeedbackVectorSlot slot, | 1520 FeedbackVectorSlot slot, |
| 1510 TypeofMode typeof_mode) { | 1521 TypeofMode typeof_mode) { |
| 1522 VariableMode mode = variable->mode(); | |
| 1511 switch (variable->location()) { | 1523 switch (variable->location()) { |
| 1512 case VariableLocation::LOCAL: { | 1524 case VariableLocation::LOCAL: { |
| 1513 Register source(Register(variable->index())); | 1525 Register source(Register(variable->index())); |
| 1514 builder()->LoadAccumulatorWithRegister(source); | 1526 builder()->LoadAccumulatorWithRegister(source); |
| 1527 BuildHoleCheckForVariableLoad(mode, variable->name()); | |
| 1515 execution_result()->SetResultInAccumulator(); | 1528 execution_result()->SetResultInAccumulator(); |
| 1516 break; | 1529 break; |
| 1517 } | 1530 } |
| 1518 case VariableLocation::PARAMETER: { | 1531 case VariableLocation::PARAMETER: { |
| 1519 // The parameter indices are shifted by 1 (receiver is variable | 1532 // The parameter indices are shifted by 1 (receiver is variable |
| 1520 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1533 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1521 Register source = builder()->Parameter(variable->index() + 1); | 1534 Register source = builder()->Parameter(variable->index() + 1); |
| 1522 builder()->LoadAccumulatorWithRegister(source); | 1535 builder()->LoadAccumulatorWithRegister(source); |
| 1536 BuildHoleCheckForVariableLoad(mode, variable->name()); | |
| 1523 execution_result()->SetResultInAccumulator(); | 1537 execution_result()->SetResultInAccumulator(); |
| 1524 break; | 1538 break; |
| 1525 } | 1539 } |
| 1526 case VariableLocation::GLOBAL: | 1540 case VariableLocation::GLOBAL: |
| 1527 case VariableLocation::UNALLOCATED: { | 1541 case VariableLocation::UNALLOCATED: { |
| 1528 builder()->LoadGlobal(variable->name(), feedback_index(slot), | 1542 builder()->LoadGlobal(variable->name(), feedback_index(slot), |
| 1529 language_mode(), typeof_mode); | 1543 language_mode(), typeof_mode); |
| 1530 execution_result()->SetResultInAccumulator(); | 1544 execution_result()->SetResultInAccumulator(); |
| 1531 break; | 1545 break; |
| 1532 } | 1546 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1545 // when this changes. | 1559 // when this changes. |
| 1546 builder() | 1560 builder() |
| 1547 ->LoadAccumulatorWithRegister(execution_context()->reg()) | 1561 ->LoadAccumulatorWithRegister(execution_context()->reg()) |
| 1548 .StoreAccumulatorInRegister(context_reg); | 1562 .StoreAccumulatorInRegister(context_reg); |
| 1549 for (int i = 0; i < depth; ++i) { | 1563 for (int i = 0; i < depth; ++i) { |
| 1550 builder() | 1564 builder() |
| 1551 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) | 1565 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) |
| 1552 .StoreAccumulatorInRegister(context_reg); | 1566 .StoreAccumulatorInRegister(context_reg); |
| 1553 } | 1567 } |
| 1554 } | 1568 } |
| 1569 | |
| 1555 builder()->LoadContextSlot(context_reg, variable->index()); | 1570 builder()->LoadContextSlot(context_reg, variable->index()); |
| 1571 BuildHoleCheckForVariableLoad(mode, variable->name()); | |
| 1556 execution_result()->SetResultInAccumulator(); | 1572 execution_result()->SetResultInAccumulator(); |
| 1557 // TODO(rmcilroy): Perform check for uninitialized legacy const, const and | |
| 1558 // let variables. | |
| 1559 break; | 1573 break; |
| 1560 } | 1574 } |
| 1561 case VariableLocation::LOOKUP: { | 1575 case VariableLocation::LOOKUP: { |
| 1562 builder()->LoadLookupSlot(variable->name(), typeof_mode); | 1576 builder()->LoadLookupSlot(variable->name(), typeof_mode); |
| 1563 execution_result()->SetResultInAccumulator(); | 1577 execution_result()->SetResultInAccumulator(); |
| 1564 break; | 1578 break; |
| 1565 } | 1579 } |
| 1566 } | 1580 } |
| 1567 } | 1581 } |
| 1568 | 1582 |
| 1569 | 1583 |
| 1570 void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( | 1584 void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( |
| 1571 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { | 1585 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { |
| 1572 AccumulatorResultScope accumulator_result(this); | 1586 AccumulatorResultScope accumulator_result(this); |
| 1573 VisitVariableLoad(variable, slot, typeof_mode); | 1587 VisitVariableLoad(variable, slot, typeof_mode); |
| 1574 } | 1588 } |
| 1575 | 1589 |
| 1576 | 1590 |
| 1577 Register BytecodeGenerator::VisitVariableLoadForRegisterValue( | 1591 Register BytecodeGenerator::VisitVariableLoadForRegisterValue( |
| 1578 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { | 1592 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { |
| 1579 RegisterResultScope register_scope(this); | 1593 RegisterResultScope register_scope(this); |
| 1580 VisitVariableLoad(variable, slot, typeof_mode); | 1594 VisitVariableLoad(variable, slot, typeof_mode); |
| 1581 return register_scope.ResultRegister(); | 1595 return register_scope.ResultRegister(); |
| 1582 } | 1596 } |
| 1583 | 1597 |
| 1598 void BytecodeGenerator::BuildThrowIfHole(Handle<String> name) { | |
| 1599 Register name_reg = register_allocator()->NewRegister(); | |
| 1600 BytecodeLabel end_label; | |
| 1601 builder() | |
| 1602 ->JumpIfNotHole(&end_label) | |
| 1603 .LoadLiteral(name) | |
| 1604 .StoreAccumulatorInRegister(name_reg) | |
| 1605 .CallRuntime(Runtime::kThrowReferenceError, name_reg, 1) | |
| 1606 .Bind(&end_label); | |
| 1607 } | |
| 1608 | |
| 1609 void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) { | |
| 1610 Register name_reg = register_allocator()->NewRegister(); | |
| 1611 BytecodeLabel end_label; | |
| 1612 builder() | |
| 1613 ->JumpIfHole(&end_label) | |
| 1614 .LoadLiteral(name) | |
| 1615 .StoreAccumulatorInRegister(name_reg) | |
| 1616 .CallRuntime(Runtime::kThrowReferenceError, name_reg, 1) | |
| 1617 .Bind(&end_label); | |
| 1618 } | |
| 1619 | |
| 1620 void BytecodeGenerator::BuildThrowReassignConstant(Register destination, | |
| 1621 Handle<String> name) { | |
| 1622 Register name_reg = register_allocator()->NewRegister(); | |
| 1623 BytecodeLabel else_label; | |
| 1624 builder() | |
| 1625 ->LoadLiteral(name) | |
| 1626 .StoreAccumulatorInRegister(name_reg) | |
| 1627 .LoadAccumulatorWithRegister(destination) | |
| 1628 .JumpIfNotHole(&else_label) | |
| 1629 .CallRuntime(Runtime::kThrowReferenceError, name_reg, 1) | |
| 1630 .Bind(&else_label) | |
| 1631 .CallRuntime(Runtime::kThrowConstAssignError, name_reg, 1); | |
| 1632 } | |
| 1633 | |
| 1634 void BytecodeGenerator::BuildThrowReassignConstant(Handle<String> name) { | |
|
rmcilroy
2016/01/26 14:37:28
Could we merge both BuildThrowReassignConstant (an
mythria
2016/02/01 10:02:18
Done.
| |
| 1635 Register name_reg = register_allocator()->NewRegister(); | |
| 1636 BytecodeLabel else_label; | |
| 1637 builder() | |
| 1638 ->JumpIfNotHole(&else_label) | |
| 1639 .LoadLiteral(name) | |
|
rmcilroy
2016/01/26 14:37:28
Move LoadLiteral / StoreAccumulatorInRegister(name
mythria
2016/02/01 10:02:18
For throwing const reassign error, we don't need t
| |
| 1640 .StoreAccumulatorInRegister(name_reg) | |
| 1641 .CallRuntime(Runtime::kThrowReferenceError, name_reg, 1) | |
| 1642 .Bind(&else_label) | |
| 1643 .LoadLiteral(name) | |
| 1644 .StoreAccumulatorInRegister(name_reg) | |
| 1645 .CallRuntime(Runtime::kThrowConstAssignError, name_reg, 1); | |
| 1646 } | |
| 1584 | 1647 |
| 1585 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 1648 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| 1649 Token::Value op, | |
| 1586 FeedbackVectorSlot slot) { | 1650 FeedbackVectorSlot slot) { |
| 1651 VariableMode mode = variable->mode(); | |
| 1652 RegisterAllocationScope assignment_register_scope(this); | |
| 1653 BytecodeLabel end_label; | |
| 1654 bool hole_check_required = | |
| 1655 (mode == CONST_LEGACY) || (mode == LET && op != Token::INIT) || | |
| 1656 (mode == CONST && op != Token::INIT) || | |
| 1657 (mode == CONST && op == Token::INIT && variable->is_this()); | |
| 1587 switch (variable->location()) { | 1658 switch (variable->location()) { |
| 1659 case VariableLocation::PARAMETER: | |
| 1588 case VariableLocation::LOCAL: { | 1660 case VariableLocation::LOCAL: { |
| 1589 // TODO(rmcilroy): support const mode initialization. | 1661 Register destination; |
| 1590 Register destination(variable->index()); | 1662 if (VariableLocation::PARAMETER == variable->location()) { |
| 1591 builder()->StoreAccumulatorInRegister(destination); | 1663 destination = Register(builder()->Parameter(variable->index() + 1)); |
| 1592 break; | 1664 } else { |
| 1593 } | 1665 destination = Register(variable->index()); |
| 1594 case VariableLocation::PARAMETER: { | 1666 } |
| 1595 // The parameter indices are shifted by 1 (receiver is variable | 1667 |
| 1596 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1668 if (!hole_check_required) { |
| 1597 Register destination(builder()->Parameter(variable->index() + 1)); | 1669 builder()->StoreAccumulatorInRegister(destination); |
| 1598 builder()->StoreAccumulatorInRegister(destination); | 1670 } else if (mode == CONST && op != Token::INIT) { |
|
rmcilroy
2016/01/26 14:37:28
As discussed, could you merge the code to do the h
mythria
2016/02/01 10:02:18
Done. I did not pull const_legacy && Token::Init t
| |
| 1671 // Assigning to constant is not allowed. Throw an appropriate | |
| 1672 // exception. Accumulator is not restored back. | |
| 1673 BuildThrowReassignConstant(destination, variable->name()); | |
| 1674 } else if (mode == CONST_LEGACY && op != Token::INIT) { | |
| 1675 // TODO(mythria): Find a test case for strict mode legacy constants. | |
|
rmcilroy
2016/01/26 14:37:28
Legacy const doesn't exist for strict mode, right?
mythria
2016/02/01 10:02:18
Done. Yes, it was a old comment. Retained the DCHE
| |
| 1676 DCHECK(!is_strict(language_mode())); | |
| 1677 } else { | |
| 1678 // Store accumulator to a temporary register and load destination to | |
| 1679 // perform hole check. | |
| 1680 BytecodeLabel end_label; | |
| 1681 Register value_temp = register_allocator()->NewRegister(); | |
| 1682 builder() | |
| 1683 ->StoreAccumulatorInRegister(value_temp) | |
| 1684 .LoadAccumulatorWithRegister(destination); | |
| 1685 if (mode == CONST_LEGACY && op == Token::INIT) { | |
| 1686 // If the destination is already initialized silently ignore this | |
| 1687 // assignment. Restore the accumulator. | |
| 1688 builder() | |
| 1689 ->JumpIfNotHole(&end_label) | |
| 1690 .MoveRegister(value_temp, destination) | |
| 1691 .Bind(&end_label) | |
| 1692 .LoadAccumulatorWithRegister(value_temp); | |
| 1693 } else if (mode == LET && op != Token::INIT) { | |
| 1694 BuildThrowIfHole(variable->name()); | |
| 1695 // Move does not help here, because accumulator should be restored to | |
| 1696 // value_temp as well. | |
| 1697 builder() | |
| 1698 ->LoadAccumulatorWithRegister(value_temp) | |
| 1699 .StoreAccumulatorInRegister(destination); | |
| 1700 } else { | |
| 1701 DCHECK(variable->is_this() && mode == CONST && op == Token::INIT); | |
| 1702 // Perform an initialization check for 'this'. 'this' variable is the | |
| 1703 // only variable being able to trigger bind operations outside the TDZ | |
| 1704 // via 'super' calls. | |
| 1705 BuildThrowIfNotHole(variable->name()); | |
| 1706 builder() | |
| 1707 ->LoadAccumulatorWithRegister(value_temp) | |
| 1708 .StoreAccumulatorInRegister(destination); | |
| 1709 } | |
| 1710 } | |
| 1599 break; | 1711 break; |
| 1600 } | 1712 } |
| 1601 case VariableLocation::GLOBAL: | 1713 case VariableLocation::GLOBAL: |
| 1602 case VariableLocation::UNALLOCATED: { | 1714 case VariableLocation::UNALLOCATED: { |
| 1603 builder()->StoreGlobal(variable->name(), feedback_index(slot), | 1715 builder()->StoreGlobal(variable->name(), feedback_index(slot), |
| 1604 language_mode()); | 1716 language_mode()); |
| 1605 break; | 1717 break; |
| 1606 } | 1718 } |
| 1607 case VariableLocation::CONTEXT: { | 1719 case VariableLocation::CONTEXT: { |
| 1608 // TODO(rmcilroy): support const mode initialization. | |
| 1609 int depth = execution_context()->ContextChainDepth(variable->scope()); | 1720 int depth = execution_context()->ContextChainDepth(variable->scope()); |
| 1610 ContextScope* context = execution_context()->Previous(depth); | 1721 ContextScope* context = execution_context()->Previous(depth); |
| 1611 Register context_reg; | 1722 Register context_reg; |
| 1723 Register value_temp; | |
| 1724 bool value_in_accumulator = true; | |
|
rmcilroy
2016/01/26 14:37:28
Let's not try to be smart with "value_in_accumulat
mythria
2016/02/01 10:02:18
Done.
| |
| 1725 | |
| 1612 if (context) { | 1726 if (context) { |
| 1613 context_reg = context->reg(); | 1727 context_reg = context->reg(); |
| 1614 } else { | 1728 } else { |
| 1615 Register value_temp = register_allocator()->NewRegister(); | 1729 value_temp = register_allocator()->NewRegister(); |
| 1616 context_reg = register_allocator()->NewRegister(); | 1730 context_reg = register_allocator()->NewRegister(); |
| 1617 // Walk the context chain to find the context at the given depth. | 1731 // Walk the context chain to find the context at the given depth. |
| 1618 // TODO(rmcilroy): Perform this work in a bytecode handler once we have | 1732 // TODO(rmcilroy): Perform this work in a bytecode handler once we have |
| 1619 // a generic mechanism for performing jumps in interpreter.cc. | 1733 // a generic mechanism for performing jumps in interpreter.cc. |
| 1620 // TODO(mythria): Also update bytecode graph builder with correct depth | 1734 // TODO(mythria): Also update bytecode graph builder with correct depth |
| 1621 // when this changes. | 1735 // when this changes. |
| 1622 builder() | 1736 builder() |
| 1623 ->StoreAccumulatorInRegister(value_temp) | 1737 ->StoreAccumulatorInRegister(value_temp) |
| 1624 .LoadAccumulatorWithRegister(execution_context()->reg()) | 1738 .LoadAccumulatorWithRegister(execution_context()->reg()) |
| 1625 .StoreAccumulatorInRegister(context_reg); | 1739 .StoreAccumulatorInRegister(context_reg); |
| 1626 for (int i = 0; i < depth; ++i) { | 1740 for (int i = 0; i < depth; ++i) { |
| 1627 builder() | 1741 builder() |
| 1628 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) | 1742 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) |
| 1629 .StoreAccumulatorInRegister(context_reg); | 1743 .StoreAccumulatorInRegister(context_reg); |
| 1630 } | 1744 } |
| 1631 builder()->LoadAccumulatorWithRegister(value_temp); | 1745 value_in_accumulator = false; |
| 1632 } | 1746 } |
| 1633 builder()->StoreContextSlot(context_reg, variable->index()); | 1747 |
| 1748 if (!hole_check_required) { | |
| 1749 if (!value_in_accumulator) { | |
| 1750 builder()->LoadAccumulatorWithRegister(value_temp); | |
| 1751 } | |
| 1752 builder()->StoreContextSlot(context_reg, variable->index()); | |
| 1753 } else if (mode == CONST && op != Token::INIT) { | |
| 1754 // Assigning to constant is not allowed. Throw an appropriate | |
| 1755 // exception. Accumulator is not restored back. | |
| 1756 builder()->LoadContextSlot(context_reg, variable->index()); | |
| 1757 BuildThrowReassignConstant(variable->name()); | |
| 1758 } else if (mode == CONST_LEGACY && op != Token::INIT) { | |
| 1759 // TODO(mythria): Find a test case for strict mode legacy constants. | |
|
rmcilroy
2016/01/26 14:37:28
ditto.
mythria
2016/02/01 10:02:18
Done.
| |
| 1760 DCHECK(!is_strict(language_mode())); | |
| 1761 // Accumulator has to be restored back. | |
| 1762 if (!value_in_accumulator) { | |
| 1763 builder()->LoadAccumulatorWithRegister(value_temp); | |
| 1764 } | |
| 1765 } else { | |
| 1766 // Store accumulator to a temporary register and load destination to | |
| 1767 // perform hole check. | |
| 1768 if (value_in_accumulator) { | |
| 1769 value_temp = register_allocator()->NewRegister(); | |
| 1770 builder()->StoreAccumulatorInRegister(value_temp); | |
| 1771 } | |
| 1772 builder()->LoadContextSlot(context_reg, variable->index()); | |
| 1773 BytecodeLabel end_label; | |
| 1774 if (mode == CONST_LEGACY && op == Token::INIT) { | |
| 1775 // If the destination is already initialized silently ignore this | |
| 1776 // assignment and restore back the accumulator. | |
|
rmcilroy
2016/01/26 14:37:28
Not sure what "restore back the accumulator" means
mythria
2016/02/01 10:02:18
Done.
| |
| 1777 builder() | |
| 1778 ->JumpIfNotHole(&end_label) | |
| 1779 .LoadAccumulatorWithRegister(value_temp) | |
| 1780 .StoreContextSlot(context_reg, variable->index()) | |
| 1781 .Bind(&end_label) | |
| 1782 .LoadAccumulatorWithRegister(value_temp); | |
| 1783 } else if (mode == LET && op != Token::INIT) { | |
| 1784 BuildThrowIfHole(variable->name()); | |
| 1785 builder() | |
| 1786 ->LoadAccumulatorWithRegister(value_temp) | |
| 1787 .StoreContextSlot(context_reg, variable->index()); | |
| 1788 } else { | |
| 1789 DCHECK(variable->is_this() && mode == CONST && op == Token::INIT); | |
| 1790 // Perform an initialization check for 'this'. 'this' variable is the | |
| 1791 // only variable being able to trigger bind operations outside the TDZ | |
|
rmcilroy
2016/01/26 14:37:28
/s/variable being able/variable able
mythria
2016/02/01 10:02:18
Done.
| |
| 1792 // via 'super' calls. | |
| 1793 BuildThrowIfNotHole(variable->name()); | |
| 1794 builder() | |
| 1795 ->LoadAccumulatorWithRegister(value_temp) | |
| 1796 .StoreContextSlot(context_reg, variable->index()); | |
| 1797 } | |
| 1798 } | |
| 1634 break; | 1799 break; |
| 1635 } | 1800 } |
| 1636 case VariableLocation::LOOKUP: { | 1801 case VariableLocation::LOOKUP: { |
| 1637 // TODO(mythria): Use Runtime::kInitializeLegacyConstLookupSlot for | 1802 if (mode == CONST_LEGACY && op == Token::INIT) { |
| 1638 // initializations of const declarations. | 1803 register_allocator()->PrepareForConsecutiveAllocations(3); |
| 1639 builder()->StoreLookupSlot(variable->name(), language_mode()); | 1804 Register value = register_allocator()->NextConsecutiveRegister(); |
| 1805 Register context = register_allocator()->NextConsecutiveRegister(); | |
| 1806 Register name = register_allocator()->NextConsecutiveRegister(); | |
| 1807 | |
| 1808 // InitializeLegacyConstLookupSlot runtime call returns the 'value' | |
| 1809 // passed to it. So, accumulator will have its original contents when | |
| 1810 // runtime call returns. | |
| 1811 builder() | |
| 1812 ->StoreAccumulatorInRegister(value) | |
| 1813 .MoveRegister(execution_context()->reg(), context) | |
| 1814 .LoadLiteral(variable->name()) | |
| 1815 .StoreAccumulatorInRegister(name) | |
| 1816 .CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, value, 3); | |
| 1817 } else if (mode == CONST_LEGACY && op != Token::INIT) { | |
| 1818 // TODO(mythria): Find a test case for strict mode. We should throw in | |
| 1819 // strict mode. | |
| 1820 DCHECK(!is_strict(language_mode())); | |
| 1821 } else { | |
| 1822 builder()->StoreLookupSlot(variable->name(), language_mode()); | |
| 1823 } | |
| 1640 break; | 1824 break; |
| 1641 } | 1825 } |
| 1642 } | 1826 } |
| 1643 } | 1827 } |
| 1644 | 1828 |
| 1645 | 1829 |
| 1646 void BytecodeGenerator::VisitAssignment(Assignment* expr) { | 1830 void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
| 1647 DCHECK(expr->target()->IsValidReferenceExpression()); | 1831 DCHECK(expr->target()->IsValidReferenceExpression()); |
| 1648 Register object, key; | 1832 Register object, key; |
| 1649 Handle<String> name; | 1833 Handle<String> name; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1722 VisitForAccumulatorValue(expr->value()); | 1906 VisitForAccumulatorValue(expr->value()); |
| 1723 } | 1907 } |
| 1724 | 1908 |
| 1725 // Store the value. | 1909 // Store the value. |
| 1726 FeedbackVectorSlot slot = expr->AssignmentSlot(); | 1910 FeedbackVectorSlot slot = expr->AssignmentSlot(); |
| 1727 switch (assign_type) { | 1911 switch (assign_type) { |
| 1728 case VARIABLE: { | 1912 case VARIABLE: { |
| 1729 // TODO(oth): The VisitVariableAssignment() call is hard to reason about. | 1913 // TODO(oth): The VisitVariableAssignment() call is hard to reason about. |
| 1730 // Is the value in the accumulator safe? Yes, but scary. | 1914 // Is the value in the accumulator safe? Yes, but scary. |
| 1731 Variable* variable = expr->target()->AsVariableProxy()->var(); | 1915 Variable* variable = expr->target()->AsVariableProxy()->var(); |
| 1732 VisitVariableAssignment(variable, slot); | 1916 VisitVariableAssignment(variable, expr->op(), slot); |
| 1733 break; | 1917 break; |
| 1734 } | 1918 } |
| 1735 case NAMED_PROPERTY: | 1919 case NAMED_PROPERTY: |
| 1736 builder()->StoreNamedProperty(object, name, feedback_index(slot), | 1920 builder()->StoreNamedProperty(object, name, feedback_index(slot), |
| 1737 language_mode()); | 1921 language_mode()); |
| 1738 break; | 1922 break; |
| 1739 case KEYED_PROPERTY: | 1923 case KEYED_PROPERTY: |
| 1740 builder()->StoreKeyedProperty(object, key, feedback_index(slot), | 1924 builder()->StoreKeyedProperty(object, key, feedback_index(slot), |
| 1741 language_mode()); | 1925 language_mode()); |
| 1742 break; | 1926 break; |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2148 } | 2332 } |
| 2149 | 2333 |
| 2150 // Perform +1/-1 operation. | 2334 // Perform +1/-1 operation. |
| 2151 builder()->CountOperation(expr->binary_op(), language_mode_strength()); | 2335 builder()->CountOperation(expr->binary_op(), language_mode_strength()); |
| 2152 | 2336 |
| 2153 // Store the value. | 2337 // Store the value. |
| 2154 FeedbackVectorSlot feedback_slot = expr->CountSlot(); | 2338 FeedbackVectorSlot feedback_slot = expr->CountSlot(); |
| 2155 switch (assign_type) { | 2339 switch (assign_type) { |
| 2156 case VARIABLE: { | 2340 case VARIABLE: { |
| 2157 Variable* variable = expr->expression()->AsVariableProxy()->var(); | 2341 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| 2158 VisitVariableAssignment(variable, feedback_slot); | 2342 VisitVariableAssignment(variable, expr->op(), feedback_slot); |
| 2159 break; | 2343 break; |
| 2160 } | 2344 } |
| 2161 case NAMED_PROPERTY: { | 2345 case NAMED_PROPERTY: { |
| 2162 builder()->StoreNamedProperty(obj, name, feedback_index(feedback_slot), | 2346 builder()->StoreNamedProperty(obj, name, feedback_index(feedback_slot), |
| 2163 language_mode()); | 2347 language_mode()); |
| 2164 break; | 2348 break; |
| 2165 } | 2349 } |
| 2166 case KEYED_PROPERTY: { | 2350 case KEYED_PROPERTY: { |
| 2167 builder()->StoreKeyedProperty(obj, key, feedback_index(feedback_slot), | 2351 builder()->StoreKeyedProperty(obj, key, feedback_index(feedback_slot), |
| 2168 language_mode()); | 2352 language_mode()); |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2412 | 2596 |
| 2413 DCHECK(variable->IsContextSlot() || variable->IsStackAllocated()); | 2597 DCHECK(variable->IsContextSlot() || variable->IsStackAllocated()); |
| 2414 | 2598 |
| 2415 // Allocate and initialize a new arguments object and assign to the | 2599 // Allocate and initialize a new arguments object and assign to the |
| 2416 // {arguments} variable. | 2600 // {arguments} variable. |
| 2417 CreateArgumentsType type = | 2601 CreateArgumentsType type = |
| 2418 is_strict(language_mode()) || !info()->has_simple_parameters() | 2602 is_strict(language_mode()) || !info()->has_simple_parameters() |
| 2419 ? CreateArgumentsType::kUnmappedArguments | 2603 ? CreateArgumentsType::kUnmappedArguments |
| 2420 : CreateArgumentsType::kMappedArguments; | 2604 : CreateArgumentsType::kMappedArguments; |
| 2421 builder()->CreateArguments(type); | 2605 builder()->CreateArguments(type); |
| 2422 VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); | 2606 VisitVariableAssignment(variable, Token::ASSIGN, |
| 2607 FeedbackVectorSlot::Invalid()); | |
| 2423 } | 2608 } |
| 2424 | 2609 |
| 2425 | 2610 |
| 2426 void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { | 2611 void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { |
| 2427 if (variable == nullptr) return; | 2612 if (variable == nullptr) return; |
| 2428 | 2613 |
| 2429 // TODO(rmcilroy): Remove once we have tests which exercise this code path. | 2614 // TODO(rmcilroy): Remove once we have tests which exercise this code path. |
| 2430 UNIMPLEMENTED(); | 2615 UNIMPLEMENTED(); |
| 2431 | 2616 |
| 2432 // Store the closure we were called with in the given variable. | 2617 // Store the closure we were called with in the given variable. |
| 2433 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | 2618 builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
| 2434 VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); | 2619 VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); |
| 2435 } | 2620 } |
| 2436 | 2621 |
| 2437 | 2622 |
| 2438 void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { | 2623 void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { |
| 2439 if (variable == nullptr) return; | 2624 if (variable == nullptr) return; |
| 2440 | 2625 |
| 2441 // Store the new target we were called with in the given variable. | 2626 // Store the new target we were called with in the given variable. |
| 2442 builder()->LoadAccumulatorWithRegister(Register::new_target()); | 2627 builder()->LoadAccumulatorWithRegister(Register::new_target()); |
| 2443 VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); | 2628 VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); |
| 2444 } | 2629 } |
| 2445 | 2630 |
| 2446 | 2631 |
| 2447 void BytecodeGenerator::VisitFunctionClosureForContext() { | 2632 void BytecodeGenerator::VisitFunctionClosureForContext() { |
| 2448 AccumulatorResultScope accumulator_execution_result(this); | 2633 AccumulatorResultScope accumulator_execution_result(this); |
| 2449 Scope* closure_scope = execution_context()->scope()->ClosureScope(); | 2634 Scope* closure_scope = execution_context()->scope()->ClosureScope(); |
| 2450 if (closure_scope->is_script_scope() || | 2635 if (closure_scope->is_script_scope() || |
| 2451 closure_scope->is_module_scope()) { | 2636 closure_scope->is_module_scope()) { |
| 2452 // Contexts nested in the native context have a canonical empty function as | 2637 // Contexts nested in the native context have a canonical empty function as |
| 2453 // their closure, not the anonymous closure containing the global code. | 2638 // their closure, not the anonymous closure containing the global code. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2505 } | 2690 } |
| 2506 | 2691 |
| 2507 | 2692 |
| 2508 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2693 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 2509 return info()->feedback_vector()->GetIndex(slot); | 2694 return info()->feedback_vector()->GetIndex(slot); |
| 2510 } | 2695 } |
| 2511 | 2696 |
| 2512 } // namespace interpreter | 2697 } // namespace interpreter |
| 2513 } // namespace internal | 2698 } // namespace internal |
| 2514 } // namespace v8 | 2699 } // namespace v8 |
| OLD | NEW |