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

Side by Side Diff: src/code-stubs.cc

Issue 1758333002: [compiler] Introduce code stubs for string relational comparisons. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@AbstractRelationalComparison
Patch Set: Created 4 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
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.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 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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698