OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
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-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | 710 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
711 __ Check(not_equal, kDeclarationInCatchContext); | 711 __ Check(not_equal, kDeclarationInCatchContext); |
712 } | 712 } |
713 } | 713 } |
714 | 714 |
715 | 715 |
716 void FullCodeGenerator::VisitVariableDeclaration( | 716 void FullCodeGenerator::VisitVariableDeclaration( |
717 VariableDeclaration* declaration) { | 717 VariableDeclaration* declaration) { |
718 VariableProxy* proxy = declaration->proxy(); | 718 VariableProxy* proxy = declaration->proxy(); |
719 Variable* variable = proxy->var(); | 719 Variable* variable = proxy->var(); |
| 720 DCHECK(!variable->binding_needs_init()); |
720 switch (variable->location()) { | 721 switch (variable->location()) { |
721 case VariableLocation::UNALLOCATED: { | 722 case VariableLocation::UNALLOCATED: { |
722 DCHECK(!variable->binding_needs_init()); | |
723 globals_->Add(variable->name(), zone()); | 723 globals_->Add(variable->name(), zone()); |
724 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); | 724 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); |
725 DCHECK(!slot.IsInvalid()); | 725 DCHECK(!slot.IsInvalid()); |
726 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); | 726 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); |
727 globals_->Add(isolate()->factory()->undefined_value(), zone()); | 727 globals_->Add(isolate()->factory()->undefined_value(), zone()); |
728 break; | 728 break; |
729 } | 729 } |
730 case VariableLocation::PARAMETER: | 730 case VariableLocation::PARAMETER: |
731 case VariableLocation::LOCAL: | 731 case VariableLocation::LOCAL: |
732 if (variable->binding_needs_init()) { | |
733 Comment cmnt(masm_, "[ VariableDeclaration"); | |
734 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | |
735 __ movp(StackOperand(variable), kScratchRegister); | |
736 } | |
737 break; | |
738 | |
739 case VariableLocation::CONTEXT: | 732 case VariableLocation::CONTEXT: |
740 if (variable->binding_needs_init()) { | |
741 Comment cmnt(masm_, "[ VariableDeclaration"); | |
742 EmitDebugCheckDeclarationContext(variable); | |
743 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | |
744 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister); | |
745 // No write barrier since the hole value is in old space. | |
746 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
747 } | |
748 break; | 733 break; |
749 | 734 |
750 case VariableLocation::LOOKUP: | 735 case VariableLocation::LOOKUP: |
751 case VariableLocation::MODULE: | 736 case VariableLocation::MODULE: |
752 UNREACHABLE(); | 737 UNREACHABLE(); |
753 } | 738 } |
754 } | 739 } |
755 | 740 |
756 | 741 |
757 void FullCodeGenerator::VisitFunctionDeclaration( | 742 void FullCodeGenerator::VisitFunctionDeclaration( |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 Operand(rsp, offset * kPointerSize)); | 1082 Operand(rsp, offset * kPointerSize)); |
1098 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1083 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); |
1099 } | 1084 } |
1100 | 1085 |
1101 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1086 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
1102 TypeofMode typeof_mode) { | 1087 TypeofMode typeof_mode) { |
1103 // Record position before possible IC call. | 1088 // Record position before possible IC call. |
1104 SetExpressionPosition(proxy); | 1089 SetExpressionPosition(proxy); |
1105 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); | 1090 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); |
1106 Variable* var = proxy->var(); | 1091 Variable* var = proxy->var(); |
| 1092 DCHECK(!var->binding_needs_init()); |
1107 | 1093 |
1108 // Two cases: global variable, and all other types of variables. | 1094 // Two cases: global variable, and all other types of variables. |
1109 switch (var->location()) { | 1095 switch (var->location()) { |
1110 case VariableLocation::UNALLOCATED: { | 1096 case VariableLocation::UNALLOCATED: { |
1111 Comment cmnt(masm_, "[ Global variable"); | 1097 Comment cmnt(masm_, "[ Global variable"); |
1112 EmitGlobalVariableLoad(proxy, typeof_mode); | 1098 EmitGlobalVariableLoad(proxy, typeof_mode); |
1113 context()->Plug(rax); | 1099 context()->Plug(rax); |
1114 break; | 1100 break; |
1115 } | 1101 } |
1116 | 1102 |
1117 case VariableLocation::PARAMETER: | 1103 case VariableLocation::PARAMETER: |
1118 case VariableLocation::LOCAL: | 1104 case VariableLocation::LOCAL: |
1119 case VariableLocation::CONTEXT: { | 1105 case VariableLocation::CONTEXT: { |
1120 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); | 1106 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); |
1121 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" | 1107 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" |
1122 : "[ Stack slot"); | 1108 : "[ Stack slot"); |
1123 if (proxy->hole_check_mode() == HoleCheckMode::kRequired) { | |
1124 // Throw a reference error when using an uninitialized let/const | |
1125 // binding in harmony mode. | |
1126 DCHECK(IsLexicalVariableMode(var->mode())); | |
1127 Label done; | |
1128 GetVar(rax, var); | |
1129 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | |
1130 __ j(not_equal, &done, Label::kNear); | |
1131 __ Push(var->name()); | |
1132 __ CallRuntime(Runtime::kThrowReferenceError); | |
1133 __ bind(&done); | |
1134 context()->Plug(rax); | |
1135 break; | |
1136 } | |
1137 context()->Plug(var); | 1109 context()->Plug(var); |
1138 break; | 1110 break; |
1139 } | 1111 } |
1140 | 1112 |
1141 case VariableLocation::LOOKUP: | 1113 case VariableLocation::LOOKUP: |
1142 case VariableLocation::MODULE: | 1114 case VariableLocation::MODULE: |
1143 UNREACHABLE(); | 1115 UNREACHABLE(); |
1144 } | 1116 } |
1145 } | 1117 } |
1146 | 1118 |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1438 } else { | 1410 } else { |
1439 VisitForAccumulatorValue(expr->value()); | 1411 VisitForAccumulatorValue(expr->value()); |
1440 } | 1412 } |
1441 | 1413 |
1442 SetExpressionPosition(expr); | 1414 SetExpressionPosition(expr); |
1443 | 1415 |
1444 // Store the value. | 1416 // Store the value. |
1445 switch (assign_type) { | 1417 switch (assign_type) { |
1446 case VARIABLE: { | 1418 case VARIABLE: { |
1447 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 1419 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
1448 EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(), | 1420 EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot()); |
1449 proxy->hole_check_mode()); | |
1450 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 1421 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
1451 context()->Plug(rax); | 1422 context()->Plug(rax); |
1452 break; | 1423 break; |
1453 } | 1424 } |
1454 case NAMED_PROPERTY: | 1425 case NAMED_PROPERTY: |
1455 EmitNamedPropertyAssignment(expr); | 1426 EmitNamedPropertyAssignment(expr); |
1456 break; | 1427 break; |
1457 case KEYED_PROPERTY: | 1428 case KEYED_PROPERTY: |
1458 EmitKeyedPropertyAssignment(expr); | 1429 EmitKeyedPropertyAssignment(expr); |
1459 break; | 1430 break; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1585 FeedbackVectorSlot slot) { | 1556 FeedbackVectorSlot slot) { |
1586 DCHECK(expr->IsValidReferenceExpressionOrThis()); | 1557 DCHECK(expr->IsValidReferenceExpressionOrThis()); |
1587 | 1558 |
1588 Property* prop = expr->AsProperty(); | 1559 Property* prop = expr->AsProperty(); |
1589 LhsKind assign_type = Property::GetAssignType(prop); | 1560 LhsKind assign_type = Property::GetAssignType(prop); |
1590 | 1561 |
1591 switch (assign_type) { | 1562 switch (assign_type) { |
1592 case VARIABLE: { | 1563 case VARIABLE: { |
1593 VariableProxy* proxy = expr->AsVariableProxy(); | 1564 VariableProxy* proxy = expr->AsVariableProxy(); |
1594 EffectContext context(this); | 1565 EffectContext context(this); |
1595 EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot, | 1566 EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot); |
1596 proxy->hole_check_mode()); | |
1597 break; | 1567 break; |
1598 } | 1568 } |
1599 case NAMED_PROPERTY: { | 1569 case NAMED_PROPERTY: { |
1600 PushOperand(rax); // Preserve value. | 1570 PushOperand(rax); // Preserve value. |
1601 VisitForAccumulatorValue(prop->obj()); | 1571 VisitForAccumulatorValue(prop->obj()); |
1602 __ Move(StoreDescriptor::ReceiverRegister(), rax); | 1572 __ Move(StoreDescriptor::ReceiverRegister(), rax); |
1603 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. | 1573 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. |
1604 CallStoreIC(slot, prop->key()->AsLiteral()->value()); | 1574 CallStoreIC(slot, prop->key()->AsLiteral()->value()); |
1605 break; | 1575 break; |
1606 } | 1576 } |
(...skipping 20 matching lines...) Expand all Loading... |
1627 Variable* var, MemOperand location) { | 1597 Variable* var, MemOperand location) { |
1628 __ movp(location, rax); | 1598 __ movp(location, rax); |
1629 if (var->IsContextSlot()) { | 1599 if (var->IsContextSlot()) { |
1630 __ movp(rdx, rax); | 1600 __ movp(rdx, rax); |
1631 __ RecordWriteContextSlot( | 1601 __ RecordWriteContextSlot( |
1632 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | 1602 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1633 } | 1603 } |
1634 } | 1604 } |
1635 | 1605 |
1636 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, | 1606 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, |
1637 FeedbackVectorSlot slot, | 1607 FeedbackVectorSlot slot) { |
1638 HoleCheckMode hole_check_mode) { | 1608 DCHECK(!var->binding_needs_init()); |
1639 if (var->IsUnallocated()) { | 1609 if (var->IsUnallocated()) { |
1640 // Global var, const, or let. | 1610 // Global var, const, or let. |
1641 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); | 1611 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); |
1642 CallStoreIC(slot, var->name()); | 1612 CallStoreIC(slot, var->name()); |
1643 | 1613 |
1644 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { | 1614 } else if (var->mode() == CONST && op != Token::INIT) { |
1645 DCHECK(!var->IsLookupSlot()); | 1615 if (var->throw_on_const_assignment(language_mode())) { |
1646 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | |
1647 MemOperand location = VarOperand(var, rcx); | |
1648 // Perform an initialization check for lexically declared variables. | |
1649 if (hole_check_mode == HoleCheckMode::kRequired) { | |
1650 Label assign; | |
1651 __ movp(rdx, location); | |
1652 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
1653 __ j(not_equal, &assign, Label::kNear); | |
1654 __ Push(var->name()); | |
1655 __ CallRuntime(Runtime::kThrowReferenceError); | |
1656 __ bind(&assign); | |
1657 } | |
1658 if (var->mode() != CONST) { | |
1659 EmitStoreToStackLocalOrContextSlot(var, location); | |
1660 } else if (var->throw_on_const_assignment(language_mode())) { | |
1661 __ CallRuntime(Runtime::kThrowConstAssignError); | 1616 __ CallRuntime(Runtime::kThrowConstAssignError); |
1662 } | 1617 } |
1663 | |
1664 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { | |
1665 // Initializing assignment to const {this} needs a write barrier. | |
1666 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | |
1667 Label uninitialized_this; | |
1668 MemOperand location = VarOperand(var, rcx); | |
1669 __ movp(rdx, location); | |
1670 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
1671 __ j(equal, &uninitialized_this); | |
1672 __ Push(var->name()); | |
1673 __ CallRuntime(Runtime::kThrowReferenceError); | |
1674 __ bind(&uninitialized_this); | |
1675 EmitStoreToStackLocalOrContextSlot(var, location); | |
1676 | |
1677 } else { | 1618 } else { |
1678 DCHECK(var->mode() != CONST || op == Token::INIT); | 1619 DCHECK(!var->is_this()); |
1679 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 1620 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
1680 DCHECK(!var->IsLookupSlot()); | 1621 DCHECK(!var->IsLookupSlot()); |
1681 // Assignment to var or initializing assignment to let/const in harmony | |
1682 // mode. | |
1683 MemOperand location = VarOperand(var, rcx); | 1622 MemOperand location = VarOperand(var, rcx); |
1684 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { | |
1685 // Check for an uninitialized let binding. | |
1686 __ movp(rdx, location); | |
1687 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
1688 __ Check(equal, kLetBindingReInitialization); | |
1689 } | |
1690 EmitStoreToStackLocalOrContextSlot(var, location); | 1623 EmitStoreToStackLocalOrContextSlot(var, location); |
1691 } | 1624 } |
1692 } | 1625 } |
1693 | 1626 |
1694 | 1627 |
1695 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1628 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1696 // Assignment to a property, using a named store IC. | 1629 // Assignment to a property, using a named store IC. |
1697 Property* prop = expr->target()->AsProperty(); | 1630 Property* prop = expr->target()->AsProperty(); |
1698 DCHECK(prop != NULL); | 1631 DCHECK(prop != NULL); |
1699 DCHECK(prop->key()->IsLiteral()); | 1632 DCHECK(prop->key()->IsLiteral()); |
(...skipping 716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2416 patch_site.EmitPatchInfo(); | 2349 patch_site.EmitPatchInfo(); |
2417 __ bind(&done); | 2350 __ bind(&done); |
2418 | 2351 |
2419 // Store the value returned in rax. | 2352 // Store the value returned in rax. |
2420 switch (assign_type) { | 2353 switch (assign_type) { |
2421 case VARIABLE: { | 2354 case VARIABLE: { |
2422 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 2355 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
2423 if (expr->is_postfix()) { | 2356 if (expr->is_postfix()) { |
2424 // Perform the assignment as if via '='. | 2357 // Perform the assignment as if via '='. |
2425 { EffectContext context(this); | 2358 { EffectContext context(this); |
2426 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), | 2359 EmitVariableAssignment(proxy->var(), Token::ASSIGN, |
2427 proxy->hole_check_mode()); | 2360 expr->CountSlot()); |
2428 PrepareForBailoutForId(expr->AssignmentId(), | 2361 PrepareForBailoutForId(expr->AssignmentId(), |
2429 BailoutState::TOS_REGISTER); | 2362 BailoutState::TOS_REGISTER); |
2430 context.Plug(rax); | 2363 context.Plug(rax); |
2431 } | 2364 } |
2432 // For all contexts except kEffect: We have the result on | 2365 // For all contexts except kEffect: We have the result on |
2433 // top of the stack. | 2366 // top of the stack. |
2434 if (!context()->IsEffect()) { | 2367 if (!context()->IsEffect()) { |
2435 context()->PlugTOS(); | 2368 context()->PlugTOS(); |
2436 } | 2369 } |
2437 } else { | 2370 } else { |
2438 // Perform the assignment as if via '='. | 2371 // Perform the assignment as if via '='. |
2439 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), | 2372 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot()); |
2440 proxy->hole_check_mode()); | |
2441 PrepareForBailoutForId(expr->AssignmentId(), | 2373 PrepareForBailoutForId(expr->AssignmentId(), |
2442 BailoutState::TOS_REGISTER); | 2374 BailoutState::TOS_REGISTER); |
2443 context()->Plug(rax); | 2375 context()->Plug(rax); |
2444 } | 2376 } |
2445 break; | 2377 break; |
2446 } | 2378 } |
2447 case NAMED_PROPERTY: { | 2379 case NAMED_PROPERTY: { |
2448 PopOperand(StoreDescriptor::ReceiverRegister()); | 2380 PopOperand(StoreDescriptor::ReceiverRegister()); |
2449 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); | 2381 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); |
2450 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 2382 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2776 DCHECK_EQ( | 2708 DCHECK_EQ( |
2777 isolate->builtins()->OnStackReplacement()->entry(), | 2709 isolate->builtins()->OnStackReplacement()->entry(), |
2778 Assembler::target_address_at(call_target_address, unoptimized_code)); | 2710 Assembler::target_address_at(call_target_address, unoptimized_code)); |
2779 return ON_STACK_REPLACEMENT; | 2711 return ON_STACK_REPLACEMENT; |
2780 } | 2712 } |
2781 | 2713 |
2782 } // namespace internal | 2714 } // namespace internal |
2783 } // namespace v8 | 2715 } // namespace v8 |
2784 | 2716 |
2785 #endif // V8_TARGET_ARCH_X64 | 2717 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |