OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 770 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
771 // Call the runtime to declare the globals. | 771 // Call the runtime to declare the globals. |
772 __ push(rsi); // The context is the first argument. | 772 __ push(rsi); // The context is the first argument. |
773 __ Push(pairs); | 773 __ Push(pairs); |
774 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 774 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
775 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 775 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
776 // Return value is ignored. | 776 // Return value is ignored. |
777 } | 777 } |
778 | 778 |
779 | 779 |
780 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 780 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
781 Comment cmnt(masm_, "[ FunctionLiteral"); | 781 UNREACHABLE(); |
| 782 } |
782 | 783 |
783 // Build the shared function info and instantiate the function based | |
784 // on it. | |
785 Handle<SharedFunctionInfo> function_info = | |
786 Compiler::BuildFunctionInfo(expr, script(), this); | |
787 if (HasStackOverflow()) return; | |
788 | 784 |
789 // Create a new closure. | 785 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
790 __ push(rsi); | 786 UNREACHABLE(); |
791 __ Push(function_info); | 787 } |
792 __ CallRuntime(Runtime::kNewClosure, 2); | 788 |
| 789 |
| 790 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { |
| 791 // Use the fast case closure allocation code that allocates in new |
| 792 // space for nested functions that don't need literals cloning. |
| 793 if (scope()->is_function_scope() && info->num_literals() == 0) { |
| 794 FastNewClosureStub stub; |
| 795 __ Push(info); |
| 796 __ CallStub(&stub); |
| 797 } else { |
| 798 __ push(rsi); |
| 799 __ Push(info); |
| 800 __ CallRuntime(Runtime::kNewClosure, 2); |
| 801 } |
793 Apply(context_, rax); | 802 Apply(context_, rax); |
794 } | 803 } |
795 | 804 |
796 | 805 |
797 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 806 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
798 Comment cmnt(masm_, "[ VariableProxy"); | 807 Comment cmnt(masm_, "[ VariableProxy"); |
799 EmitVariableLoad(expr->var(), context_); | 808 EmitVariableLoad(expr->var(), context_); |
800 } | 809 } |
801 | 810 |
802 | 811 |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 if (result_saved) { | 1021 if (result_saved) { |
1013 ApplyTOS(context_); | 1022 ApplyTOS(context_); |
1014 } else { | 1023 } else { |
1015 Apply(context_, rax); | 1024 Apply(context_, rax); |
1016 } | 1025 } |
1017 } | 1026 } |
1018 | 1027 |
1019 | 1028 |
1020 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1029 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
1021 Comment cmnt(masm_, "[ Assignment"); | 1030 Comment cmnt(masm_, "[ Assignment"); |
1022 ASSERT(expr->op() != Token::INIT_CONST); | 1031 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1032 // on the left-hand side. |
| 1033 if (!expr->target()->IsValidLeftHandSide()) { |
| 1034 VisitForEffect(expr->target()); |
| 1035 return; |
| 1036 } |
| 1037 |
1023 // Left-hand side can only be a property, a global or a (parameter or local) | 1038 // Left-hand side can only be a property, a global or a (parameter or local) |
1024 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1039 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1025 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1040 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1026 LhsKind assign_type = VARIABLE; | 1041 LhsKind assign_type = VARIABLE; |
1027 Property* prop = expr->target()->AsProperty(); | 1042 Property* prop = expr->target()->AsProperty(); |
1028 if (prop != NULL) { | 1043 if (prop != NULL) { |
1029 assign_type = | 1044 assign_type = |
1030 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 1045 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
1031 } | 1046 } |
1032 | 1047 |
1033 // Evaluate LHS expression. | 1048 // Evaluate LHS expression. |
1034 switch (assign_type) { | 1049 switch (assign_type) { |
1035 case VARIABLE: | 1050 case VARIABLE: |
1036 // Nothing to do here. | 1051 // Nothing to do here. |
1037 break; | 1052 break; |
1038 case NAMED_PROPERTY: | 1053 case NAMED_PROPERTY: |
1039 if (expr->is_compound()) { | 1054 if (expr->is_compound()) { |
1040 // We need the receiver both on the stack and in the accumulator. | 1055 // We need the receiver both on the stack and in the accumulator. |
1041 VisitForValue(prop->obj(), kAccumulator); | 1056 VisitForValue(prop->obj(), kAccumulator); |
1042 __ push(result_register()); | 1057 __ push(result_register()); |
1043 } else { | 1058 } else { |
1044 VisitForValue(prop->obj(), kStack); | 1059 VisitForValue(prop->obj(), kStack); |
1045 } | 1060 } |
1046 break; | 1061 break; |
1047 case KEYED_PROPERTY: | 1062 case KEYED_PROPERTY: |
1048 VisitForValue(prop->obj(), kStack); | 1063 if (expr->is_compound()) { |
1049 VisitForValue(prop->key(), kStack); | 1064 VisitForValue(prop->obj(), kStack); |
| 1065 VisitForValue(prop->key(), kAccumulator); |
| 1066 __ movq(rdx, Operand(rsp, 0)); |
| 1067 __ push(rax); |
| 1068 } else { |
| 1069 VisitForValue(prop->obj(), kStack); |
| 1070 VisitForValue(prop->key(), kStack); |
| 1071 } |
1050 break; | 1072 break; |
1051 } | 1073 } |
1052 | 1074 |
1053 // If we have a compound assignment: Get value of LHS expression and | 1075 // If we have a compound assignment: Get value of LHS expression and |
1054 // store in on top of the stack. | 1076 // store in on top of the stack. |
1055 if (expr->is_compound()) { | 1077 if (expr->is_compound()) { |
1056 Location saved_location = location_; | 1078 Location saved_location = location_; |
1057 location_ = kStack; | 1079 location_ = kStack; |
1058 switch (assign_type) { | 1080 switch (assign_type) { |
1059 case VARIABLE: | 1081 case VARIABLE: |
(...skipping 24 matching lines...) Expand all Loading... |
1084 location_ = saved_location; | 1106 location_ = saved_location; |
1085 } | 1107 } |
1086 | 1108 |
1087 // Record source position before possible IC call. | 1109 // Record source position before possible IC call. |
1088 SetSourcePosition(expr->position()); | 1110 SetSourcePosition(expr->position()); |
1089 | 1111 |
1090 // Store the value. | 1112 // Store the value. |
1091 switch (assign_type) { | 1113 switch (assign_type) { |
1092 case VARIABLE: | 1114 case VARIABLE: |
1093 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1115 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1116 expr->op(), |
1094 context_); | 1117 context_); |
1095 break; | 1118 break; |
1096 case NAMED_PROPERTY: | 1119 case NAMED_PROPERTY: |
1097 EmitNamedPropertyAssignment(expr); | 1120 EmitNamedPropertyAssignment(expr); |
1098 break; | 1121 break; |
1099 case KEYED_PROPERTY: | 1122 case KEYED_PROPERTY: |
1100 EmitKeyedPropertyAssignment(expr); | 1123 EmitKeyedPropertyAssignment(expr); |
1101 break; | 1124 break; |
1102 } | 1125 } |
1103 } | 1126 } |
(...skipping 22 matching lines...) Expand all Loading... |
1126 __ push(result_register()); | 1149 __ push(result_register()); |
1127 GenericBinaryOpStub stub(op, | 1150 GenericBinaryOpStub stub(op, |
1128 NO_OVERWRITE, | 1151 NO_OVERWRITE, |
1129 NO_GENERIC_BINARY_FLAGS); | 1152 NO_GENERIC_BINARY_FLAGS); |
1130 __ CallStub(&stub); | 1153 __ CallStub(&stub); |
1131 Apply(context, rax); | 1154 Apply(context, rax); |
1132 } | 1155 } |
1133 | 1156 |
1134 | 1157 |
1135 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1158 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1159 Token::Value op, |
1136 Expression::Context context) { | 1160 Expression::Context context) { |
1137 // Three main cases: non-this global variables, lookup slots, and | 1161 // Left-hand sides that rewrite to explicit property accesses do not reach |
1138 // all other types of slots. Left-hand-side parameters that rewrite | 1162 // here. |
1139 // to explicit property accesses do not reach here. | |
1140 ASSERT(var != NULL); | 1163 ASSERT(var != NULL); |
1141 ASSERT(var->is_global() || var->slot() != NULL); | 1164 ASSERT(var->is_global() || var->slot() != NULL); |
1142 Slot* slot = var->slot(); | 1165 |
1143 if (var->is_global()) { | 1166 if (var->is_global()) { |
1144 ASSERT(!var->is_this()); | 1167 ASSERT(!var->is_this()); |
1145 // Assignment to a global variable. Use inline caching for the | 1168 // Assignment to a global variable. Use inline caching for the |
1146 // assignment. Right-hand-side value is passed in rax, variable name in | 1169 // assignment. Right-hand-side value is passed in rax, variable name in |
1147 // rcx, and the global object in rdx. | 1170 // rcx, and the global object on the stack. |
1148 __ Move(rcx, var->name()); | 1171 __ Move(rcx, var->name()); |
1149 __ movq(rdx, CodeGenerator::GlobalObject()); | 1172 __ movq(rdx, CodeGenerator::GlobalObject()); |
1150 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1173 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1151 __ Call(ic, RelocInfo::CODE_TARGET); | 1174 __ Call(ic, RelocInfo::CODE_TARGET); |
1152 Apply(context, rax); | 1175 __ nop(); |
1153 | 1176 |
1154 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1177 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { |
1155 __ push(result_register()); // Value. | 1178 // Perform the assignment for non-const variables and for initialization |
1156 __ push(rsi); // Context. | 1179 // of const variables. Const assignments are simply skipped. |
1157 __ Push(var->name()); | 1180 Label done; |
1158 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1181 Slot* slot = var->slot(); |
1159 Apply(context, rax); | |
1160 | |
1161 } else if (var->slot() != NULL) { | |
1162 switch (slot->type()) { | 1182 switch (slot->type()) { |
| 1183 case Slot::PARAMETER: |
1163 case Slot::LOCAL: | 1184 case Slot::LOCAL: |
1164 case Slot::PARAMETER: | 1185 if (op == Token::INIT_CONST) { |
1165 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); | 1186 // Detect const reinitialization by checking for the hole value. |
| 1187 __ movq(rdx, Operand(rbp, SlotOffset(slot))); |
| 1188 __ Cmp(rdx, Factory::the_hole_value()); |
| 1189 __ j(not_equal, &done); |
| 1190 } |
| 1191 // Perform the assignment. |
| 1192 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
1166 break; | 1193 break; |
1167 | 1194 |
1168 case Slot::CONTEXT: { | 1195 case Slot::CONTEXT: { |
1169 MemOperand target = EmitSlotSearch(slot, rcx); | 1196 MemOperand target = EmitSlotSearch(slot, rcx); |
1170 __ movq(target, result_register()); | 1197 if (op == Token::INIT_CONST) { |
1171 | 1198 // Detect const reinitialization by checking for the hole value. |
1172 // RecordWrite may destroy all its register arguments. | 1199 __ movq(rdx, target); |
1173 __ movq(rdx, result_register()); | 1200 __ Cmp(rdx, Factory::the_hole_value()); |
| 1201 __ j(not_equal, &done); |
| 1202 } |
| 1203 // Perform the assignment and issue the write barrier. |
| 1204 __ movq(target, rax); |
| 1205 // The value of the assignment is in rax. RecordWrite clobbers its |
| 1206 // register arguments. |
| 1207 __ movq(rdx, rax); |
1174 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1208 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
1175 __ RecordWrite(rcx, offset, rdx, rbx); | 1209 __ RecordWrite(rcx, offset, rdx, rbx); |
1176 break; | 1210 break; |
1177 } | 1211 } |
1178 | 1212 |
1179 case Slot::LOOKUP: | 1213 case Slot::LOOKUP: |
1180 UNREACHABLE(); | 1214 // Call the runtime for the assignment. The runtime will ignore |
| 1215 // const reinitialization. |
| 1216 __ push(rax); // Value. |
| 1217 __ push(rsi); // Context. |
| 1218 __ Push(var->name()); |
| 1219 if (op == Token::INIT_CONST) { |
| 1220 // The runtime will ignore const redeclaration. |
| 1221 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1222 } else { |
| 1223 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 1224 } |
1181 break; | 1225 break; |
1182 } | 1226 } |
1183 Apply(context, result_register()); | 1227 __ bind(&done); |
| 1228 } |
1184 | 1229 |
1185 } else { | 1230 Apply(context, rax); |
1186 // Variables rewritten as properties are not treated as variables in | |
1187 // assignments. | |
1188 UNREACHABLE(); | |
1189 } | |
1190 } | 1231 } |
1191 | 1232 |
1192 | 1233 |
1193 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1234 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1194 // Assignment to a property, using a named store IC. | 1235 // Assignment to a property, using a named store IC. |
1195 Property* prop = expr->target()->AsProperty(); | 1236 Property* prop = expr->target()->AsProperty(); |
1196 ASSERT(prop != NULL); | 1237 ASSERT(prop != NULL); |
1197 ASSERT(prop->key()->AsLiteral() != NULL); | 1238 ASSERT(prop->key()->AsLiteral() != NULL); |
1198 | 1239 |
1199 // If the assignment starts a block of assignments to the same object, | 1240 // If the assignment starts a block of assignments to the same object, |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1728 GenericBinaryOpStub stub(expr->binary_op(), | 1769 GenericBinaryOpStub stub(expr->binary_op(), |
1729 NO_OVERWRITE, | 1770 NO_OVERWRITE, |
1730 NO_GENERIC_BINARY_FLAGS); | 1771 NO_GENERIC_BINARY_FLAGS); |
1731 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); | 1772 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); |
1732 __ bind(&done); | 1773 __ bind(&done); |
1733 | 1774 |
1734 // Store the value returned in rax. | 1775 // Store the value returned in rax. |
1735 switch (assign_type) { | 1776 switch (assign_type) { |
1736 case VARIABLE: | 1777 case VARIABLE: |
1737 if (expr->is_postfix()) { | 1778 if (expr->is_postfix()) { |
| 1779 // Perform the assignment as if via '='. |
1738 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1780 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1781 Token::ASSIGN, |
1739 Expression::kEffect); | 1782 Expression::kEffect); |
1740 // For all contexts except kEffect: We have the result on | 1783 // For all contexts except kEffect: We have the result on |
1741 // top of the stack. | 1784 // top of the stack. |
1742 if (context_ != Expression::kEffect) { | 1785 if (context_ != Expression::kEffect) { |
1743 ApplyTOS(context_); | 1786 ApplyTOS(context_); |
1744 } | 1787 } |
1745 } else { | 1788 } else { |
| 1789 // Perform the assignment as if via '='. |
1746 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1790 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1791 Token::ASSIGN, |
1747 context_); | 1792 context_); |
1748 } | 1793 } |
1749 break; | 1794 break; |
1750 case NAMED_PROPERTY: { | 1795 case NAMED_PROPERTY: { |
1751 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1796 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
1752 __ pop(rdx); | 1797 __ pop(rdx); |
1753 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1798 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1754 __ call(ic, RelocInfo::CODE_TARGET); | 1799 __ call(ic, RelocInfo::CODE_TARGET); |
1755 // This nop signals to the IC that there is no inlined code at the call | 1800 // This nop signals to the IC that there is no inlined code at the call |
1756 // site for it to patch. | 1801 // site for it to patch. |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1984 __ movq(Operand(rsp, 0), rdx); | 2029 __ movq(Operand(rsp, 0), rdx); |
1985 // And return. | 2030 // And return. |
1986 __ ret(0); | 2031 __ ret(0); |
1987 } | 2032 } |
1988 | 2033 |
1989 | 2034 |
1990 #undef __ | 2035 #undef __ |
1991 | 2036 |
1992 | 2037 |
1993 } } // namespace v8::internal | 2038 } } // namespace v8::internal |
OLD | NEW |