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

Side by Side Diff: src/builtins/builtins-string.cc

Issue 2381053002: Reland "[builtins] migrate C++ String Iterator builtins to baseline TurboFan" (Closed)
Patch Set: Add the fix and test Created 4 years, 2 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/builtins/builtins.h ('k') | src/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 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 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/builtins/builtins.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 1010 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 typedef compiler::Node Node; 1021 typedef compiler::Node Node;
1022 1022
1023 Node* receiver = assembler->Parameter(0); 1023 Node* receiver = assembler->Parameter(0);
1024 Node* context = assembler->Parameter(3); 1024 Node* context = assembler->Parameter(3);
1025 1025
1026 Node* result = assembler->ToThisValue( 1026 Node* result = assembler->ToThisValue(
1027 context, receiver, PrimitiveType::kString, "String.prototype.valueOf"); 1027 context, receiver, PrimitiveType::kString, "String.prototype.valueOf");
1028 assembler->Return(result); 1028 assembler->Return(result);
1029 } 1029 }
1030 1030
1031 BUILTIN(StringPrototypeIterator) { 1031 void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) {
1032 HandleScope scope(isolate); 1032 typedef CodeStubAssembler::Label Label;
1033 TO_THIS_STRING(object, "String.prototype[Symbol.iterator]"); 1033 typedef compiler::Node Node;
1034 1034 typedef CodeStubAssembler::Variable Variable;
1035 Handle<String> string; 1035
1036 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, 1036 Variable var_string(assembler, MachineRepresentation::kTagged);
1037 Object::ToString(isolate, object)); 1037 Variable var_index(assembler, MachineRepresentation::kTagged);
1038 1038
1039 return *isolate->factory()->NewJSStringIterator(string); 1039 Variable* loop_inputs[] = {&var_string, &var_index};
1040 Label loop(assembler, 2, loop_inputs);
1041 Label allocate_iterator(assembler);
1042
1043 Node* receiver = assembler->Parameter(0);
1044 Node* context = assembler->Parameter(3);
1045
1046 var_string.Bind(assembler->ToThisString(context, receiver,
1047 "String.prototype[Symbol.iterator]"));
1048 var_index.Bind(assembler->SmiConstant(Smi::FromInt(0)));
1049
1050 assembler->Goto(&loop);
1051 assembler->Bind(&loop);
1052 {
1053 Node* string = var_string.value();
1054 // Load the instance type of the {string}.
1055 Node* string_instance_type = assembler->LoadInstanceType(string);
1056
1057 // Check if the {string} is a SeqString.
1058 Label if_stringisnotsequential(assembler);
1059 assembler->Branch(assembler->Word32Equal(
1060 assembler->Word32And(string_instance_type,
1061 assembler->Int32Constant(
1062 kStringRepresentationMask)),
1063 assembler->Int32Constant(kSeqStringTag)),
1064 &allocate_iterator, &if_stringisnotsequential);
1065
1066 assembler->Bind(&if_stringisnotsequential);
1067 {
1068 // Check if the {string} is a ConsString.
1069 Label if_stringiscons(assembler), if_stringisnotcons(assembler);
1070 assembler->Branch(
1071 assembler->Word32Equal(
1072 assembler->Word32And(
1073 string_instance_type,
1074 assembler->Int32Constant(kStringRepresentationMask)),
1075 assembler->Int32Constant(kConsStringTag)),
1076 &if_stringiscons, &if_stringisnotcons);
1077
1078 assembler->Bind(&if_stringiscons);
1079 {
1080 // Flatten cons-string and finish.
1081 var_string.Bind(assembler->CallRuntime(
1082 Runtime::kFlattenString, assembler->NoContextConstant(), string));
1083 assembler->Goto(&allocate_iterator);
1084 }
1085
1086 assembler->Bind(&if_stringisnotcons);
1087 {
1088 // Check if the {string} is an ExternalString.
1089 Label if_stringisnotexternal(assembler);
1090 assembler->Branch(
1091 assembler->Word32Equal(
1092 assembler->Word32And(
1093 string_instance_type,
1094 assembler->Int32Constant(kStringRepresentationMask)),
1095 assembler->Int32Constant(kExternalStringTag)),
1096 &allocate_iterator, &if_stringisnotexternal);
1097
1098 assembler->Bind(&if_stringisnotexternal);
1099 {
1100 // The {string} is a SlicedString, continue with its parent.
1101 Node* index = var_index.value();
1102 Node* string_offset =
1103 assembler->LoadObjectField(string, SlicedString::kOffsetOffset);
1104 Node* string_parent =
1105 assembler->LoadObjectField(string, SlicedString::kParentOffset);
1106 var_index.Bind(assembler->SmiAdd(index, string_offset));
1107 var_string.Bind(string_parent);
1108 assembler->Goto(&loop);
1109 }
1110 }
1111 }
1112 }
1113
1114 assembler->Bind(&allocate_iterator);
1115 {
1116 Node* native_context = assembler->LoadNativeContext(context);
1117 Node* map = assembler->LoadFixedArrayElement(
1118 native_context,
1119 assembler->IntPtrConstant(Context::STRING_ITERATOR_MAP_INDEX), 0,
1120 CodeStubAssembler::INTPTR_PARAMETERS);
1121 Node* iterator = assembler->Allocate(JSStringIterator::kSize);
1122 assembler->StoreMapNoWriteBarrier(iterator, map);
1123 assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset,
1124 Heap::kEmptyFixedArrayRootIndex);
1125 assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset,
1126 Heap::kEmptyFixedArrayRootIndex);
1127 assembler->StoreObjectFieldNoWriteBarrier(
1128 iterator, JSStringIterator::kStringOffset, var_string.value());
1129
1130 assembler->StoreObjectFieldNoWriteBarrier(
1131 iterator, JSStringIterator::kNextIndexOffset, var_index.value());
1132 assembler->Return(iterator);
1133 }
1040 } 1134 }
1041 1135
1042 BUILTIN(StringIteratorPrototypeNext) { 1136 namespace {
1043 HandleScope scope(isolate); 1137
1044 1138 // Return the |word32| codepoint at {index}. Supports SeqStrings and
1045 if (!args.receiver()->IsJSStringIterator()) { 1139 // ExternalStrings.
1046 Handle<String> reason = isolate->factory()->NewStringFromAsciiChecked( 1140 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler,
1047 "String Iterator.prototype.next"); 1141 compiler::Node* string,
1048 THROW_NEW_ERROR_RETURN_FAILURE( 1142 compiler::Node* length,
1049 isolate, 1143 compiler::Node* index,
1050 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, reason)); 1144 UnicodeEncoding encoding) {
1051 } 1145 typedef CodeStubAssembler::Label Label;
1052 Handle<JSStringIterator> iterator = 1146 typedef compiler::Node Node;
1053 Handle<JSStringIterator>::cast(args.receiver()); 1147 typedef CodeStubAssembler::Variable Variable;
1054 Handle<String> string(iterator->string()); 1148 Label handle_surrogate_pair(assembler), return_result(assembler);
1055 1149 Variable var_result(assembler, MachineRepresentation::kWord32);
1056 int position = iterator->index(); 1150 Variable var_trail(assembler, MachineRepresentation::kWord16);
1057 int length = string->length(); 1151 var_result.Bind(assembler->Int32Constant(0));
1058 1152 var_trail.Bind(assembler->Int32Constant(0));
1059 if (position < length) { 1153
1060 uint16_t lead = string->Get(position); 1154 Node* string_instance_type = assembler->LoadInstanceType(string);
1061 if (lead >= 0xD800 && lead <= 0xDBFF && position + 1 < length) { 1155
1062 uint16_t trail = string->Get(position + 1); 1156 Label if_stringissequential(assembler), if_stringisexternal(assembler);
1063 if (V8_LIKELY(trail >= 0xDC00 && trail <= 0xDFFF)) { 1157 assembler->Branch(assembler->Word32Equal(
1064 // Return surrogate pair code units 1158 assembler->Word32And(string_instance_type,
1065 iterator->set_index(position + 2); 1159 assembler->Int32Constant(
1066 Handle<String> value = 1160 kStringRepresentationMask)),
1067 isolate->factory()->NewSurrogatePairString(lead, trail); 1161 assembler->Int32Constant(kSeqStringTag)),
1068 return *isolate->factory()->NewJSIteratorResult(value, false); 1162 &if_stringissequential, &if_stringisexternal);
1069 } 1163
1070 } 1164 assembler->Bind(&if_stringissequential);
1071 1165 {
1072 // Return single code unit 1166 Label if_stringisonebyte(assembler), if_stringistwobyte(assembler);
1073 iterator->set_index(position + 1); 1167 assembler->Branch(
1074 Handle<String> value = 1168 assembler->Word32Equal(
1075 isolate->factory()->LookupSingleCharacterStringFromCode(lead); 1169 assembler->Word32And(string_instance_type,
1076 return *isolate->factory()->NewJSIteratorResult(value, false); 1170 assembler->Int32Constant(kStringEncodingMask)),
1077 } 1171 assembler->Int32Constant(kOneByteStringTag)),
1078 1172 &if_stringisonebyte, &if_stringistwobyte);
1079 iterator->set_string(isolate->heap()->empty_string()); 1173
1080 1174 assembler->Bind(&if_stringisonebyte);
1081 return *isolate->factory()->NewJSIteratorResult( 1175 {
1082 isolate->factory()->undefined_value(), true); 1176 var_result.Bind(assembler->Load(
1177 MachineType::Uint8(), string,
1178 assembler->IntPtrAdd(
1179 index, assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
1180 kHeapObjectTag))));
1181 assembler->Goto(&return_result);
1182 }
1183
1184 assembler->Bind(&if_stringistwobyte);
1185 {
1186 Node* lead = assembler->Load(
1187 MachineType::Uint16(), string,
1188 assembler->IntPtrAdd(
1189 assembler->WordShl(index, assembler->IntPtrConstant(1)),
1190 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
1191 kHeapObjectTag)));
1192 var_result.Bind(lead);
1193 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1));
1194
1195 Label if_isdoublecodeunit(assembler);
1196 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
1197 &return_result);
1198 assembler->GotoIf(
1199 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
1200 &return_result);
1201 assembler->Branch(
1202 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)),
1203 &if_isdoublecodeunit, &return_result);
1204
1205 assembler->Bind(&if_isdoublecodeunit);
1206 {
1207 Node* trail = assembler->Load(
1208 MachineType::Uint16(), string,
1209 assembler->IntPtrAdd(
1210 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)),
1211 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
1212 kHeapObjectTag)));
1213 assembler->GotoIf(
1214 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)),
1215 &return_result);
1216 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
1217 trail, assembler->Int32Constant(0xE000)),
1218 &return_result);
1219
1220 var_trail.Bind(trail);
1221 assembler->Goto(&handle_surrogate_pair);
1222 }
1223 }
1224 }
1225
1226 assembler->Bind(&if_stringisexternal);
1227 {
1228 assembler->Assert(assembler->Word32Equal(
1229 assembler->Word32And(
1230 string_instance_type,
1231 assembler->Int32Constant(kStringRepresentationMask)),
1232 assembler->Int32Constant(kExternalStringTag)));
1233 Label if_stringisshort(assembler), if_stringisnotshort(assembler);
1234
1235 assembler->Branch(assembler->Word32Equal(
1236 assembler->Word32And(string_instance_type,
1237 assembler->Int32Constant(
1238 kShortExternalStringMask)),
1239 assembler->Int32Constant(0)),
1240 &if_stringisshort, &if_stringisnotshort);
1241
1242 assembler->Bind(&if_stringisshort);
1243 {
1244 // Load the actual resource data from the {string}.
1245 Node* string_resource_data = assembler->LoadObjectField(
1246 string, ExternalString::kResourceDataOffset, MachineType::Pointer());
1247
1248 Label if_stringistwobyte(assembler), if_stringisonebyte(assembler);
1249 assembler->Branch(assembler->Word32Equal(
1250 assembler->Word32And(
1251 string_instance_type,
1252 assembler->Int32Constant(kStringEncodingMask)),
1253 assembler->Int32Constant(kTwoByteStringTag)),
1254 &if_stringistwobyte, &if_stringisonebyte);
1255
1256 assembler->Bind(&if_stringisonebyte);
1257 {
1258 var_result.Bind(
1259 assembler->Load(MachineType::Uint8(), string_resource_data, index));
1260 assembler->Goto(&return_result);
1261 }
1262
1263 assembler->Bind(&if_stringistwobyte);
1264 {
1265 Label if_isdoublecodeunit(assembler);
1266 Node* lead = assembler->Load(
1267 MachineType::Uint16(), string_resource_data,
1268 assembler->WordShl(index, assembler->IntPtrConstant(1)));
1269 var_result.Bind(lead);
1270 Node* next_pos =
1271 assembler->Int32Add(index, assembler->Int32Constant(1));
1272
1273 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
1274 &return_result);
1275 assembler->GotoIf(
1276 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
1277 &return_result);
1278 assembler->Branch(
1279 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)),
1280 &if_isdoublecodeunit, &return_result);
1281
1282 assembler->Bind(&if_isdoublecodeunit);
1283 {
1284 Node* trail = assembler->Load(
1285 MachineType::Uint16(), string,
1286 assembler->IntPtrAdd(
1287 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)),
1288 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
1289 kHeapObjectTag)));
1290 assembler->GotoIf(assembler->Uint32LessThan(
1291 trail, assembler->Int32Constant(0xDC00)),
1292 &return_result);
1293 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
1294 trail, assembler->Int32Constant(0xE000)),
1295 &return_result);
1296
1297 var_trail.Bind(trail);
1298 assembler->Goto(&handle_surrogate_pair);
1299 }
1300 }
1301 }
1302
1303 assembler->Bind(&if_stringisnotshort);
1304 {
1305 Label if_isdoublecodeunit(assembler);
1306 Node* lead = assembler->SmiToWord32(assembler->CallRuntime(
1307 Runtime::kExternalStringGetChar, assembler->NoContextConstant(),
1308 string, assembler->SmiTag(index)));
1309 var_result.Bind(lead);
1310 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1));
1311
1312 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
1313 &return_result);
1314 assembler->GotoIf(
1315 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
1316 &return_result);
1317 assembler->Branch(assembler->Uint32GreaterThanOrEqual(
1318 lead, assembler->Int32Constant(0xDC00)),
1319 &return_result, &if_isdoublecodeunit);
1320
1321 assembler->Bind(&if_isdoublecodeunit);
1322 {
1323 Node* trail = assembler->SmiToWord32(assembler->CallRuntime(
1324 Runtime::kExternalStringGetChar, assembler->NoContextConstant(),
1325 string, assembler->SmiTag(next_pos)));
1326 assembler->GotoIf(
1327 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)),
1328 &return_result);
1329 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
1330 trail, assembler->Int32Constant(0xE000)),
1331 &return_result);
1332 var_trail.Bind(trail);
1333 assembler->Goto(&handle_surrogate_pair);
1334 }
1335 }
1336 }
1337
1338 assembler->Bind(&handle_surrogate_pair);
1339 {
1340 Node* lead = var_result.value();
1341 Node* trail = var_trail.value();
1342 #ifdef ENABLE_SLOW_DCHECKS
1343 // Check that this path is only taken if a surrogate pair is found
1344 assembler->Assert(assembler->Uint32GreaterThanOrEqual(
1345 lead, assembler->Int32Constant(0xD800)));
1346 assembler->Assert(
1347 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)));
1348 assembler->Assert(assembler->Uint32GreaterThanOrEqual(
1349 trail, assembler->Int32Constant(0xDC00)));
1350 assembler->Assert(
1351 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xE000)));
1352 #endif
1353
1354 switch (encoding) {
1355 case UnicodeEncoding::UTF16:
1356 var_result.Bind(assembler->WordOr(
1357 assembler->WordShl(trail, assembler->Int32Constant(16)), lead));
1358 break;
1359
1360 case UnicodeEncoding::UTF32: {
1361 // Convert UTF16 surrogate pair into |word32| code point, encoded as
1362 // UTF32.
1363 Node* surrogate_offset =
1364 assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00);
1365
1366 // (lead << 10) + trail + SURROGATE_OFFSET
1367 var_result.Bind(assembler->Int32Add(
1368 assembler->WordShl(lead, assembler->Int32Constant(10)),
1369 assembler->Int32Add(trail, surrogate_offset)));
1370 break;
1371 }
1372 }
1373 assembler->Goto(&return_result);
1374 }
1375
1376 assembler->Bind(&return_result);
1377 return var_result.value();
1083 } 1378 }
1084 1379
1380 compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler,
1381 compiler::Node* string,
1382 compiler::Node* length,
1383 compiler::Node* index) {
1384 return LoadSurrogatePairInternal(assembler, string, length, index,
1385 UnicodeEncoding::UTF16);
1386 }
1387
1388 } // namespace
1389
1390 void Builtins::Generate_StringIteratorPrototypeNext(
1391 CodeStubAssembler* assembler) {
1392 typedef CodeStubAssembler::Label Label;
1393 typedef compiler::Node Node;
1394 typedef CodeStubAssembler::Variable Variable;
1395
1396 Variable var_value(assembler, MachineRepresentation::kTagged);
1397 Variable var_done(assembler, MachineRepresentation::kTagged);
1398
1399 var_value.Bind(assembler->UndefinedConstant());
1400 var_done.Bind(assembler->BooleanConstant(true));
1401
1402 Label throw_bad_receiver(assembler), next_codepoint(assembler),
1403 return_result(assembler);
1404
1405 Node* iterator = assembler->Parameter(0);
1406 Node* context = assembler->Parameter(3);
1407
1408 assembler->GotoIf(assembler->WordIsSmi(iterator), &throw_bad_receiver);
1409 assembler->GotoUnless(
1410 assembler->WordEqual(assembler->LoadInstanceType(iterator),
1411 assembler->Int32Constant(JS_STRING_ITERATOR_TYPE)),
1412 &throw_bad_receiver);
1413
1414 Node* string =
1415 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset);
1416 Node* position =
1417 assembler->LoadObjectField(iterator, JSStringIterator::kNextIndexOffset);
1418 Node* length = assembler->LoadObjectField(string, String::kLengthOffset);
1419
1420 assembler->Branch(assembler->SmiLessThan(position, length), &next_codepoint,
1421 &return_result);
1422
1423 assembler->Bind(&next_codepoint);
1424 {
1425 Node* ch =
1426 LoadSurrogatePairAt(assembler, string, assembler->SmiUntag(length),
1427 assembler->SmiUntag(position));
1428 Node* value = assembler->StringFromCodePoint(ch, UnicodeEncoding::UTF16);
1429 var_value.Bind(value);
1430 Node* length = assembler->LoadObjectField(value, String::kLengthOffset);
1431 assembler->StoreObjectFieldNoWriteBarrier(
1432 iterator, JSStringIterator::kNextIndexOffset,
1433 assembler->SmiAdd(position, length));
1434 var_done.Bind(assembler->BooleanConstant(false));
1435 assembler->Goto(&return_result);
1436 }
1437
1438 assembler->Bind(&return_result);
1439 {
1440 Node* native_context = assembler->LoadNativeContext(context);
1441 Node* map = assembler->LoadFixedArrayElement(
1442 native_context,
1443 assembler->IntPtrConstant(Context::ITERATOR_RESULT_MAP_INDEX), 0,
1444 CodeStubAssembler::INTPTR_PARAMETERS);
1445 Node* result = assembler->Allocate(JSIteratorResult::kSize);
1446 assembler->StoreMapNoWriteBarrier(result, map);
1447 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
1448 Heap::kEmptyFixedArrayRootIndex);
1449 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
1450 Heap::kEmptyFixedArrayRootIndex);
1451 assembler->StoreObjectFieldNoWriteBarrier(
1452 result, JSIteratorResult::kValueOffset, var_value.value());
1453 assembler->StoreObjectFieldNoWriteBarrier(
1454 result, JSIteratorResult::kDoneOffset, var_done.value());
1455 assembler->Return(result);
1456 }
1457
1458 assembler->Bind(&throw_bad_receiver);
1459 {
1460 // The {receiver} is not a valid JSGeneratorObject.
1461 Node* result = assembler->CallRuntime(
1462 Runtime::kThrowIncompatibleMethodReceiver, context,
1463 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked(
1464 "String Iterator.prototype.next", TENURED)),
1465 iterator);
1466 assembler->Return(result); // Never reached.
1467 }
1468 }
1469
1085 } // namespace internal 1470 } // namespace internal
1086 } // namespace v8 1471 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698