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 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 compiler::Node* value = assembler->Parameter(0); | 494 compiler::Node* value = assembler->Parameter(0); |
495 compiler::Node* string = | 495 compiler::Node* string = |
496 assembler->LoadObjectField(value, JSValue::kValueOffset); | 496 assembler->LoadObjectField(value, JSValue::kValueOffset); |
497 compiler::Node* result = | 497 compiler::Node* result = |
498 assembler->LoadObjectField(string, String::kLengthOffset); | 498 assembler->LoadObjectField(string, String::kLengthOffset); |
499 assembler->Return(result); | 499 assembler->Return(result); |
500 } | 500 } |
501 | 501 |
502 namespace { | 502 namespace { |
503 | 503 |
504 enum AbstractRelationalComparisonMode { | 504 enum RelationalComparisonMode { |
505 kLessThan, | 505 kLessThan, |
506 kLessThanOrEqual, | 506 kLessThanOrEqual, |
507 kGreaterThan, | 507 kGreaterThan, |
508 kGreaterThanOrEqual | 508 kGreaterThanOrEqual |
509 }; | 509 }; |
510 | 510 |
511 void GenerateAbstractRelationalComparison( | 511 void GenerateAbstractRelationalComparison( |
512 compiler::CodeStubAssembler* assembler, | 512 compiler::CodeStubAssembler* assembler, RelationalComparisonMode mode) { |
513 AbstractRelationalComparisonMode mode) { | |
514 typedef compiler::CodeStubAssembler::Label Label; | 513 typedef compiler::CodeStubAssembler::Label Label; |
515 typedef compiler::Node Node; | 514 typedef compiler::Node Node; |
516 typedef compiler::CodeStubAssembler::Variable Variable; | 515 typedef compiler::CodeStubAssembler::Variable Variable; |
517 | 516 |
518 Node* context = assembler->Parameter(2); | 517 Node* context = assembler->Parameter(2); |
519 | 518 |
520 Label return_true(assembler), return_false(assembler); | 519 Label return_true(assembler), return_false(assembler); |
521 | 520 |
522 // Shared entry for floating point comparison. | 521 // Shared entry for floating point comparison. |
523 Label do_fcmp(assembler); | 522 Label do_fcmp(assembler); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 Label if_rhsisstring(assembler), | 709 Label if_rhsisstring(assembler), |
711 if_rhsisnotstring(assembler, Label::kDeferred); | 710 if_rhsisnotstring(assembler, Label::kDeferred); |
712 assembler->Branch(assembler->Int32LessThan( | 711 assembler->Branch(assembler->Int32LessThan( |
713 rhs_instance_type, assembler->Int32Constant( | 712 rhs_instance_type, assembler->Int32Constant( |
714 FIRST_NONSTRING_TYPE)), | 713 FIRST_NONSTRING_TYPE)), |
715 &if_rhsisstring, &if_rhsisnotstring); | 714 &if_rhsisstring, &if_rhsisnotstring); |
716 | 715 |
717 assembler->Bind(&if_rhsisstring); | 716 assembler->Bind(&if_rhsisstring); |
718 { | 717 { |
719 // Both {lhs} and {rhs} are strings. | 718 // Both {lhs} and {rhs} are strings. |
720 // TODO(bmeurer): Hook up String<Compare>Stub once we have it. | |
721 switch (mode) { | 719 switch (mode) { |
722 case kLessThan: | 720 case kLessThan: |
723 assembler->TailCallRuntime(Runtime::kStringLessThan, context, | 721 assembler->TailCallStub( |
724 lhs, rhs); | 722 CodeFactory::StringLessThan(assembler->isolate()), |
| 723 context, lhs, rhs); |
725 break; | 724 break; |
726 case kLessThanOrEqual: | 725 case kLessThanOrEqual: |
727 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, | 726 assembler->TailCallStub( |
728 context, lhs, rhs); | 727 CodeFactory::StringLessThanOrEqual(assembler->isolate()), |
| 728 context, lhs, rhs); |
729 break; | 729 break; |
730 case kGreaterThan: | 730 case kGreaterThan: |
731 assembler->TailCallRuntime(Runtime::kStringGreaterThan, | 731 assembler->TailCallStub( |
732 context, lhs, rhs); | 732 CodeFactory::StringGreaterThan(assembler->isolate()), |
| 733 context, lhs, rhs); |
733 break; | 734 break; |
734 case kGreaterThanOrEqual: | 735 case kGreaterThanOrEqual: |
735 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, | 736 assembler->TailCallStub(CodeFactory::StringGreaterThanOrEqual( |
736 context, lhs, rhs); | 737 assembler->isolate()), |
| 738 context, lhs, rhs); |
737 break; | 739 break; |
738 } | 740 } |
739 } | 741 } |
740 | 742 |
741 assembler->Bind(&if_rhsisnotstring); | 743 assembler->Bind(&if_rhsisnotstring); |
742 { | 744 { |
743 // The {lhs} is a String, while {rhs} is neither a Number nor a | 745 // The {lhs} is a String, while {rhs} is neither a Number nor a |
744 // String, so we need to call ToPrimitive(rhs, hint Number) if | 746 // String, so we need to call ToPrimitive(rhs, hint Number) if |
745 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the | 747 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the |
746 // other cases. | 748 // other cases. |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1127 } | 1129 } |
1128 } | 1130 } |
1129 | 1131 |
1130 assembler->Bind(&if_equal); | 1132 assembler->Bind(&if_equal); |
1131 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); | 1133 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
1132 | 1134 |
1133 assembler->Bind(&if_notequal); | 1135 assembler->Bind(&if_notequal); |
1134 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); | 1136 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
1135 } | 1137 } |
1136 | 1138 |
| 1139 void GenerateStringRelationalComparison(compiler::CodeStubAssembler* assembler, |
| 1140 RelationalComparisonMode mode) { |
| 1141 typedef compiler::CodeStubAssembler::Label Label; |
| 1142 typedef compiler::Node Node; |
| 1143 typedef compiler::CodeStubAssembler::Variable Variable; |
| 1144 |
| 1145 Node* lhs = assembler->Parameter(0); |
| 1146 Node* rhs = assembler->Parameter(1); |
| 1147 Node* context = assembler->Parameter(2); |
| 1148 |
| 1149 Label if_less(assembler), if_equal(assembler), if_greater(assembler); |
| 1150 |
| 1151 // Fast check to see if {lhs} and {rhs} refer to the same String object. |
| 1152 Label if_same(assembler), if_notsame(assembler); |
| 1153 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 1154 |
| 1155 assembler->Bind(&if_same); |
| 1156 assembler->Goto(&if_equal); |
| 1157 |
| 1158 assembler->Bind(&if_notsame); |
| 1159 { |
| 1160 // Load instance types of {lhs} and {rhs}. |
| 1161 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); |
| 1162 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); |
| 1163 |
| 1164 // Combine the instance types into a single 16-bit value, so we can check |
| 1165 // both of them at once. |
| 1166 Node* both_instance_types = assembler->Word32Or( |
| 1167 lhs_instance_type, |
| 1168 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); |
| 1169 |
| 1170 // Check that both {lhs} and {rhs} are flat one-byte strings. |
| 1171 int const kBothSeqOneByteStringMask = |
| 1172 kStringEncodingMask | kStringRepresentationMask | |
| 1173 ((kStringEncodingMask | kStringRepresentationMask) << 8); |
| 1174 int const kBothSeqOneByteStringTag = |
| 1175 kOneByteStringTag | kSeqStringTag | |
| 1176 ((kOneByteStringTag | kSeqStringTag) << 8); |
| 1177 Label if_bothonebyteseqstrings(assembler), |
| 1178 if_notbothonebyteseqstrings(assembler); |
| 1179 assembler->Branch(assembler->Word32Equal( |
| 1180 assembler->Word32And(both_instance_types, |
| 1181 assembler->Int32Constant( |
| 1182 kBothSeqOneByteStringMask)), |
| 1183 assembler->Int32Constant(kBothSeqOneByteStringTag)), |
| 1184 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); |
| 1185 |
| 1186 assembler->Bind(&if_bothonebyteseqstrings); |
| 1187 { |
| 1188 // Load the length of {lhs} and {rhs}. |
| 1189 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); |
| 1190 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); |
| 1191 |
| 1192 // Determine the minimum length. |
| 1193 Node* length = assembler->SmiMin(lhs_length, rhs_length); |
| 1194 |
| 1195 // Compute the effective offset of the first character. |
| 1196 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - |
| 1197 kHeapObjectTag); |
| 1198 |
| 1199 // Compute the first offset after the string from the length. |
| 1200 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length)); |
| 1201 |
| 1202 // Loop over the {lhs} and {rhs} strings to see if they are equal. |
| 1203 Variable var_offset(assembler, MachineType::PointerRepresentation()); |
| 1204 Label loop(assembler, &var_offset); |
| 1205 var_offset.Bind(begin); |
| 1206 assembler->Goto(&loop); |
| 1207 assembler->Bind(&loop); |
| 1208 { |
| 1209 // Check if {offset} equals {end}. |
| 1210 Node* offset = var_offset.value(); |
| 1211 Label if_done(assembler), if_notdone(assembler); |
| 1212 assembler->Branch(assembler->WordEqual(offset, end), &if_done, |
| 1213 &if_notdone); |
| 1214 |
| 1215 assembler->Bind(&if_notdone); |
| 1216 { |
| 1217 // Load the next characters from {lhs} and {rhs}. |
| 1218 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset); |
| 1219 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset); |
| 1220 |
| 1221 // Check if the characters match. |
| 1222 Label if_valueissame(assembler), if_valueisnotsame(assembler); |
| 1223 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), |
| 1224 &if_valueissame, &if_valueisnotsame); |
| 1225 |
| 1226 assembler->Bind(&if_valueissame); |
| 1227 { |
| 1228 // Advance to next character. |
| 1229 var_offset.Bind( |
| 1230 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); |
| 1231 } |
| 1232 assembler->Goto(&loop); |
| 1233 |
| 1234 assembler->Bind(&if_valueisnotsame); |
| 1235 assembler->BranchIfInt32LessThan(lhs_value, rhs_value, &if_less, |
| 1236 &if_greater); |
| 1237 } |
| 1238 |
| 1239 assembler->Bind(&if_done); |
| 1240 { |
| 1241 // All characters up to the min length are equal, decide based on |
| 1242 // string length. |
| 1243 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); |
| 1244 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length), |
| 1245 &if_lengthisequal, &if_lengthisnotequal); |
| 1246 |
| 1247 assembler->Bind(&if_lengthisequal); |
| 1248 assembler->Goto(&if_equal); |
| 1249 |
| 1250 assembler->Bind(&if_lengthisnotequal); |
| 1251 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, |
| 1252 &if_greater); |
| 1253 } |
| 1254 } |
| 1255 } |
| 1256 |
| 1257 assembler->Bind(&if_notbothonebyteseqstrings); |
| 1258 { |
| 1259 // TODO(bmeurer): Add fast case support for flattened cons strings; |
| 1260 // also add support for two byte string relational comparisons. |
| 1261 switch (mode) { |
| 1262 case kLessThan: |
| 1263 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs, |
| 1264 rhs); |
| 1265 break; |
| 1266 case kLessThanOrEqual: |
| 1267 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context, |
| 1268 lhs, rhs); |
| 1269 break; |
| 1270 case kGreaterThan: |
| 1271 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, |
| 1272 rhs); |
| 1273 break; |
| 1274 case kGreaterThanOrEqual: |
| 1275 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, |
| 1276 context, lhs, rhs); |
| 1277 break; |
| 1278 } |
| 1279 } |
| 1280 } |
| 1281 |
| 1282 assembler->Bind(&if_less); |
| 1283 switch (mode) { |
| 1284 case kLessThan: |
| 1285 case kLessThanOrEqual: |
| 1286 assembler->Return(assembler->BooleanConstant(true)); |
| 1287 break; |
| 1288 |
| 1289 case kGreaterThan: |
| 1290 case kGreaterThanOrEqual: |
| 1291 assembler->Return(assembler->BooleanConstant(false)); |
| 1292 break; |
| 1293 } |
| 1294 |
| 1295 assembler->Bind(&if_equal); |
| 1296 switch (mode) { |
| 1297 case kLessThan: |
| 1298 case kGreaterThan: |
| 1299 assembler->Return(assembler->BooleanConstant(false)); |
| 1300 break; |
| 1301 |
| 1302 case kLessThanOrEqual: |
| 1303 case kGreaterThanOrEqual: |
| 1304 assembler->Return(assembler->BooleanConstant(true)); |
| 1305 break; |
| 1306 } |
| 1307 |
| 1308 assembler->Bind(&if_greater); |
| 1309 switch (mode) { |
| 1310 case kLessThan: |
| 1311 case kLessThanOrEqual: |
| 1312 assembler->Return(assembler->BooleanConstant(false)); |
| 1313 break; |
| 1314 |
| 1315 case kGreaterThan: |
| 1316 case kGreaterThanOrEqual: |
| 1317 assembler->Return(assembler->BooleanConstant(true)); |
| 1318 break; |
| 1319 } |
| 1320 } |
| 1321 |
1137 void GenerateStringEqual(compiler::CodeStubAssembler* assembler, | 1322 void GenerateStringEqual(compiler::CodeStubAssembler* assembler, |
1138 ResultMode mode) { | 1323 ResultMode mode) { |
1139 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | 1324 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
1140 // mode; for kNegateResult mode we properly negate the result. | 1325 // mode; for kNegateResult mode we properly negate the result. |
1141 // | 1326 // |
1142 // if (lhs == rhs) return true; | 1327 // if (lhs == rhs) return true; |
1143 // if (lhs->length() != rhs->length()) return false; | 1328 // if (lhs->length() != rhs->length()) return false; |
1144 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { | 1329 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { |
1145 // return false; | 1330 // return false; |
1146 // } | 1331 // } |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1346 void StringEqualStub::GenerateAssembly( | 1531 void StringEqualStub::GenerateAssembly( |
1347 compiler::CodeStubAssembler* assembler) const { | 1532 compiler::CodeStubAssembler* assembler) const { |
1348 GenerateStringEqual(assembler, kDontNegateResult); | 1533 GenerateStringEqual(assembler, kDontNegateResult); |
1349 } | 1534 } |
1350 | 1535 |
1351 void StringNotEqualStub::GenerateAssembly( | 1536 void StringNotEqualStub::GenerateAssembly( |
1352 compiler::CodeStubAssembler* assembler) const { | 1537 compiler::CodeStubAssembler* assembler) const { |
1353 GenerateStringEqual(assembler, kNegateResult); | 1538 GenerateStringEqual(assembler, kNegateResult); |
1354 } | 1539 } |
1355 | 1540 |
| 1541 void StringLessThanStub::GenerateAssembly( |
| 1542 compiler::CodeStubAssembler* assembler) const { |
| 1543 GenerateStringRelationalComparison(assembler, kLessThan); |
| 1544 } |
| 1545 |
| 1546 void StringLessThanOrEqualStub::GenerateAssembly( |
| 1547 compiler::CodeStubAssembler* assembler) const { |
| 1548 GenerateStringRelationalComparison(assembler, kLessThanOrEqual); |
| 1549 } |
| 1550 |
| 1551 void StringGreaterThanStub::GenerateAssembly( |
| 1552 compiler::CodeStubAssembler* assembler) const { |
| 1553 GenerateStringRelationalComparison(assembler, kGreaterThan); |
| 1554 } |
| 1555 |
| 1556 void StringGreaterThanOrEqualStub::GenerateAssembly( |
| 1557 compiler::CodeStubAssembler* assembler) const { |
| 1558 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual); |
| 1559 } |
| 1560 |
1356 void ToBooleanStub::GenerateAssembly( | 1561 void ToBooleanStub::GenerateAssembly( |
1357 compiler::CodeStubAssembler* assembler) const { | 1562 compiler::CodeStubAssembler* assembler) const { |
1358 typedef compiler::Node Node; | 1563 typedef compiler::Node Node; |
1359 typedef compiler::CodeStubAssembler::Label Label; | 1564 typedef compiler::CodeStubAssembler::Label Label; |
1360 | 1565 |
1361 Node* value = assembler->Parameter(0); | 1566 Node* value = assembler->Parameter(0); |
1362 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | 1567 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
1363 | 1568 |
1364 // Check if {value} is a Smi or a HeapObject. | 1569 // Check if {value} is a Smi or a HeapObject. |
1365 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, | 1570 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, |
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1921 if (type->Is(Type::UntaggedPointer())) { | 2126 if (type->Is(Type::UntaggedPointer())) { |
1922 return Representation::External(); | 2127 return Representation::External(); |
1923 } | 2128 } |
1924 | 2129 |
1925 DCHECK(!type->Is(Type::Untagged())); | 2130 DCHECK(!type->Is(Type::Untagged())); |
1926 return Representation::Tagged(); | 2131 return Representation::Tagged(); |
1927 } | 2132 } |
1928 | 2133 |
1929 } // namespace internal | 2134 } // namespace internal |
1930 } // namespace v8 | 2135 } // namespace v8 |
OLD | NEW |