OLD | NEW |
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 1011 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) { | 1031 void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) { |
1032 typedef CodeStubAssembler::Label Label; | |
1033 typedef compiler::Node Node; | 1032 typedef compiler::Node Node; |
1034 typedef CodeStubAssembler::Variable Variable; | |
1035 | |
1036 Variable var_string(assembler, MachineRepresentation::kTagged); | |
1037 Variable var_index(assembler, MachineRepresentation::kTagged); | |
1038 | |
1039 Variable* loop_inputs[] = {&var_string, &var_index}; | |
1040 Label loop(assembler, 2, loop_inputs); | |
1041 Label allocate_iterator(assembler); | |
1042 | 1033 |
1043 Node* receiver = assembler->Parameter(0); | 1034 Node* receiver = assembler->Parameter(0); |
1044 Node* context = assembler->Parameter(3); | 1035 Node* context = assembler->Parameter(3); |
1045 | 1036 |
1046 var_string.Bind(assembler->ToThisString(context, receiver, | 1037 Node* string = assembler->ToThisString(context, receiver, |
1047 "String.prototype[Symbol.iterator]")); | 1038 "String.prototype[Symbol.iterator]"); |
1048 var_index.Bind(assembler->SmiConstant(Smi::FromInt(0))); | |
1049 | 1039 |
1050 assembler->Goto(&loop); | 1040 Node* native_context = assembler->LoadNativeContext(context); |
1051 assembler->Bind(&loop); | 1041 Node* map = assembler->LoadFixedArrayElement( |
1052 { | 1042 native_context, |
1053 Node* string = var_string.value(); | 1043 assembler->IntPtrConstant(Context::STRING_ITERATOR_MAP_INDEX), 0, |
1054 // Load the instance type of the {string}. | 1044 CodeStubAssembler::INTPTR_PARAMETERS); |
1055 Node* string_instance_type = assembler->LoadInstanceType(string); | 1045 Node* iterator = assembler->Allocate(JSStringIterator::kSize); |
1056 | 1046 assembler->StoreMapNoWriteBarrier(iterator, map); |
1057 // Check if the {string} is a SeqString. | 1047 assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset, |
1058 Label if_stringisnotsequential(assembler); | 1048 Heap::kEmptyFixedArrayRootIndex); |
1059 assembler->Branch(assembler->Word32Equal( | 1049 assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, |
1060 assembler->Word32And(string_instance_type, | 1050 Heap::kEmptyFixedArrayRootIndex); |
1061 assembler->Int32Constant( | 1051 assembler->StoreObjectFieldNoWriteBarrier( |
1062 kStringRepresentationMask)), | 1052 iterator, JSStringIterator::kStringOffset, string); |
1063 assembler->Int32Constant(kSeqStringTag)), | 1053 Node* index = assembler->SmiConstant(Smi::FromInt(0)); |
1064 &allocate_iterator, &if_stringisnotsequential); | 1054 assembler->StoreObjectFieldNoWriteBarrier( |
1065 | 1055 iterator, JSStringIterator::kNextIndexOffset, index); |
1066 assembler->Bind(&if_stringisnotsequential); | 1056 assembler->Return(iterator); |
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 } | |
1134 } | 1057 } |
1135 | 1058 |
1136 namespace { | 1059 namespace { |
1137 | 1060 |
1138 // Return the |word32| codepoint at {index}. Supports SeqStrings and | 1061 // Return the |word32| codepoint at {index}. Supports SeqStrings and |
1139 // ExternalStrings. | 1062 // ExternalStrings. |
1140 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, | 1063 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, |
1141 compiler::Node* string, | 1064 compiler::Node* string, |
1142 compiler::Node* length, | 1065 compiler::Node* length, |
1143 compiler::Node* index, | 1066 compiler::Node* index, |
1144 UnicodeEncoding encoding) { | 1067 UnicodeEncoding encoding) { |
1145 typedef CodeStubAssembler::Label Label; | 1068 typedef CodeStubAssembler::Label Label; |
1146 typedef compiler::Node Node; | 1069 typedef compiler::Node Node; |
1147 typedef CodeStubAssembler::Variable Variable; | 1070 typedef CodeStubAssembler::Variable Variable; |
1148 Label handle_surrogate_pair(assembler), return_result(assembler); | 1071 Label handle_surrogate_pair(assembler), return_result(assembler); |
1149 Variable var_result(assembler, MachineRepresentation::kWord32); | 1072 Variable var_result(assembler, MachineRepresentation::kWord32); |
1150 Variable var_trail(assembler, MachineRepresentation::kWord16); | 1073 Variable var_trail(assembler, MachineRepresentation::kWord16); |
1151 var_result.Bind(assembler->Int32Constant(0)); | 1074 var_result.Bind(assembler->StringCharCodeAt(string, index)); |
1152 var_trail.Bind(assembler->Int32Constant(0)); | 1075 var_trail.Bind(assembler->Int32Constant(0)); |
1153 | 1076 |
1154 Node* string_instance_type = assembler->LoadInstanceType(string); | 1077 assembler->GotoIf(assembler->Word32NotEqual( |
| 1078 assembler->Word32And(var_result.value(), |
| 1079 assembler->Int32Constant(0xFC00)), |
| 1080 assembler->Int32Constant(0xD800)), |
| 1081 &return_result); |
| 1082 Node* next_index = |
| 1083 assembler->SmiAdd(index, assembler->SmiConstant(Smi::FromInt(1))); |
1155 | 1084 |
1156 Label if_stringissequential(assembler), if_stringisexternal(assembler); | 1085 assembler->GotoUnless(assembler->SmiLessThan(next_index, length), |
| 1086 &return_result); |
| 1087 var_trail.Bind(assembler->StringCharCodeAt(string, next_index)); |
1157 assembler->Branch(assembler->Word32Equal( | 1088 assembler->Branch(assembler->Word32Equal( |
1158 assembler->Word32And(string_instance_type, | 1089 assembler->Word32And(var_trail.value(), |
1159 assembler->Int32Constant( | 1090 assembler->Int32Constant(0xFC00)), |
1160 kStringRepresentationMask)), | 1091 assembler->Int32Constant(0xDC00)), |
1161 assembler->Int32Constant(kSeqStringTag)), | 1092 &handle_surrogate_pair, &return_result); |
1162 &if_stringissequential, &if_stringisexternal); | |
1163 | |
1164 assembler->Bind(&if_stringissequential); | |
1165 { | |
1166 Label if_stringisonebyte(assembler), if_stringistwobyte(assembler); | |
1167 assembler->Branch( | |
1168 assembler->Word32Equal( | |
1169 assembler->Word32And(string_instance_type, | |
1170 assembler->Int32Constant(kStringEncodingMask)), | |
1171 assembler->Int32Constant(kOneByteStringTag)), | |
1172 &if_stringisonebyte, &if_stringistwobyte); | |
1173 | |
1174 assembler->Bind(&if_stringisonebyte); | |
1175 { | |
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 | 1093 |
1338 assembler->Bind(&handle_surrogate_pair); | 1094 assembler->Bind(&handle_surrogate_pair); |
1339 { | 1095 { |
1340 Node* lead = var_result.value(); | 1096 Node* lead = var_result.value(); |
1341 Node* trail = var_trail.value(); | 1097 Node* trail = var_trail.value(); |
1342 #ifdef ENABLE_SLOW_DCHECKS | 1098 #ifdef ENABLE_SLOW_DCHECKS |
1343 // Check that this path is only taken if a surrogate pair is found | 1099 // Check that this path is only taken if a surrogate pair is found |
1344 assembler->Assert(assembler->Uint32GreaterThanOrEqual( | 1100 assembler->Assert(assembler->Uint32GreaterThanOrEqual( |
1345 lead, assembler->Int32Constant(0xD800))); | 1101 lead, assembler->Int32Constant(0xD800))); |
1346 assembler->Assert( | 1102 assembler->Assert( |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1415 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset); | 1171 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset); |
1416 Node* position = | 1172 Node* position = |
1417 assembler->LoadObjectField(iterator, JSStringIterator::kNextIndexOffset); | 1173 assembler->LoadObjectField(iterator, JSStringIterator::kNextIndexOffset); |
1418 Node* length = assembler->LoadObjectField(string, String::kLengthOffset); | 1174 Node* length = assembler->LoadObjectField(string, String::kLengthOffset); |
1419 | 1175 |
1420 assembler->Branch(assembler->SmiLessThan(position, length), &next_codepoint, | 1176 assembler->Branch(assembler->SmiLessThan(position, length), &next_codepoint, |
1421 &return_result); | 1177 &return_result); |
1422 | 1178 |
1423 assembler->Bind(&next_codepoint); | 1179 assembler->Bind(&next_codepoint); |
1424 { | 1180 { |
1425 Node* ch = | 1181 Node* ch = LoadSurrogatePairAt(assembler, string, length, position); |
1426 LoadSurrogatePairAt(assembler, string, assembler->SmiUntag(length), | |
1427 assembler->SmiUntag(position)); | |
1428 Node* value = assembler->StringFromCodePoint(ch, UnicodeEncoding::UTF16); | 1182 Node* value = assembler->StringFromCodePoint(ch, UnicodeEncoding::UTF16); |
1429 var_value.Bind(value); | 1183 var_value.Bind(value); |
1430 Node* length = assembler->LoadObjectField(value, String::kLengthOffset); | 1184 Node* length = assembler->LoadObjectField(value, String::kLengthOffset); |
1431 assembler->StoreObjectFieldNoWriteBarrier( | 1185 assembler->StoreObjectFieldNoWriteBarrier( |
1432 iterator, JSStringIterator::kNextIndexOffset, | 1186 iterator, JSStringIterator::kNextIndexOffset, |
1433 assembler->SmiAdd(position, length)); | 1187 assembler->SmiAdd(position, length)); |
1434 var_done.Bind(assembler->BooleanConstant(false)); | 1188 var_done.Bind(assembler->BooleanConstant(false)); |
1435 assembler->Goto(&return_result); | 1189 assembler->Goto(&return_result); |
1436 } | 1190 } |
1437 | 1191 |
(...skipping 24 matching lines...) Expand all Loading... |
1462 Runtime::kThrowIncompatibleMethodReceiver, context, | 1216 Runtime::kThrowIncompatibleMethodReceiver, context, |
1463 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | 1217 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( |
1464 "String Iterator.prototype.next", TENURED)), | 1218 "String Iterator.prototype.next", TENURED)), |
1465 iterator); | 1219 iterator); |
1466 assembler->Return(result); // Never reached. | 1220 assembler->Return(result); // Never reached. |
1467 } | 1221 } |
1468 } | 1222 } |
1469 | 1223 |
1470 } // namespace internal | 1224 } // namespace internal |
1471 } // namespace v8 | 1225 } // namespace v8 |
OLD | NEW |