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 697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | 708 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
709 __ Check(not_equal, kDeclarationInCatchContext); | 709 __ Check(not_equal, kDeclarationInCatchContext); |
710 } | 710 } |
711 } | 711 } |
712 | 712 |
713 | 713 |
714 void FullCodeGenerator::VisitVariableDeclaration( | 714 void FullCodeGenerator::VisitVariableDeclaration( |
715 VariableDeclaration* declaration) { | 715 VariableDeclaration* declaration) { |
716 VariableProxy* proxy = declaration->proxy(); | 716 VariableProxy* proxy = declaration->proxy(); |
717 Variable* variable = proxy->var(); | 717 Variable* variable = proxy->var(); |
718 DCHECK(!variable->binding_needs_init()); | |
719 switch (variable->location()) { | 718 switch (variable->location()) { |
720 case VariableLocation::UNALLOCATED: { | 719 case VariableLocation::UNALLOCATED: { |
| 720 DCHECK(!variable->binding_needs_init()); |
721 globals_->Add(variable->name(), zone()); | 721 globals_->Add(variable->name(), zone()); |
722 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); | 722 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); |
723 DCHECK(!slot.IsInvalid()); | 723 DCHECK(!slot.IsInvalid()); |
724 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); | 724 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); |
725 globals_->Add(isolate()->factory()->undefined_value(), zone()); | 725 globals_->Add(isolate()->factory()->undefined_value(), zone()); |
726 break; | 726 break; |
727 } | 727 } |
728 case VariableLocation::PARAMETER: | 728 case VariableLocation::PARAMETER: |
729 case VariableLocation::LOCAL: | 729 case VariableLocation::LOCAL: |
| 730 if (variable->binding_needs_init()) { |
| 731 Comment cmnt(masm_, "[ VariableDeclaration"); |
| 732 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 733 __ movp(StackOperand(variable), kScratchRegister); |
| 734 } |
| 735 break; |
| 736 |
730 case VariableLocation::CONTEXT: | 737 case VariableLocation::CONTEXT: |
| 738 if (variable->binding_needs_init()) { |
| 739 Comment cmnt(masm_, "[ VariableDeclaration"); |
| 740 EmitDebugCheckDeclarationContext(variable); |
| 741 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 742 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister); |
| 743 // No write barrier since the hole value is in old space. |
| 744 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
| 745 } |
731 break; | 746 break; |
732 | 747 |
733 case VariableLocation::LOOKUP: | 748 case VariableLocation::LOOKUP: |
734 case VariableLocation::MODULE: | 749 case VariableLocation::MODULE: |
735 UNREACHABLE(); | 750 UNREACHABLE(); |
736 } | 751 } |
737 } | 752 } |
738 | 753 |
739 | 754 |
740 void FullCodeGenerator::VisitFunctionDeclaration( | 755 void FullCodeGenerator::VisitFunctionDeclaration( |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 Operand(rsp, offset * kPointerSize)); | 1095 Operand(rsp, offset * kPointerSize)); |
1081 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1096 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); |
1082 } | 1097 } |
1083 | 1098 |
1084 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1099 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
1085 TypeofMode typeof_mode) { | 1100 TypeofMode typeof_mode) { |
1086 // Record position before possible IC call. | 1101 // Record position before possible IC call. |
1087 SetExpressionPosition(proxy); | 1102 SetExpressionPosition(proxy); |
1088 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); | 1103 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); |
1089 Variable* var = proxy->var(); | 1104 Variable* var = proxy->var(); |
1090 DCHECK(!var->binding_needs_init()); | |
1091 | 1105 |
1092 // Two cases: global variable, and all other types of variables. | 1106 // Two cases: global variable, and all other types of variables. |
1093 switch (var->location()) { | 1107 switch (var->location()) { |
1094 case VariableLocation::UNALLOCATED: { | 1108 case VariableLocation::UNALLOCATED: { |
1095 Comment cmnt(masm_, "[ Global variable"); | 1109 Comment cmnt(masm_, "[ Global variable"); |
1096 EmitGlobalVariableLoad(proxy, typeof_mode); | 1110 EmitGlobalVariableLoad(proxy, typeof_mode); |
1097 context()->Plug(rax); | 1111 context()->Plug(rax); |
1098 break; | 1112 break; |
1099 } | 1113 } |
1100 | 1114 |
1101 case VariableLocation::PARAMETER: | 1115 case VariableLocation::PARAMETER: |
1102 case VariableLocation::LOCAL: | 1116 case VariableLocation::LOCAL: |
1103 case VariableLocation::CONTEXT: { | 1117 case VariableLocation::CONTEXT: { |
1104 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); | 1118 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); |
1105 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" | 1119 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" |
1106 : "[ Stack slot"); | 1120 : "[ Stack slot"); |
| 1121 if (proxy->hole_check_mode() == HoleCheckMode::kRequired) { |
| 1122 // Throw a reference error when using an uninitialized let/const |
| 1123 // binding in harmony mode. |
| 1124 DCHECK(IsLexicalVariableMode(var->mode())); |
| 1125 Label done; |
| 1126 GetVar(rax, var); |
| 1127 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1128 __ j(not_equal, &done, Label::kNear); |
| 1129 __ Push(var->name()); |
| 1130 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1131 __ bind(&done); |
| 1132 context()->Plug(rax); |
| 1133 break; |
| 1134 } |
1107 context()->Plug(var); | 1135 context()->Plug(var); |
1108 break; | 1136 break; |
1109 } | 1137 } |
1110 | 1138 |
1111 case VariableLocation::LOOKUP: | 1139 case VariableLocation::LOOKUP: |
1112 case VariableLocation::MODULE: | 1140 case VariableLocation::MODULE: |
1113 UNREACHABLE(); | 1141 UNREACHABLE(); |
1114 } | 1142 } |
1115 } | 1143 } |
1116 | 1144 |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1411 } else { | 1439 } else { |
1412 VisitForAccumulatorValue(expr->value()); | 1440 VisitForAccumulatorValue(expr->value()); |
1413 } | 1441 } |
1414 | 1442 |
1415 SetExpressionPosition(expr); | 1443 SetExpressionPosition(expr); |
1416 | 1444 |
1417 // Store the value. | 1445 // Store the value. |
1418 switch (assign_type) { | 1446 switch (assign_type) { |
1419 case VARIABLE: { | 1447 case VARIABLE: { |
1420 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 1448 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
1421 EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot()); | 1449 EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(), |
| 1450 proxy->hole_check_mode()); |
1422 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 1451 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
1423 context()->Plug(rax); | 1452 context()->Plug(rax); |
1424 break; | 1453 break; |
1425 } | 1454 } |
1426 case NAMED_PROPERTY: | 1455 case NAMED_PROPERTY: |
1427 EmitNamedPropertyAssignment(expr); | 1456 EmitNamedPropertyAssignment(expr); |
1428 break; | 1457 break; |
1429 case KEYED_PROPERTY: | 1458 case KEYED_PROPERTY: |
1430 EmitKeyedPropertyAssignment(expr); | 1459 EmitKeyedPropertyAssignment(expr); |
1431 break; | 1460 break; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1557 FeedbackVectorSlot slot) { | 1586 FeedbackVectorSlot slot) { |
1558 DCHECK(expr->IsValidReferenceExpressionOrThis()); | 1587 DCHECK(expr->IsValidReferenceExpressionOrThis()); |
1559 | 1588 |
1560 Property* prop = expr->AsProperty(); | 1589 Property* prop = expr->AsProperty(); |
1561 LhsKind assign_type = Property::GetAssignType(prop); | 1590 LhsKind assign_type = Property::GetAssignType(prop); |
1562 | 1591 |
1563 switch (assign_type) { | 1592 switch (assign_type) { |
1564 case VARIABLE: { | 1593 case VARIABLE: { |
1565 VariableProxy* proxy = expr->AsVariableProxy(); | 1594 VariableProxy* proxy = expr->AsVariableProxy(); |
1566 EffectContext context(this); | 1595 EffectContext context(this); |
1567 EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot); | 1596 EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot, |
| 1597 proxy->hole_check_mode()); |
1568 break; | 1598 break; |
1569 } | 1599 } |
1570 case NAMED_PROPERTY: { | 1600 case NAMED_PROPERTY: { |
1571 PushOperand(rax); // Preserve value. | 1601 PushOperand(rax); // Preserve value. |
1572 VisitForAccumulatorValue(prop->obj()); | 1602 VisitForAccumulatorValue(prop->obj()); |
1573 __ Move(StoreDescriptor::ReceiverRegister(), rax); | 1603 __ Move(StoreDescriptor::ReceiverRegister(), rax); |
1574 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. | 1604 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. |
1575 CallStoreIC(slot, prop->key()->AsLiteral()->value()); | 1605 CallStoreIC(slot, prop->key()->AsLiteral()->value()); |
1576 break; | 1606 break; |
1577 } | 1607 } |
(...skipping 20 matching lines...) Expand all Loading... |
1598 Variable* var, MemOperand location) { | 1628 Variable* var, MemOperand location) { |
1599 __ movp(location, rax); | 1629 __ movp(location, rax); |
1600 if (var->IsContextSlot()) { | 1630 if (var->IsContextSlot()) { |
1601 __ movp(rdx, rax); | 1631 __ movp(rdx, rax); |
1602 __ RecordWriteContextSlot( | 1632 __ RecordWriteContextSlot( |
1603 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | 1633 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1604 } | 1634 } |
1605 } | 1635 } |
1606 | 1636 |
1607 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, | 1637 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, |
1608 FeedbackVectorSlot slot) { | 1638 FeedbackVectorSlot slot, |
1609 DCHECK(!var->binding_needs_init()); | 1639 HoleCheckMode hole_check_mode) { |
1610 if (var->IsUnallocated()) { | 1640 if (var->IsUnallocated()) { |
1611 // Global var, const, or let. | 1641 // Global var, const, or let. |
1612 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); | 1642 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); |
1613 CallStoreIC(slot, var->name()); | 1643 CallStoreIC(slot, var->name()); |
1614 | 1644 |
1615 } else if (var->mode() == CONST && op != Token::INIT) { | 1645 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { |
1616 if (var->throw_on_const_assignment(language_mode())) { | 1646 DCHECK(!var->IsLookupSlot()); |
| 1647 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 1648 MemOperand location = VarOperand(var, rcx); |
| 1649 // Perform an initialization check for lexically declared variables. |
| 1650 if (hole_check_mode == HoleCheckMode::kRequired) { |
| 1651 Label assign; |
| 1652 __ movp(rdx, location); |
| 1653 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1654 __ j(not_equal, &assign, Label::kNear); |
| 1655 __ Push(var->name()); |
| 1656 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1657 __ bind(&assign); |
| 1658 } |
| 1659 if (var->mode() != CONST) { |
| 1660 EmitStoreToStackLocalOrContextSlot(var, location); |
| 1661 } else if (var->throw_on_const_assignment(language_mode())) { |
1617 __ CallRuntime(Runtime::kThrowConstAssignError); | 1662 __ CallRuntime(Runtime::kThrowConstAssignError); |
1618 } | 1663 } |
| 1664 |
| 1665 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { |
| 1666 // Initializing assignment to const {this} needs a write barrier. |
| 1667 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 1668 Label uninitialized_this; |
| 1669 MemOperand location = VarOperand(var, rcx); |
| 1670 __ movp(rdx, location); |
| 1671 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1672 __ j(equal, &uninitialized_this); |
| 1673 __ Push(var->name()); |
| 1674 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1675 __ bind(&uninitialized_this); |
| 1676 EmitStoreToStackLocalOrContextSlot(var, location); |
| 1677 |
1619 } else { | 1678 } else { |
1620 DCHECK(!var->is_this()); | 1679 DCHECK(var->mode() != CONST || op == Token::INIT); |
1621 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 1680 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
1622 DCHECK(!var->IsLookupSlot()); | 1681 DCHECK(!var->IsLookupSlot()); |
| 1682 // Assignment to var or initializing assignment to let/const in harmony |
| 1683 // mode. |
1623 MemOperand location = VarOperand(var, rcx); | 1684 MemOperand location = VarOperand(var, rcx); |
| 1685 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { |
| 1686 // Check for an uninitialized let binding. |
| 1687 __ movp(rdx, location); |
| 1688 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1689 __ Check(equal, kLetBindingReInitialization); |
| 1690 } |
1624 EmitStoreToStackLocalOrContextSlot(var, location); | 1691 EmitStoreToStackLocalOrContextSlot(var, location); |
1625 } | 1692 } |
1626 } | 1693 } |
1627 | 1694 |
1628 | 1695 |
1629 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1696 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1630 // Assignment to a property, using a named store IC. | 1697 // Assignment to a property, using a named store IC. |
1631 Property* prop = expr->target()->AsProperty(); | 1698 Property* prop = expr->target()->AsProperty(); |
1632 DCHECK(prop != NULL); | 1699 DCHECK(prop != NULL); |
1633 DCHECK(prop->key()->IsLiteral()); | 1700 DCHECK(prop->key()->IsLiteral()); |
(...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2328 patch_site.EmitPatchInfo(); | 2395 patch_site.EmitPatchInfo(); |
2329 __ bind(&done); | 2396 __ bind(&done); |
2330 | 2397 |
2331 // Store the value returned in rax. | 2398 // Store the value returned in rax. |
2332 switch (assign_type) { | 2399 switch (assign_type) { |
2333 case VARIABLE: { | 2400 case VARIABLE: { |
2334 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 2401 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
2335 if (expr->is_postfix()) { | 2402 if (expr->is_postfix()) { |
2336 // Perform the assignment as if via '='. | 2403 // Perform the assignment as if via '='. |
2337 { EffectContext context(this); | 2404 { EffectContext context(this); |
2338 EmitVariableAssignment(proxy->var(), Token::ASSIGN, | 2405 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), |
2339 expr->CountSlot()); | 2406 proxy->hole_check_mode()); |
2340 PrepareForBailoutForId(expr->AssignmentId(), | 2407 PrepareForBailoutForId(expr->AssignmentId(), |
2341 BailoutState::TOS_REGISTER); | 2408 BailoutState::TOS_REGISTER); |
2342 context.Plug(rax); | 2409 context.Plug(rax); |
2343 } | 2410 } |
2344 // For all contexts except kEffect: We have the result on | 2411 // For all contexts except kEffect: We have the result on |
2345 // top of the stack. | 2412 // top of the stack. |
2346 if (!context()->IsEffect()) { | 2413 if (!context()->IsEffect()) { |
2347 context()->PlugTOS(); | 2414 context()->PlugTOS(); |
2348 } | 2415 } |
2349 } else { | 2416 } else { |
2350 // Perform the assignment as if via '='. | 2417 // Perform the assignment as if via '='. |
2351 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot()); | 2418 EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), |
| 2419 proxy->hole_check_mode()); |
2352 PrepareForBailoutForId(expr->AssignmentId(), | 2420 PrepareForBailoutForId(expr->AssignmentId(), |
2353 BailoutState::TOS_REGISTER); | 2421 BailoutState::TOS_REGISTER); |
2354 context()->Plug(rax); | 2422 context()->Plug(rax); |
2355 } | 2423 } |
2356 break; | 2424 break; |
2357 } | 2425 } |
2358 case NAMED_PROPERTY: { | 2426 case NAMED_PROPERTY: { |
2359 PopOperand(StoreDescriptor::ReceiverRegister()); | 2427 PopOperand(StoreDescriptor::ReceiverRegister()); |
2360 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); | 2428 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); |
2361 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 2429 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2687 DCHECK_EQ( | 2755 DCHECK_EQ( |
2688 isolate->builtins()->OnStackReplacement()->entry(), | 2756 isolate->builtins()->OnStackReplacement()->entry(), |
2689 Assembler::target_address_at(call_target_address, unoptimized_code)); | 2757 Assembler::target_address_at(call_target_address, unoptimized_code)); |
2690 return ON_STACK_REPLACEMENT; | 2758 return ON_STACK_REPLACEMENT; |
2691 } | 2759 } |
2692 | 2760 |
2693 } // namespace internal | 2761 } // namespace internal |
2694 } // namespace v8 | 2762 } // namespace v8 |
2695 | 2763 |
2696 #endif // V8_TARGET_ARCH_X64 | 2764 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |