OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
772 case Token::SHL: return "GenericBinaryOpStub_SHL"; | 772 case Token::SHL: return "GenericBinaryOpStub_SHL"; |
773 case Token::SHR: return "GenericBinaryOpStub_SHR"; | 773 case Token::SHR: return "GenericBinaryOpStub_SHR"; |
774 default: return "GenericBinaryOpStub"; | 774 default: return "GenericBinaryOpStub"; |
775 } | 775 } |
776 } | 776 } |
777 | 777 |
778 | 778 |
779 // Call the specialized stub for a binary operation. | 779 // Call the specialized stub for a binary operation. |
780 class DeferredInlineBinaryOperation: public DeferredCode { | 780 class DeferredInlineBinaryOperation: public DeferredCode { |
781 public: | 781 public: |
782 DeferredInlineBinaryOperation(Token::Value op, | 782 DeferredInlineBinaryOperation(Token::Value op, OverwriteMode mode) |
783 OverwriteMode mode) | |
784 : op_(op), mode_(mode) { | 783 : op_(op), mode_(mode) { |
785 set_comment("[ DeferredInlineBinaryOperation"); | 784 set_comment("[ DeferredInlineBinaryOperation"); |
786 } | 785 } |
787 | 786 |
788 virtual void Generate(); | 787 virtual void Generate(); |
789 | 788 |
790 private: | 789 private: |
791 Token::Value op_; | 790 Token::Value op_; |
792 OverwriteMode mode_; | 791 OverwriteMode mode_; |
793 }; | 792 }; |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
994 } | 993 } |
995 frame_->Push(Handle<Object>(answer_object)); | 994 frame_->Push(Handle<Object>(answer_object)); |
996 return true; | 995 return true; |
997 } | 996 } |
998 | 997 |
999 | 998 |
1000 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 999 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
1001 Result* left, | 1000 Result* left, |
1002 Result* right, | 1001 Result* right, |
1003 OverwriteMode overwrite_mode) { | 1002 OverwriteMode overwrite_mode) { |
1004 // Implements a binary operation using a deferred code object and | 1003 // Implements a binary operation using a deferred code object and some |
1005 // some inline code to operate on smis quickly. | 1004 // inline code to operate on smis quickly. |
1006 DeferredInlineBinaryOperation* deferred = | 1005 DeferredInlineBinaryOperation* deferred = |
1007 new DeferredInlineBinaryOperation(op, overwrite_mode); | 1006 new DeferredInlineBinaryOperation(op, overwrite_mode); |
1008 | 1007 |
1009 // Special handling of div and mod because they use fixed registers. | 1008 // Special handling of div and mod because they use fixed registers. |
1010 if (op == Token::DIV || op == Token::MOD) { | 1009 if (op == Token::DIV || op == Token::MOD) { |
1011 // We need eax as the quotient register, edx as the remainder | 1010 // We need eax as the quotient register, edx as the remainder |
1012 // register, neither left nor right in eax or edx, and left copied | 1011 // register, neither left nor right in eax or edx, and left copied |
1013 // to eax. | 1012 // to eax. |
1014 Result quotient; | 1013 Result quotient; |
1015 Result remainder; | 1014 Result remainder; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1141 deferred->enter()->Branch(negative, left, right); | 1140 deferred->enter()->Branch(negative, left, right); |
1142 left->Unuse(); | 1141 left->Unuse(); |
1143 right->Unuse(); | 1142 right->Unuse(); |
1144 __ bind(&non_zero_result); | 1143 __ bind(&non_zero_result); |
1145 deferred->BindExit(&remainder); | 1144 deferred->BindExit(&remainder); |
1146 frame_->Push(&remainder); | 1145 frame_->Push(&remainder); |
1147 } | 1146 } |
1148 return; | 1147 return; |
1149 } | 1148 } |
1150 | 1149 |
1150 // Special handling of shift operations because they use fixed | |
1151 // registers. | |
1152 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { | |
1153 // Move left out of ecx if necessary. | |
1154 if (left->is_register() && left->reg().is(ecx)) { | |
1155 *left = allocator_->Allocate(); | |
1156 ASSERT(left->is_valid()); | |
1157 __ mov(left->reg(), ecx); | |
1158 } | |
1159 right->ToRegister(ecx); | |
1160 left->ToRegister(); | |
1161 ASSERT(left->is_register() && !left->reg().is(ecx)); | |
1162 ASSERT(right->is_register() && right->reg().is(ecx)); | |
1163 | |
1164 // We will modify right, it must be spilled. | |
1165 frame_->Spill(ecx); | |
1166 | |
1167 // Use a fresh answer register to avoid spilling the left operand. | |
1168 Result answer = allocator_->Allocate(); | |
1169 ASSERT(answer.is_valid()); | |
1170 // Check that both operands are smis using the answer register as a | |
1171 // temporary. | |
1172 __ mov(answer.reg(), left->reg()); | |
1173 __ or_(answer.reg(), Operand(ecx)); | |
1174 __ test(answer.reg(), Immediate(kSmiTagMask)); | |
1175 deferred->enter()->Branch(not_zero, left, right); | |
1176 | |
1177 // Untag both operands. | |
1178 __ mov(answer.reg(), left->reg()); | |
1179 __ sar(answer.reg(), kSmiTagSize); | |
1180 __ sar(ecx, kSmiTagSize); | |
1181 // Perform the operation. | |
1182 switch (op) { | |
1183 case Token::SAR: | |
1184 __ sar(answer.reg()); | |
1185 // No checks of result necessary | |
1186 break; | |
1187 case Token::SHR: { | |
1188 JumpTarget result_ok; | |
1189 __ shr(answer.reg()); | |
1190 // Check that the *unsigned* result fits in a smi. | |
1191 // Neither of the two high-order bits can be set: | |
1192 // - 0x80000000: high bit would be lost when smi tagging. | |
1193 // - 0x40000000: this number would convert to negative when | |
1194 // Smi tagging these two cases can only happen with shifts | |
William Hesse
2009/06/03 12:12:04
// Smi tagging. These two cases can..
| |
1195 // by 0 or 1 when handed a valid smi. | |
1196 // If the answer cannot be represented by a smi, restore | |
1197 // the left and right arguments, and jump to slow case. | |
1198 // The low bit of the left argument may be lost, but only | |
1199 // in a case where it is dropped anyway. | |
1200 __ test(answer.reg(), Immediate(0xc0000000)); | |
1201 result_ok.Branch(zero, &answer); | |
1202 ASSERT(kSmiTag == 0); | |
1203 __ shl(ecx, kSmiTagSize); | |
1204 answer.Unuse(); | |
1205 deferred->enter()->Jump(left, right); | |
1206 result_ok.Bind(&answer); | |
1207 break; | |
1208 } | |
1209 case Token::SHL: { | |
1210 JumpTarget result_ok; | |
1211 __ shl(answer.reg()); | |
1212 // Check that the *signed* result fits in a smi. | |
1213 __ cmp(answer.reg(), 0xc0000000); | |
1214 result_ok.Branch(positive, &answer); | |
1215 ASSERT(kSmiTag == 0); | |
1216 __ shl(ecx, kSmiTagSize); | |
1217 answer.Unuse(); | |
1218 deferred->enter()->Jump(left, right); | |
1219 result_ok.Bind(&answer); | |
1220 break; | |
1221 } | |
1222 default: | |
1223 UNREACHABLE(); | |
1224 } | |
1225 left->Unuse(); | |
1226 right->Unuse(); | |
1227 // Smi-tag the result in answer. | |
1228 ASSERT(kSmiTagSize == 1); // Adjust code if not the case. | |
1229 __ lea(answer.reg(), | |
1230 Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); | |
1231 deferred->BindExit(&answer); | |
1232 frame_->Push(&answer); | |
1233 return; | |
1234 } | |
1235 | |
1151 // Handle the other binary operations. | 1236 // Handle the other binary operations. |
1152 left->ToRegister(); | 1237 left->ToRegister(); |
1153 right->ToRegister(); | 1238 right->ToRegister(); |
1154 // A newly allocated register answer is used to hold the answer. The | 1239 // A newly allocated register answer is used to hold the answer. The |
1155 // registers containing left and right are not modified in most cases, | 1240 // registers containing left and right are not modified so they don't |
1156 // so they usually don't need to be spilled in the fast case. | 1241 // need to be spilled in the fast case. |
1157 Result answer = allocator_->Allocate(); | 1242 Result answer = allocator_->Allocate(); |
1158 | 1243 |
1159 ASSERT(answer.is_valid()); | 1244 ASSERT(answer.is_valid()); |
1160 // Perform the smi tag check. | 1245 // Perform the smi tag check. |
1161 if (left->reg().is(right->reg())) { | 1246 if (left->reg().is(right->reg())) { |
1162 __ test(left->reg(), Immediate(kSmiTagMask)); | 1247 __ test(left->reg(), Immediate(kSmiTagMask)); |
1163 } else { | 1248 } else { |
1164 __ mov(answer.reg(), left->reg()); | 1249 __ mov(answer.reg(), left->reg()); |
1165 __ or_(answer.reg(), Operand(right->reg())); | 1250 __ or_(answer.reg(), Operand(right->reg())); |
1166 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 1251 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1222 __ mov(answer.reg(), left->reg()); | 1307 __ mov(answer.reg(), left->reg()); |
1223 __ and_(answer.reg(), Operand(right->reg())); | 1308 __ and_(answer.reg(), Operand(right->reg())); |
1224 break; | 1309 break; |
1225 | 1310 |
1226 case Token::BIT_XOR: | 1311 case Token::BIT_XOR: |
1227 deferred->enter()->Branch(not_zero, left, right, not_taken); | 1312 deferred->enter()->Branch(not_zero, left, right, not_taken); |
1228 __ mov(answer.reg(), left->reg()); | 1313 __ mov(answer.reg(), left->reg()); |
1229 __ xor_(answer.reg(), Operand(right->reg())); | 1314 __ xor_(answer.reg(), Operand(right->reg())); |
1230 break; | 1315 break; |
1231 | 1316 |
1232 case Token::SHL: | |
1233 case Token::SHR: | |
1234 case Token::SAR: | |
1235 deferred->enter()->Branch(not_zero, left, right, not_taken); | |
1236 __ mov(answer.reg(), left->reg()); | |
1237 // Move right into ecx. | |
1238 // Left is in two registers already, so even if left or answer is ecx, | |
1239 // we can move right to it, and use the other one. | |
1240 // Right operand must be in register cl because x86 likes it that way. | |
1241 if (right->reg().is(ecx)) { | |
1242 // Right is already in the right place. Left may be in the | |
1243 // same register, which causes problems. Always use answer | |
1244 // instead of left, even if left is not ecx, since this avoids | |
1245 // spilling left. | |
1246 *left = answer; | |
1247 } else if (left->reg().is(ecx)) { | |
1248 frame_->Spill(left->reg()); | |
1249 __ mov(left->reg(), right->reg()); | |
1250 *right = *left; | |
1251 *left = answer; // Use copy of left in answer as left. | |
1252 } else if (answer.reg().is(ecx)) { | |
1253 __ mov(answer.reg(), right->reg()); | |
1254 *right = answer; | |
1255 } else { | |
1256 Result reg_ecx = allocator_->Allocate(ecx); | |
1257 ASSERT(reg_ecx.is_valid()); | |
1258 __ mov(ecx, right->reg()); | |
1259 *right = reg_ecx; | |
1260 // Answer and left both contain the left operand. Use answer, so | |
1261 // left is not spilled. | |
1262 *left = answer; | |
1263 } | |
1264 ASSERT(left->reg().is_valid()); | |
1265 ASSERT(!left->reg().is(ecx)); | |
1266 ASSERT(right->reg().is(ecx)); | |
1267 answer.Unuse(); // Answer may now be being used for left or right. | |
1268 // We will modify left and right, which we do not do in any other | |
1269 // binary operation. The exits to slow code need to restore the | |
1270 // original values of left and right, or at least values that give | |
1271 // the same answer. | |
1272 | |
1273 // We are modifying left and right. They must be spilled! | |
1274 frame_->Spill(left->reg()); | |
1275 frame_->Spill(right->reg()); | |
1276 | |
1277 // Remove tags from operands (but keep sign). | |
1278 __ sar(left->reg(), kSmiTagSize); | |
1279 __ sar(ecx, kSmiTagSize); | |
1280 // Perform the operation. | |
1281 switch (op) { | |
1282 case Token::SAR: | |
1283 __ sar(left->reg()); | |
1284 // No checks of result necessary | |
1285 break; | |
1286 case Token::SHR: { | |
1287 __ shr(left->reg()); | |
1288 // Check that the *unsigned* result fits in a smi. | |
1289 // Neither of the two high-order bits can be set: | |
1290 // - 0x80000000: high bit would be lost when smi tagging. | |
1291 // - 0x40000000: this number would convert to negative when | |
1292 // Smi tagging these two cases can only happen with shifts | |
1293 // by 0 or 1 when handed a valid smi. | |
1294 // If the answer cannot be represented by a SMI, restore | |
1295 // the left and right arguments, and jump to slow case. | |
1296 // The low bit of the left argument may be lost, but only | |
1297 // in a case where it is dropped anyway. | |
1298 JumpTarget result_ok; | |
1299 __ test(left->reg(), Immediate(0xc0000000)); | |
1300 result_ok.Branch(zero, left, taken); | |
1301 __ shl(left->reg()); | |
1302 ASSERT(kSmiTag == 0); | |
1303 __ shl(left->reg(), kSmiTagSize); | |
1304 __ shl(right->reg(), kSmiTagSize); | |
1305 deferred->enter()->Jump(left, right); | |
1306 result_ok.Bind(left); | |
1307 break; | |
1308 } | |
1309 case Token::SHL: { | |
1310 __ shl(left->reg()); | |
1311 // Check that the *signed* result fits in a smi. | |
1312 JumpTarget result_ok; | |
1313 __ cmp(left->reg(), 0xc0000000); | |
1314 result_ok.Branch(positive, left, taken); | |
1315 | |
1316 __ shr(left->reg()); | |
1317 ASSERT(kSmiTag == 0); | |
1318 __ shl(left->reg(), kSmiTagSize); | |
1319 __ shl(right->reg(), kSmiTagSize); | |
1320 deferred->enter()->Jump(left, right); | |
1321 result_ok.Bind(left); | |
1322 break; | |
1323 } | |
1324 default: | |
1325 UNREACHABLE(); | |
1326 } | |
1327 // Smi-tag the result, in left, and make answer an alias for left-> | |
1328 answer = *left; | |
1329 answer.ToRegister(); | |
1330 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | |
1331 __ lea(answer.reg(), | |
1332 Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); | |
1333 break; | |
1334 | |
1335 default: | 1317 default: |
1336 UNREACHABLE(); | 1318 UNREACHABLE(); |
1337 break; | 1319 break; |
1338 } | 1320 } |
1339 left->Unuse(); | 1321 left->Unuse(); |
1340 right->Unuse(); | 1322 right->Unuse(); |
1341 deferred->BindExit(&answer); | 1323 deferred->BindExit(&answer); |
1342 frame_->Push(&answer); | 1324 frame_->Push(&answer); |
1343 } | 1325 } |
1344 | 1326 |
(...skipping 5945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7290 | 7272 |
7291 // Slow-case: Go through the JavaScript implementation. | 7273 // Slow-case: Go through the JavaScript implementation. |
7292 __ bind(&slow); | 7274 __ bind(&slow); |
7293 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7275 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7294 } | 7276 } |
7295 | 7277 |
7296 | 7278 |
7297 #undef __ | 7279 #undef __ |
7298 | 7280 |
7299 } } // namespace v8::internal | 7281 } } // namespace v8::internal |
OLD | NEW |