Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(674)

Side by Side Diff: src/codegen-ia32.cc

Issue 40290: Experimental: Merge 1395:1441 from bleeding_edge branch to the... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/global/
Patch Set: Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-arm.cc ('k') | src/compilation-cache.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 Result answer = frame_->CallStub(&stub, 3); 147 Result answer = frame_->CallStub(&stub, 3);
148 frame_->Push(&answer); 148 frame_->Push(&answer);
149 } 149 }
150 150
151 if (scope_->num_heap_slots() > 0) { 151 if (scope_->num_heap_slots() > 0) {
152 Comment cmnt(masm_, "[ allocate local context"); 152 Comment cmnt(masm_, "[ allocate local context");
153 // Allocate local context. 153 // Allocate local context.
154 // Get outer context and create a new context based on it. 154 // Get outer context and create a new context based on it.
155 frame_->PushFunction(); 155 frame_->PushFunction();
156 Result context = frame_->CallRuntime(Runtime::kNewContext, 1); 156 Result context = frame_->CallRuntime(Runtime::kNewContext, 1);
157
157 // Update context local. 158 // Update context local.
158 frame_->SaveContextRegister(); 159 frame_->SaveContextRegister();
159 160
160 if (kDebug) { 161 // Verify that the runtime call result and esi agree.
161 JumpTarget verified_true(this); 162 if (FLAG_debug_code) {
162 // Verify eax and esi are the same in debug mode
163 __ cmp(context.reg(), Operand(esi)); 163 __ cmp(context.reg(), Operand(esi));
164 context.Unuse(); 164 __ Assert(equal, "Runtime::NewContext should end up in esi");
165 verified_true.Branch(equal);
166 frame_->SpillAll();
167 __ int3();
168 verified_true.Bind();
169 } 165 }
170 } 166 }
171 167
172 // TODO(1241774): Improve this code: 168 // TODO(1241774): Improve this code:
173 // 1) only needed if we have a context 169 // 1) only needed if we have a context
174 // 2) no need to recompute context ptr every single time 170 // 2) no need to recompute context ptr every single time
175 // 3) don't copy parameter operand code from SlotOperand! 171 // 3) don't copy parameter operand code from SlotOperand!
176 { 172 {
177 Comment cmnt2(masm_, "[ copy context parameters into .context"); 173 Comment cmnt2(masm_, "[ copy context parameters into .context");
178 174
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 return OpBits::encode(op_) | 725 return OpBits::encode(op_) |
730 ModeBits::encode(mode_) | 726 ModeBits::encode(mode_) |
731 FlagBits::encode(flags_); 727 FlagBits::encode(flags_);
732 } 728 }
733 void Generate(MacroAssembler* masm); 729 void Generate(MacroAssembler* masm);
734 }; 730 };
735 731
736 732
737 const char* GenericBinaryOpStub::GetName() { 733 const char* GenericBinaryOpStub::GetName() {
738 switch (op_) { 734 switch (op_) {
739 case Token::ADD: return "GenericBinaryOpStub_ADD"; 735 case Token::ADD: return "GenericBinaryOpStub_ADD";
740 case Token::SUB: return "GenericBinaryOpStub_SUB"; 736 case Token::SUB: return "GenericBinaryOpStub_SUB";
741 case Token::MUL: return "GenericBinaryOpStub_MUL"; 737 case Token::MUL: return "GenericBinaryOpStub_MUL";
742 case Token::DIV: return "GenericBinaryOpStub_DIV"; 738 case Token::DIV: return "GenericBinaryOpStub_DIV";
743 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; 739 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
744 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; 740 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
745 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; 741 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
746 case Token::SAR: return "GenericBinaryOpStub_SAR"; 742 case Token::SAR: return "GenericBinaryOpStub_SAR";
747 case Token::SHL: return "GenericBinaryOpStub_SHL"; 743 case Token::SHL: return "GenericBinaryOpStub_SHL";
748 case Token::SHR: return "GenericBinaryOpStub_SHR"; 744 case Token::SHR: return "GenericBinaryOpStub_SHR";
749 default: return "GenericBinaryOpStub"; 745 default: return "GenericBinaryOpStub";
750 } 746 }
751 } 747 }
752 748
753 749
754 class DeferredInlineBinaryOperation: public DeferredCode { 750 class DeferredInlineBinaryOperation: public DeferredCode {
755 public: 751 public:
756 DeferredInlineBinaryOperation(CodeGenerator* generator, 752 DeferredInlineBinaryOperation(CodeGenerator* generator,
757 Token::Value op, 753 Token::Value op,
758 OverwriteMode mode, 754 OverwriteMode mode,
759 GenericBinaryFlags flags) 755 GenericBinaryFlags flags)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 GenericBinaryOpStub stub(op, overwrite_mode, flags); 829 GenericBinaryOpStub stub(op, overwrite_mode, flags);
834 Result answer = frame_->CallStub(&stub, 2); 830 Result answer = frame_->CallStub(&stub, 2);
835 frame_->Push(&answer); 831 frame_->Push(&answer);
836 } 832 }
837 } 833 }
838 834
839 835
840 class DeferredInlineSmiOperation: public DeferredCode { 836 class DeferredInlineSmiOperation: public DeferredCode {
841 public: 837 public:
842 DeferredInlineSmiOperation(CodeGenerator* generator, 838 DeferredInlineSmiOperation(CodeGenerator* generator,
843 Token::Value op, 839 Token::Value op,
844 Smi* value, 840 Smi* value,
845 OverwriteMode overwrite_mode) 841 OverwriteMode overwrite_mode)
846 : DeferredCode(generator), 842 : DeferredCode(generator),
847 op_(op), 843 op_(op),
848 value_(value), 844 value_(value),
849 overwrite_mode_(overwrite_mode) { 845 overwrite_mode_(overwrite_mode) {
850 set_comment("[ DeferredInlineSmiOperation"); 846 set_comment("[ DeferredInlineSmiOperation");
851 } 847 }
852 848
853 virtual void Generate(); 849 virtual void Generate();
854 850
855 private: 851 private:
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 if (reversed) { 1112 if (reversed) {
1117 Result top = frame_->Pop(); 1113 Result top = frame_->Pop();
1118 frame_->Push(value); 1114 frame_->Push(value);
1119 frame_->Push(&top); 1115 frame_->Push(&top);
1120 GenericBinaryOperation(op, type, overwrite_mode); 1116 GenericBinaryOperation(op, type, overwrite_mode);
1121 } else { 1117 } else {
1122 // Only the least significant 5 bits of the shift value are used. 1118 // Only the least significant 5 bits of the shift value are used.
1123 // In the slow case, this masking is done inside the runtime call. 1119 // In the slow case, this masking is done inside the runtime call.
1124 int shift_value = int_value & 0x1f; 1120 int shift_value = int_value & 0x1f;
1125 DeferredCode* deferred = 1121 DeferredCode* deferred =
1126 new DeferredInlineSmiOperation(this, Token::SAR, smi_value, 1122 new DeferredInlineSmiOperation(this, Token::SAR, smi_value,
1127 overwrite_mode); 1123 overwrite_mode);
1128 Result result = frame_->Pop(); 1124 Result result = frame_->Pop();
1129 result.ToRegister(); 1125 result.ToRegister();
1130 __ test(result.reg(), Immediate(kSmiTagMask)); 1126 __ test(result.reg(), Immediate(kSmiTagMask));
1131 deferred->enter()->Branch(not_zero, &result, not_taken); 1127 deferred->enter()->Branch(not_zero, &result, not_taken);
1132 frame_->Spill(result.reg()); 1128 frame_->Spill(result.reg());
1133 __ sar(result.reg(), shift_value); 1129 __ sar(result.reg(), shift_value);
1134 __ and_(result.reg(), ~kSmiTagMask); 1130 __ and_(result.reg(), ~kSmiTagMask);
1135 deferred->BindExit(&result); 1131 deferred->BindExit(&result);
1136 frame_->Push(&result); 1132 frame_->Push(&result);
1137 } 1133 }
1138 break; 1134 break;
1139 } 1135 }
1140 1136
1141 case Token::SHR: { 1137 case Token::SHR: {
1142 if (reversed) { 1138 if (reversed) {
1143 Result top = frame_->Pop(); 1139 Result top = frame_->Pop();
1144 frame_->Push(value); 1140 frame_->Push(value);
1145 frame_->Push(&top); 1141 frame_->Push(&top);
1146 GenericBinaryOperation(op, type, overwrite_mode); 1142 GenericBinaryOperation(op, type, overwrite_mode);
1147 } else { 1143 } else {
1148 // Only the least significant 5 bits of the shift value are used. 1144 // Only the least significant 5 bits of the shift value are used.
1149 // In the slow case, this masking is done inside the runtime call. 1145 // In the slow case, this masking is done inside the runtime call.
1150 int shift_value = int_value & 0x1f; 1146 int shift_value = int_value & 0x1f;
1151 DeferredCode* deferred = 1147 DeferredCode* deferred =
1152 new DeferredInlineSmiOperation(this, Token::SHR, smi_value, 1148 new DeferredInlineSmiOperation(this, Token::SHR, smi_value,
1153 overwrite_mode); 1149 overwrite_mode);
1154 Result operand = frame_->Pop(); 1150 Result operand = frame_->Pop();
1155 operand.ToRegister(); 1151 operand.ToRegister();
1156 __ test(operand.reg(), Immediate(kSmiTagMask)); 1152 __ test(operand.reg(), Immediate(kSmiTagMask));
1157 deferred->enter()->Branch(not_zero, &operand, not_taken); 1153 deferred->enter()->Branch(not_zero, &operand, not_taken);
1158 Result answer = allocator()->Allocate(); 1154 Result answer = allocator()->Allocate();
1159 ASSERT(answer.is_valid()); 1155 ASSERT(answer.is_valid());
1160 __ mov(answer.reg(), Operand(operand.reg())); 1156 __ mov(answer.reg(), Operand(operand.reg()));
1161 __ sar(answer.reg(), kSmiTagSize); 1157 __ sar(answer.reg(), kSmiTagSize);
1162 __ shr(answer.reg(), shift_value); 1158 __ shr(answer.reg(), shift_value);
1163 // A negative Smi shifted right two is in the positive Smi range. 1159 // A negative Smi shifted right two is in the positive Smi range.
(...skipping 15 matching lines...) Expand all
1179 if (reversed) { 1175 if (reversed) {
1180 Result top = frame_->Pop(); 1176 Result top = frame_->Pop();
1181 frame_->Push(value); 1177 frame_->Push(value);
1182 frame_->Push(&top); 1178 frame_->Push(&top);
1183 GenericBinaryOperation(op, type, overwrite_mode); 1179 GenericBinaryOperation(op, type, overwrite_mode);
1184 } else { 1180 } else {
1185 // Only the least significant 5 bits of the shift value are used. 1181 // Only the least significant 5 bits of the shift value are used.
1186 // In the slow case, this masking is done inside the runtime call. 1182 // In the slow case, this masking is done inside the runtime call.
1187 int shift_value = int_value & 0x1f; 1183 int shift_value = int_value & 0x1f;
1188 DeferredCode* deferred = 1184 DeferredCode* deferred =
1189 new DeferredInlineSmiOperation(this, Token::SHL, smi_value, 1185 new DeferredInlineSmiOperation(this, Token::SHL, smi_value,
1190 overwrite_mode); 1186 overwrite_mode);
1191 Result operand = frame_->Pop(); 1187 Result operand = frame_->Pop();
1192 operand.ToRegister(); 1188 operand.ToRegister();
1193 __ test(operand.reg(), Immediate(kSmiTagMask)); 1189 __ test(operand.reg(), Immediate(kSmiTagMask));
1194 deferred->enter()->Branch(not_zero, &operand, not_taken); 1190 deferred->enter()->Branch(not_zero, &operand, not_taken);
1195 Result answer = allocator()->Allocate(); 1191 Result answer = allocator()->Allocate();
1196 ASSERT(answer.is_valid()); 1192 ASSERT(answer.is_valid());
1197 __ mov(answer.reg(), Operand(operand.reg())); 1193 __ mov(answer.reg(), Operand(operand.reg()));
1198 ASSERT(kSmiTag == 0); // adjust code if not the case 1194 ASSERT(kSmiTag == 0); // adjust code if not the case
1199 // We do no shifts, only the Smi conversion, if shift_value is 1. 1195 // We do no shifts, only the Smi conversion, if shift_value is 1.
1200 if (shift_value == 0) { 1196 if (shift_value == 0) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 Result right_side(this); 1299 Result right_side(this);
1304 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 1300 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1305 if (cc == greater || cc == less_equal) { 1301 if (cc == greater || cc == less_equal) {
1306 cc = ReverseCondition(cc); 1302 cc = ReverseCondition(cc);
1307 left_side = frame_->Pop(); 1303 left_side = frame_->Pop();
1308 right_side = frame_->Pop(); 1304 right_side = frame_->Pop();
1309 } else { 1305 } else {
1310 right_side = frame_->Pop(); 1306 right_side = frame_->Pop();
1311 left_side = frame_->Pop(); 1307 left_side = frame_->Pop();
1312 } 1308 }
1309 ASSERT(cc == less || cc == equal || cc == greater_equal);
1310
1313 // If either side is a constant smi, optimize the comparison. 1311 // If either side is a constant smi, optimize the comparison.
1314 bool left_side_constant_smi = 1312 bool left_side_constant_smi =
1315 left_side.is_constant() && left_side.handle()->IsSmi(); 1313 left_side.is_constant() && left_side.handle()->IsSmi();
1316 bool right_side_constant_smi = 1314 bool right_side_constant_smi =
1317 right_side.is_constant() && right_side.handle()->IsSmi(); 1315 right_side.is_constant() && right_side.handle()->IsSmi();
1318 bool left_side_constant_null = 1316 bool left_side_constant_null =
1319 left_side.is_constant() && left_side.handle()->IsNull(); 1317 left_side.is_constant() && left_side.handle()->IsNull();
1320 bool right_side_constant_null = 1318 bool right_side_constant_null =
1321 right_side.is_constant() && right_side.handle()->IsNull(); 1319 right_side.is_constant() && right_side.handle()->IsNull();
1322 1320
1323 if (left_side_constant_smi || right_side_constant_smi) { 1321 if (left_side_constant_smi || right_side_constant_smi) {
1324 if (left_side_constant_smi && right_side_constant_smi) { 1322 if (left_side_constant_smi && right_side_constant_smi) {
1325 // Trivial case, comparing two constants. 1323 // Trivial case, comparing two constants.
1326 int left_value = Smi::cast(*left_side.handle())->value(); 1324 int left_value = Smi::cast(*left_side.handle())->value();
1327 int right_value = Smi::cast(*right_side.handle())->value(); 1325 int right_value = Smi::cast(*right_side.handle())->value();
1328 if (left_value < right_value && 1326 switch (cc) {
1329 (cc == less || cc == less_equal || cc == not_equal) || 1327 case less:
1330 left_value == right_value && 1328 dest->Goto(left_value < right_value);
1331 (cc == less_equal || cc == equal || cc == greater_equal) || 1329 break;
1332 left_value > right_value && 1330 case equal:
1333 (cc == greater || cc == greater_equal || cc == not_equal)) { 1331 dest->Goto(left_value == right_value);
1334 // The comparison is unconditionally true. 1332 break;
1335 dest->Goto(true); 1333 case greater_equal:
1336 } else { 1334 dest->Goto(left_value >= right_value);
1337 // The comparison is unconditionally false. 1335 break;
1338 dest->Goto(false); 1336 default:
1337 UNREACHABLE();
1339 } 1338 }
1340 } else { // Only one side is a constant Smi. 1339 } else { // Only one side is a constant Smi.
1341 // If left side is a constant Smi, reverse the operands. 1340 // If left side is a constant Smi, reverse the operands.
1342 // Since one side is a constant Smi, conversion order does not matter. 1341 // Since one side is a constant Smi, conversion order does not matter.
1343 if (left_side_constant_smi) { 1342 if (left_side_constant_smi) {
1344 Result temp = left_side; 1343 Result temp = left_side;
1345 left_side = right_side; 1344 left_side = right_side;
1346 right_side = temp; 1345 right_side = temp;
1347 cc = ReverseCondition(cc); 1346 cc = ReverseCondition(cc);
1348 // This may reintroduce greater or less_equal as the value of cc. 1347 // This may reintroduce greater or less_equal as the value of cc.
(...skipping 20 matching lines...) Expand all
1369 dest->false_target()->Jump(); 1368 dest->false_target()->Jump();
1370 1369
1371 is_smi.Bind(&left_side, &right_side); 1370 is_smi.Bind(&left_side, &right_side);
1372 left_side.ToRegister(); 1371 left_side.ToRegister();
1373 // Test smi equality and comparison by signed int comparison. 1372 // Test smi equality and comparison by signed int comparison.
1374 if (IsUnsafeSmi(right_side.handle())) { 1373 if (IsUnsafeSmi(right_side.handle())) {
1375 right_side.ToRegister(); 1374 right_side.ToRegister();
1376 ASSERT(right_side.is_valid()); 1375 ASSERT(right_side.is_valid());
1377 __ cmp(left_side.reg(), Operand(right_side.reg())); 1376 __ cmp(left_side.reg(), Operand(right_side.reg()));
1378 } else { 1377 } else {
1379 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); 1378 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
1380 } 1379 }
1381 left_side.Unuse(); 1380 left_side.Unuse();
1382 right_side.Unuse(); 1381 right_side.Unuse();
1383 dest->Split(cc); 1382 dest->Split(cc);
1384 } 1383 }
1385 } else if (cc == equal && 1384 } else if (cc == equal &&
1386 (left_side_constant_null || right_side_constant_null)) { 1385 (left_side_constant_null || right_side_constant_null)) {
1387 // To make null checks efficient, we check if either the left side or 1386 // To make null checks efficient, we check if either the left side or
1388 // the right side is the constant 'null'. 1387 // the right side is the constant 'null'.
1389 // If so, we optimize the code by inlining a null check instead of 1388 // If so, we optimize the code by inlining a null check instead of
(...skipping 24 matching lines...) Expand all
1414 __ movzx_b(temp.reg(), 1413 __ movzx_b(temp.reg(),
1415 FieldOperand(temp.reg(), Map::kBitFieldOffset)); 1414 FieldOperand(temp.reg(), Map::kBitFieldOffset));
1416 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); 1415 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
1417 temp.Unuse(); 1416 temp.Unuse();
1418 operand.Unuse(); 1417 operand.Unuse();
1419 dest->Split(not_zero); 1418 dest->Split(not_zero);
1420 } 1419 }
1421 } else { // Neither side is a constant Smi or null. 1420 } else { // Neither side is a constant Smi or null.
1422 // If either side is a non-smi constant, skip the smi check. 1421 // If either side is a non-smi constant, skip the smi check.
1423 bool known_non_smi = 1422 bool known_non_smi =
1424 left_side.is_constant() && !left_side.handle()->IsSmi() || 1423 (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
1425 right_side.is_constant() && !right_side.handle()->IsSmi(); 1424 (right_side.is_constant() && !right_side.handle()->IsSmi());
1426 left_side.ToRegister(); 1425 left_side.ToRegister();
1427 right_side.ToRegister(); 1426 right_side.ToRegister();
1428 JumpTarget is_smi(this); 1427 JumpTarget is_smi(this);
1429 if (!known_non_smi) { 1428 if (!known_non_smi) {
1430 // Check for the smi case. 1429 // Check for the smi case.
1431 Result temp = allocator_->Allocate(); 1430 Result temp = allocator_->Allocate();
1432 ASSERT(temp.is_valid()); 1431 ASSERT(temp.is_valid());
1433 __ mov(temp.reg(), left_side.reg()); 1432 __ mov(temp.reg(), left_side.reg());
1434 __ or_(temp.reg(), Operand(right_side.reg())); 1433 __ or_(temp.reg(), Operand(right_side.reg()));
1435 __ test(temp.reg(), Immediate(kSmiTagMask)); 1434 __ test(temp.reg(), Immediate(kSmiTagMask));
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
1863 Result context(this); 1862 Result context(this);
1864 if (node->is_catch_block()) { 1863 if (node->is_catch_block()) {
1865 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); 1864 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1);
1866 } else { 1865 } else {
1867 context = frame_->CallRuntime(Runtime::kPushContext, 1); 1866 context = frame_->CallRuntime(Runtime::kPushContext, 1);
1868 } 1867 }
1869 1868
1870 // Update context local. 1869 // Update context local.
1871 frame_->SaveContextRegister(); 1870 frame_->SaveContextRegister();
1872 1871
1873 if (kDebug) { 1872 // Verify that the runtime call result and esi agree.
1874 JumpTarget verified_true(this); 1873 if (FLAG_debug_code) {
1875 // Verify that the result of the runtime call and the esi register are
1876 // the same in debug mode.
1877 __ cmp(context.reg(), Operand(esi)); 1874 __ cmp(context.reg(), Operand(esi));
1878 context.Unuse(); 1875 __ Assert(equal, "Runtime::NewContext should end up in esi");
1879 verified_true.Branch(equal);
1880 frame_->SpillAll();
1881 __ int3();
1882 verified_true.Bind();
1883 } 1876 }
1884 } 1877 }
1885 1878
1886 1879
1887 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { 1880 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
1888 ASSERT(!in_spilled_code()); 1881 ASSERT(!in_spilled_code());
1889 Comment cmnt(masm_, "[ WithExitStatement"); 1882 Comment cmnt(masm_, "[ WithExitStatement");
1890 CodeForStatementPosition(node); 1883 CodeForStatementPosition(node);
1891 // Pop context. 1884 // Pop context.
1892 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); 1885 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
2024 } 2017 }
2025 2018
2026 2019
2027 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { 2020 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
2028 ASSERT(!in_spilled_code()); 2021 ASSERT(!in_spilled_code());
2029 Comment cmnt(masm_, "[ SwitchStatement"); 2022 Comment cmnt(masm_, "[ SwitchStatement");
2030 CodeForStatementPosition(node); 2023 CodeForStatementPosition(node);
2031 node->set_break_stack_height(break_stack_height_); 2024 node->set_break_stack_height(break_stack_height_);
2032 node->break_target()->Initialize(this); 2025 node->break_target()->Initialize(this);
2033 2026
2027 // Compile the switch value.
2034 Load(node->tag()); 2028 Load(node->tag());
2029
2035 if (TryGenerateFastCaseSwitchStatement(node)) { 2030 if (TryGenerateFastCaseSwitchStatement(node)) {
2036 return; 2031 return;
2037 } 2032 }
2038 2033
2039 JumpTarget next_test(this);
2040 JumpTarget fall_through(this);
2041 JumpTarget default_entry(this);
2042 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL);
2043 ZoneList<CaseClause*>* cases = node->cases(); 2034 ZoneList<CaseClause*>* cases = node->cases();
2044 int length = cases->length(); 2035 int length = cases->length();
2045 CaseClause* default_clause = NULL; 2036 CaseClause* default_clause = NULL;
2046 2037
2047 // Loop over the cases, compiling tests and bodies. Skip the 2038 JumpTarget next_test(this);
2048 // default if found and compile it at the end. Exit early if an 2039 // Compile the case label expressions and comparisons. Exit early
2049 // unconditionally true match occurs (which can happen, eg, in the 2040 // if a comparison is unconditionally true. The target next_test is
2050 // event the switch value is a compile-time constant). 2041 // bound before the loop in order to indicate control flow to the
2051 // 2042 // first comparison.
2052 // Bind the next_test target before entering the loop so we can use
2053 // its state to detect whether the switch value needs to be dropped
2054 // from the frame.
2055 next_test.Bind(); 2043 next_test.Bind();
2056 int index = 0; 2044 for (int i = 0; i < length && !next_test.is_unused(); i++) {
2057 for (; index < length; index++) { 2045 CaseClause* clause = cases->at(i);
2058 CaseClause* clause = cases->at(index); 2046 clause->body_target()->Initialize(this);
2047 // The default is not a test, but remember it for later.
2059 if (clause->is_default()) { 2048 if (clause->is_default()) {
2060 // Remember the default clause and compile it at the end.
2061 default_clause = clause; 2049 default_clause = clause;
2062 continue; 2050 continue;
2063 } 2051 }
2064 2052
2065 // Compile each non-default clause. 2053 Comment cmnt(masm_, "[ Case comparison");
2066 Comment cmnt(masm_, "[ Case clause"); 2054 // We recycle the same target next_test for each test. Bind it if
2067 // Recycle the same target for each test. 2055 // the previous test has not done so and then unuse it for the
2068 if (!next_test.is_unused()) { 2056 // loop.
2069 // The next test target may be linked (as the target of a 2057 if (next_test.is_linked()) {
2070 // previous match failure) or bound (if the previous comparison 2058 next_test.Bind();
2071 // was unconditionally false or this is the first non-default
2072 // comparison).
2073 if (next_test.is_linked()) {
2074 next_test.Bind();
2075 }
2076 next_test.Unuse();
2077 } 2059 }
2060 next_test.Unuse();
2078 2061
2079 // Duplicate the switch value. 2062 // Duplicate the switch value.
2080 frame_->Dup(); 2063 frame_->Dup();
2081 2064
2082 // Compile the clause's label expression. 2065 // Compile the label expression.
2083 Load(clause->label()); 2066 Load(clause->label());
2084 2067
2085 // Compare and branch to the body if true and to the next test if 2068 // Compare and branch to the body if true or the next test if
2086 // false. 2069 // false. Prefer the next test as a fall through.
2087 JumpTarget enter_body(this); 2070 ControlDestination dest(clause->body_target(), &next_test, false);
2088 ControlDestination dest(&enter_body, &next_test, true);
2089 Comparison(equal, true, &dest); 2071 Comparison(equal, true, &dest);
2090 2072
2091 bool previous_was_default = 2073 // If the comparison fell through to the true target, jump to the
2092 index > 0 && cases->at(index - 1)->is_default(); 2074 // actual body.
2093 if (dest.false_was_fall_through()) { 2075 if (dest.true_was_fall_through()) {
2094 // The false target next_test was bound as the fall-through. 2076 clause->body_target()->Unuse();
2095 // This may indicate that the comparison was unconditionally 2077 clause->body_target()->Jump();
2096 // false if there are no dangling jumps to enter_body. Even
2097 // then we may still need to compile the body if it is reachable
2098 // as a fall through.
2099
2100 // We do not need to compile the body if control cannot reach
2101 // it. Control could reach the body (1) from the comparison by
2102 // a branch to enter_body, (2) as the fall through of some
2103 // previous case, or (3) possibly via a backward jump from the
2104 // default.
2105 if (!enter_body.is_linked() &&
2106 !fall_through.is_linked() &&
2107 !previous_was_default) {
2108 continue;
2109 }
2110
2111 // We will compile the body and we have to jump around it on
2112 // this path where the comparison failed.
2113 next_test.Unuse();
2114 next_test.Jump();
2115 if (enter_body.is_linked()) {
2116 enter_body.Bind();
2117 }
2118 }
2119
2120 // The body entry target may have been bound, indicating control
2121 // flow can reach the body via the comparison.
2122 if (enter_body.is_bound()) {
2123 // The switch value is no longer needed.
2124 frame_->Drop();
2125 } else {
2126 // The test was unconditionally false but we will compile the
2127 // body as a fall through.
2128 ASSERT(!has_valid_frame());
2129 }
2130
2131 // Label the body if needed for fall through.
2132 if (previous_was_default) {
2133 // Because the default is compiled last, there is always a potential
2134 // backwards edge to here, falling through from the default.
2135 default_exit.Bind();
2136 } else {
2137 // Recycle the same target for each fall through.
2138 fall_through.Bind();
2139 fall_through.Unuse();
2140 }
2141
2142 // Compile the body.
2143 ASSERT(has_valid_frame());
2144 { Comment body_cmnt(masm_, "[ Case body");
2145 VisitStatements(clause->statements());
2146 }
2147
2148 // The test may have been unconditionally true, which is indicated
2149 // by the absence of any control flow to the next_test target. In
2150 // that case, exit this loop and stop compiling both tests and
2151 // bodies (and begin compiling only bodies if necessary).
2152
2153 // Otherwise, if control flow can fall off the end of the body
2154 // jump to the body of the next case as fall through unless this
2155 // is the last non-default case.
2156 if (!next_test.is_linked()) {
2157 index++;
2158 break;
2159 } else if (has_valid_frame()) {
2160 if (index < length - 2 && // There are at least two cases after this
2161 cases->at(index + 1)->is_default()) { // The next is the default.
2162 default_entry.Jump();
2163 } else if (index < length - 1) { // This is not the last case.
2164 fall_through.Jump();
2165 }
2166 } 2078 }
2167 } 2079 }
2168 2080
2169 // If we did not compile all the cases then we must have hit one 2081 // If there was control flow to a next test from the last one
2170 // that was unconditionally true. We do not need to compile any 2082 // compiled, compile a jump to the default or break target.
2171 // more tests but we may have (and continue to have) fall through. 2083 if (!next_test.is_unused()) {
2172 for (; index < length && has_valid_frame(); index++) {
2173 Comment cmnt(masm_, "[ Case fall-through");
2174 VisitStatements(cases->at(index)->statements());
2175 }
2176
2177 // Complete the switch statement based on the compilation state of
2178 // the last case that was compiled.
2179 if (next_test.is_unused()) {
2180 // The last test compiled was unconditionally true. We still need
2181 // to compile the default if we found one and it can be targeted
2182 // by fall through.
2183 if (default_clause != NULL) {
2184 bool was_only_clause = length == 1 && cases->at(0) == default_clause;
2185 if (was_only_clause || default_entry.is_linked()) {
2186 Comment cmnt(masm_, "[ Default clause");
2187 default_entry.Bind();
2188 VisitStatements(default_clause->statements());
2189 // If control flow can fall off the end of the default and there
2190 // was a case after it, jump to that case's body.
2191 if (has_valid_frame() && default_exit.is_bound()) {
2192 default_exit.Jump();
2193 }
2194 }
2195 }
2196 } else {
2197 // The switch value is still on the frame. We have to drop it and
2198 // possibly compile a default case.
2199 if (next_test.is_linked()) { 2084 if (next_test.is_linked()) {
2200 if (has_valid_frame()) {
2201 // We have fall through and thus need to jump around the code
2202 // to drop the switch value.
2203 fall_through.Jump();
2204 }
2205 next_test.Bind(); 2085 next_test.Bind();
2206 } 2086 }
2087 // Drop the switch value.
2207 frame_->Drop(); 2088 frame_->Drop();
2208
2209 // If there was a default clause, compile it now.
2210 if (default_clause != NULL) { 2089 if (default_clause != NULL) {
2211 Comment cmnt(masm_, "[ Default clause"); 2090 default_clause->body_target()->Jump();
2212 if (default_entry.is_linked()) { 2091 } else {
2213 default_entry.Bind(); 2092 node->break_target()->Jump();
2214 }
2215 VisitStatements(default_clause->statements());
2216 // If control flow can fall off the end of the default and there
2217 // was a case after it, jump to that case's body.
2218 if (has_valid_frame() && default_exit.is_bound()) {
2219 default_exit.Jump();
2220 }
2221 } 2093 }
2222 } 2094 }
2223 2095
2224 if (fall_through.is_linked()) { 2096
2225 fall_through.Bind(); 2097 // The last instruction emitted was a jump, either to the default
2098 // clause or the break target, or else to a case body from the loop
2099 // that compiles the tests.
2100 ASSERT(!has_valid_frame());
2101 // Compile case bodies as needed.
2102 for (int i = 0; i < length; i++) {
2103 CaseClause* clause = cases->at(i);
2104
2105 // There are two ways to reach the body: from the corresponding
2106 // test or as the fall through of the previous body.
2107 if (!clause->body_target()->is_linked() && !has_valid_frame()) {
2108 // If we have neither, skip this body.
2109 continue;
2110 } else if (clause->body_target()->is_linked() && has_valid_frame()) {
2111 // If we have both, put a jump on the fall through path to avoid
2112 // the dropping of the switch value on the test path. The
2113 // exception is the default which has already had the switch
2114 // value dropped.
2115 if (clause->is_default()) {
2116 clause->body_target()->Bind();
2117 } else {
2118 JumpTarget body(this);
2119 body.Jump();
2120 clause->body_target()->Bind();
2121 frame_->Drop();
2122 body.Bind();
2123 }
2124 } else if (clause->body_target()->is_linked()) {
2125 // No fall through to worry about.
2126 clause->body_target()->Bind();
2127 if (!clause->is_default()) {
2128 frame_->Drop();
2129 }
2130 } else {
2131 // Otherwise, we have only fall through.
2132 ASSERT(has_valid_frame());
2133 }
2134
2135 // We are now prepared to compile the body.
2136 Comment cmnt(masm_, "[ Case body");
2137 VisitStatements(clause->statements());
2226 } 2138 }
2139
2140 // We may not have a valid frame here so bind the break target only
2141 // if needed.
2227 if (node->break_target()->is_linked()) { 2142 if (node->break_target()->is_linked()) {
2228 node->break_target()->Bind(); 2143 node->break_target()->Bind();
2229 } 2144 }
2230 } 2145 }
2231 2146
2232 2147
2233 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { 2148 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
2234 ASSERT(!in_spilled_code()); 2149 ASSERT(!in_spilled_code());
2235 Comment cmnt(masm_, "[ LoopStatement"); 2150 Comment cmnt(masm_, "[ LoopStatement");
2236 CodeForStatementPosition(node); 2151 CodeForStatementPosition(node);
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
2908 } else { 2823 } else {
2909 // Fake TOS for targets that shadowed breaks and continues. 2824 // Fake TOS for targets that shadowed breaks and continues.
2910 frame_->EmitPush(Immediate(Factory::undefined_value())); 2825 frame_->EmitPush(Immediate(Factory::undefined_value()));
2911 } 2826 }
2912 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); 2827 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
2913 unlink.Jump(); 2828 unlink.Jump();
2914 } 2829 }
2915 } 2830 }
2916 2831
2917 // Unlink from try chain; be careful not to destroy the TOS. 2832 // Unlink from try chain; be careful not to destroy the TOS.
2918 unlink.Bind(); 2833 if (unlink.is_linked()) {
2919 // Reload sp from the top handler, because some statements that we 2834 unlink.Bind();
2920 // break from (eg, for...in) may have left stuff on the stack. 2835 }
2921 // Preserve the TOS in a register across stack manipulation.
2922 frame_->EmitPop(eax);
2923 ExternalReference handler_address(Top::k_handler_address);
2924 __ mov(edx, Operand::StaticVariable(handler_address));
2925 const int kNextOffset = StackHandlerConstants::kNextOffset +
2926 StackHandlerConstants::kAddressDisplacement;
2927 __ lea(esp, Operand(edx, kNextOffset));
2928 frame_->Forget(frame_->height() - handler_height);
2929 2836
2930 frame_->EmitPop(Operand::StaticVariable(handler_address)); 2837 // Control can reach here via a jump to unlink or by falling off the
2931 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2838 // end of the try block (with no unlinks).
2932 // Next_sp popped. 2839 if (has_valid_frame()) {
2933 frame_->EmitPush(eax); 2840 // Reload sp from the top handler, because some statements that we
2841 // break from (eg, for...in) may have left stuff on the stack.
2842 // Preserve the TOS in a register across stack manipulation.
2843 frame_->EmitPop(eax);
2844 ExternalReference handler_address(Top::k_handler_address);
2845 __ mov(edx, Operand::StaticVariable(handler_address));
2846 const int kNextOffset = StackHandlerConstants::kNextOffset +
2847 StackHandlerConstants::kAddressDisplacement;
2848 __ lea(esp, Operand(edx, kNextOffset));
2849 frame_->Forget(frame_->height() - handler_height);
2850
2851 frame_->EmitPop(Operand::StaticVariable(handler_address));
2852 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2853 // Next_sp popped.
2854 frame_->EmitPush(eax);
2855 }
2934 2856
2935 // --- Finally block --- 2857 // --- Finally block ---
2936 finally_block.Bind(); 2858 finally_block.Bind();
2937 2859
2938 // Push the state on the stack. 2860 // Push the state on the stack.
2939 frame_->EmitPush(ecx); 2861 frame_->EmitPush(ecx);
2940 2862
2941 // We keep two elements on the stack - the (possibly faked) result 2863 // We keep two elements on the stack - the (possibly faked) result
2942 // and the state - while evaluating the finally block. Record it, so 2864 // and the state - while evaluating the finally block. Record it, so
2943 // that a break/continue crossing this statement can restore the 2865 // that a break/continue crossing this statement can restore the
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
3510 frame_->Push(&boilerplate); 3432 frame_->Push(&boilerplate);
3511 // Clone the boilerplate object. 3433 // Clone the boilerplate object.
3512 Result clone = 3434 Result clone =
3513 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); 3435 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
3514 // Push the newly cloned literal object as the result. 3436 // Push the newly cloned literal object as the result.
3515 frame_->Push(&clone); 3437 frame_->Push(&clone);
3516 3438
3517 for (int i = 0; i < node->properties()->length(); i++) { 3439 for (int i = 0; i < node->properties()->length(); i++) {
3518 ObjectLiteral::Property* property = node->properties()->at(i); 3440 ObjectLiteral::Property* property = node->properties()->at(i);
3519 switch (property->kind()) { 3441 switch (property->kind()) {
3520 case ObjectLiteral::Property::CONSTANT: break; 3442 case ObjectLiteral::Property::CONSTANT:
3443 break;
3444 case ObjectLiteral::Property::OBJECT_LITERAL:
3445 if (property->value()->AsObjectLiteral()->is_simple()) break;
3521 case ObjectLiteral::Property::COMPUTED: { 3446 case ObjectLiteral::Property::COMPUTED: {
3522 Handle<Object> key(property->key()->handle()); 3447 Handle<Object> key(property->key()->handle());
3523 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 3448 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3524 if (key->IsSymbol()) { 3449 if (key->IsSymbol()) {
3525 // Duplicate the object as the IC receiver. 3450 // Duplicate the object as the IC receiver.
3526 frame_->Dup(); 3451 frame_->Dup();
3527 Load(property->value()); 3452 Load(property->value());
3528 Result value = frame_->Pop(); 3453 Result value = frame_->Pop();
3529 value.ToRegister(eax); 3454 value.ToRegister(eax);
3530 3455
(...skipping 3370 matching lines...) Expand 10 before | Expand all | Expand 10 after
6901 6826
6902 // Slow-case: Go through the JavaScript implementation. 6827 // Slow-case: Go through the JavaScript implementation.
6903 __ bind(&slow); 6828 __ bind(&slow);
6904 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6829 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6905 } 6830 }
6906 6831
6907 6832
6908 #undef __ 6833 #undef __
6909 6834
6910 } } // namespace v8::internal 6835 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.cc ('k') | src/compilation-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698