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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
10 #include "src/string-builder.h" | 10 #include "src/string-builder.h" |
(...skipping 1217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1228 previous_last_index_obj, STRICT)); | 1228 previous_last_index_obj, STRICT)); |
1229 } | 1229 } |
1230 } | 1230 } |
1231 | 1231 |
1232 if (result->IsNull(isolate)) return Smi::FromInt(-1); | 1232 if (result->IsNull(isolate)) return Smi::FromInt(-1); |
1233 | 1233 |
1234 RETURN_RESULT_OR_FAILURE( | 1234 RETURN_RESULT_OR_FAILURE( |
1235 isolate, Object::GetProperty(result, isolate->factory()->index_string())); | 1235 isolate, Object::GetProperty(result, isolate->factory()->index_string())); |
1236 } | 1236 } |
1237 | 1237 |
| 1238 namespace { |
| 1239 |
| 1240 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
| 1241 Handle<Object> object, |
| 1242 uint32_t* out) { |
| 1243 if (object->IsUndefined(isolate)) { |
| 1244 *out = kMaxUInt32; |
| 1245 return object; |
| 1246 } |
| 1247 |
| 1248 Handle<Object> number; |
| 1249 ASSIGN_RETURN_ON_EXCEPTION(isolate, number, Object::ToNumber(object), Object); |
| 1250 *out = NumberToUint32(*number); |
| 1251 return object; |
| 1252 } |
| 1253 |
| 1254 bool AtSurrogatePair(Isolate* isolate, Handle<String> string, int index) { |
| 1255 if (index + 1 >= string->length()) return false; |
| 1256 const uint16_t first = string->Get(index); |
| 1257 if (first < 0xD800 || first > 0xDBFF) return false; |
| 1258 const uint16_t second = string->Get(index + 1); |
| 1259 return (second >= 0xDC00 && second <= 0xDFFF); |
| 1260 } |
| 1261 |
| 1262 Handle<JSArray> NewJSArrayWithElements(Isolate* isolate, |
| 1263 Handle<FixedArray> elems, |
| 1264 int num_elems) { |
| 1265 elems->Shrink(num_elems); |
| 1266 return isolate->factory()->NewJSArrayWithElements(elems); |
| 1267 } |
| 1268 |
| 1269 MaybeHandle<JSArray> RegExpSplit(Isolate* isolate, Handle<JSRegExp> regexp, |
| 1270 Handle<String> string, |
| 1271 Handle<Object> limit_obj) { |
| 1272 Factory* factory = isolate->factory(); |
| 1273 |
| 1274 uint32_t limit; |
| 1275 RETURN_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit), JSArray); |
| 1276 |
| 1277 const int length = string->length(); |
| 1278 |
| 1279 if (limit == 0) return factory->NewJSArray(0); |
| 1280 |
| 1281 Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); |
| 1282 |
| 1283 if (length == 0) { |
| 1284 Handle<Object> match_indices; |
| 1285 ASSIGN_RETURN_ON_EXCEPTION( |
| 1286 isolate, match_indices, |
| 1287 RegExpImpl::Exec(regexp, string, 0, last_match_info), JSArray); |
| 1288 |
| 1289 if (!match_indices->IsNull(isolate)) return factory->NewJSArray(0); |
| 1290 |
| 1291 Handle<FixedArray> elems = factory->NewUninitializedFixedArray(1); |
| 1292 elems->set(0, *string); |
| 1293 return factory->NewJSArrayWithElements(elems); |
| 1294 } |
| 1295 |
| 1296 int current_index = 0; |
| 1297 int start_index = 0; |
| 1298 int start_match = 0; |
| 1299 |
| 1300 static const int kInitialArraySize = 8; |
| 1301 Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize); |
| 1302 int num_elems = 0; |
| 1303 |
| 1304 while (true) { |
| 1305 if (start_index == length) { |
| 1306 Handle<String> substr = |
| 1307 factory->NewSubString(string, current_index, length); |
| 1308 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1309 break; |
| 1310 } |
| 1311 |
| 1312 Handle<Object> match_indices_obj; |
| 1313 ASSIGN_RETURN_ON_EXCEPTION( |
| 1314 isolate, match_indices_obj, |
| 1315 RegExpImpl::Exec(regexp, string, start_index, last_match_info), |
| 1316 JSArray); |
| 1317 |
| 1318 if (match_indices_obj->IsNull(isolate)) { |
| 1319 Handle<String> substr = |
| 1320 factory->NewSubString(string, current_index, length); |
| 1321 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1322 break; |
| 1323 } |
| 1324 |
| 1325 auto match_indices = Handle<JSReceiver>::cast(match_indices_obj); |
| 1326 |
| 1327 Handle<Object> start_match_obj = |
| 1328 JSReceiver::GetElement(isolate, match_indices, |
| 1329 RegExpImpl::kFirstCapture) |
| 1330 .ToHandleChecked(); |
| 1331 start_match = Handle<Smi>::cast(start_match_obj)->value(); |
| 1332 |
| 1333 if (start_match == length) { |
| 1334 Handle<String> substr = |
| 1335 factory->NewSubString(string, current_index, length); |
| 1336 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1337 break; |
| 1338 } |
| 1339 |
| 1340 Handle<Object> end_index_obj = |
| 1341 JSReceiver::GetElement(isolate, match_indices, |
| 1342 RegExpImpl::kFirstCapture + 1) |
| 1343 .ToHandleChecked(); |
| 1344 const int end_index = Handle<Smi>::cast(end_index_obj)->value(); |
| 1345 |
| 1346 if (start_index == end_index && end_index == current_index) { |
| 1347 const bool unicode = (regexp->GetFlags() & JSRegExp::kUnicode) != 0; |
| 1348 if (unicode && AtSurrogatePair(isolate, string, start_index)) { |
| 1349 start_index += 2; |
| 1350 } else { |
| 1351 start_index += 1; |
| 1352 } |
| 1353 continue; |
| 1354 } |
| 1355 |
| 1356 { |
| 1357 Handle<String> substr = |
| 1358 factory->NewSubString(string, current_index, start_match); |
| 1359 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1360 } |
| 1361 |
| 1362 if (num_elems == limit) break; |
| 1363 |
| 1364 // TODO(jgruber): Refactor GetLastMatchInfo methods to take an input |
| 1365 // argument. |
| 1366 Handle<Object> num_captures_obj = |
| 1367 JSReceiver::GetElement(isolate, match_indices, |
| 1368 RegExpImpl::kLastCaptureCount) |
| 1369 .ToHandleChecked(); |
| 1370 const int match_indices_len = Handle<Smi>::cast(num_captures_obj)->value() + |
| 1371 RegExpImpl::kFirstCapture; |
| 1372 |
| 1373 for (int i = RegExpImpl::kFirstCapture + 2; i < match_indices_len;) { |
| 1374 Handle<Object> start_obj = |
| 1375 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked(); |
| 1376 const int start = Handle<Smi>::cast(start_obj)->value(); |
| 1377 |
| 1378 Handle<Object> end_obj = |
| 1379 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked(); |
| 1380 const int end = Handle<Smi>::cast(end_obj)->value(); |
| 1381 |
| 1382 if (end != -1) { |
| 1383 Handle<String> substr = factory->NewSubString(string, start, end); |
| 1384 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1385 } else { |
| 1386 elems = FixedArray::SetAndGrow(elems, num_elems++, |
| 1387 factory->undefined_value()); |
| 1388 } |
| 1389 |
| 1390 if (num_elems == limit) { |
| 1391 return NewJSArrayWithElements(isolate, elems, num_elems); |
| 1392 } |
| 1393 } |
| 1394 |
| 1395 start_index = current_index = end_index; |
| 1396 } |
| 1397 |
| 1398 return NewJSArrayWithElements(isolate, elems, num_elems); |
| 1399 } |
| 1400 |
| 1401 // ES##sec-speciesconstructor |
| 1402 // SpeciesConstructor ( O, defaultConstructor ) |
| 1403 MaybeHandle<Object> SpeciesConstructor(Isolate* isolate, |
| 1404 Handle<JSReceiver> recv, |
| 1405 Handle<JSFunction> default_ctor) { |
| 1406 Handle<Object> ctor_obj; |
| 1407 ASSIGN_RETURN_ON_EXCEPTION( |
| 1408 isolate, ctor_obj, |
| 1409 JSObject::GetProperty(recv, isolate->factory()->constructor_string()), |
| 1410 Object); |
| 1411 |
| 1412 if (ctor_obj->IsUndefined(isolate)) return default_ctor; |
| 1413 |
| 1414 if (!ctor_obj->IsJSReceiver()) { |
| 1415 THROW_NEW_ERROR(isolate, |
| 1416 NewTypeError(MessageTemplate::kConstructorNotReceiver), |
| 1417 Object); |
| 1418 } |
| 1419 |
| 1420 Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj); |
| 1421 |
| 1422 Handle<Object> species; |
| 1423 ASSIGN_RETURN_ON_EXCEPTION( |
| 1424 isolate, species, |
| 1425 JSObject::GetProperty(ctor, isolate->factory()->species_symbol()), |
| 1426 Object); |
| 1427 |
| 1428 if (species->IsNull(isolate) || species->IsUndefined(isolate)) { |
| 1429 return default_ctor; |
| 1430 } |
| 1431 |
| 1432 if (species->IsConstructor()) return species; |
| 1433 |
| 1434 THROW_NEW_ERROR( |
| 1435 isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); |
| 1436 } |
| 1437 |
| 1438 bool IsBuiltinExec(Handle<Object> exec) { |
| 1439 if (!exec->IsJSFunction()) return false; |
| 1440 |
| 1441 Code* code = Handle<JSFunction>::cast(exec)->code(); |
| 1442 if (code == nullptr) return false; |
| 1443 |
| 1444 return (code->builtin_index() == Builtins::kRegExpPrototypeExec); |
| 1445 } |
| 1446 |
| 1447 } // namespace |
| 1448 |
| 1449 // ES#sec-regexp.prototype-@@split |
| 1450 // RegExp.prototype [ @@split ] ( string, limit ) |
| 1451 BUILTIN(RegExpPrototypeSplit) { |
| 1452 HandleScope scope(isolate); |
| 1453 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@split"); |
| 1454 |
| 1455 Factory* factory = isolate->factory(); |
| 1456 |
| 1457 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); |
| 1458 Handle<Object> limit_obj = args.atOrUndefined(isolate, 2); |
| 1459 |
| 1460 Handle<String> string; |
| 1461 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, |
| 1462 Object::ToString(isolate, string_obj)); |
| 1463 |
| 1464 Handle<JSFunction> regexp_fun = isolate->regexp_function(); |
| 1465 Handle<Object> ctor; |
| 1466 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1467 isolate, ctor, SpeciesConstructor(isolate, recv, regexp_fun)); |
| 1468 |
| 1469 if (recv->IsJSRegExp() && *ctor == *regexp_fun) { |
| 1470 Handle<Object> exec; |
| 1471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1472 isolate, exec, JSObject::GetProperty( |
| 1473 recv, factory->NewStringFromAsciiChecked("exec"))); |
| 1474 if (IsBuiltinExec(exec)) { |
| 1475 RETURN_RESULT_OR_FAILURE( |
| 1476 isolate, RegExpSplit(isolate, Handle<JSRegExp>::cast(recv), string, |
| 1477 limit_obj)); |
| 1478 } |
| 1479 } |
| 1480 |
| 1481 Handle<Object> flags_obj; |
| 1482 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1483 isolate, flags_obj, JSObject::GetProperty(recv, factory->flags_string())); |
| 1484 |
| 1485 Handle<String> flags; |
| 1486 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags, |
| 1487 Object::ToString(isolate, flags_obj)); |
| 1488 |
| 1489 Handle<String> u_str = factory->LookupSingleCharacterStringFromCode('u'); |
| 1490 const bool unicode = (String::IndexOf(isolate, flags, u_str, 0) >= 0); |
| 1491 |
| 1492 Handle<String> y_str = factory->LookupSingleCharacterStringFromCode('y'); |
| 1493 const bool sticky = (String::IndexOf(isolate, flags, y_str, 0) >= 0); |
| 1494 |
| 1495 Handle<String> new_flags = flags; |
| 1496 if (!sticky) { |
| 1497 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_flags, |
| 1498 factory->NewConsString(flags, y_str)); |
| 1499 } |
| 1500 |
| 1501 Handle<JSReceiver> splitter; |
| 1502 { |
| 1503 const int argc = 2; |
| 1504 |
| 1505 ScopedVector<Handle<Object>> argv(argc); |
| 1506 argv[0] = recv; |
| 1507 argv[1] = new_flags; |
| 1508 |
| 1509 Handle<JSFunction> ctor_fun = Handle<JSFunction>::cast(ctor); |
| 1510 Handle<Object> splitter_obj; |
| 1511 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1512 isolate, splitter_obj, Execution::New(ctor_fun, argc, argv.start())); |
| 1513 |
| 1514 splitter = Handle<JSReceiver>::cast(splitter_obj); |
| 1515 } |
| 1516 |
| 1517 uint32_t limit; |
| 1518 RETURN_FAILURE_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit)); |
| 1519 |
| 1520 const int length = string->length(); |
| 1521 |
| 1522 if (limit == 0) return *factory->NewJSArray(0); |
| 1523 |
| 1524 if (length == 0) { |
| 1525 Handle<Object> result; |
| 1526 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1527 isolate, result, |
| 1528 RegExpExec(isolate, splitter, string, factory->undefined_value())); |
| 1529 |
| 1530 if (!result->IsNull(isolate)) return *factory->NewJSArray(0); |
| 1531 |
| 1532 Handle<FixedArray> elems = factory->NewUninitializedFixedArray(1); |
| 1533 elems->set(0, *string); |
| 1534 return *factory->NewJSArrayWithElements(elems); |
| 1535 } |
| 1536 |
| 1537 // TODO(jgruber): Wrap this in a helper class. |
| 1538 static const int kInitialArraySize = 8; |
| 1539 Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize); |
| 1540 int num_elems = 0; |
| 1541 |
| 1542 int string_index = 0; |
| 1543 int prev_string_index = 0; |
| 1544 while (string_index < length) { |
| 1545 RETURN_FAILURE_ON_EXCEPTION(isolate, |
| 1546 SetLastIndex(isolate, splitter, string_index)); |
| 1547 |
| 1548 Handle<Object> result; |
| 1549 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1550 isolate, result, |
| 1551 RegExpExec(isolate, splitter, string, factory->undefined_value())); |
| 1552 |
| 1553 if (result->IsNull(isolate)) { |
| 1554 string_index += |
| 1555 AdvanceStringIndex(isolate, string, string_index, unicode); |
| 1556 continue; |
| 1557 } |
| 1558 |
| 1559 // TODO(jgruber): Extract toLength of some property into function. |
| 1560 Handle<Object> last_index_obj; |
| 1561 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, last_index_obj, |
| 1562 GetLastIndex(isolate, splitter)); |
| 1563 |
| 1564 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1565 isolate, last_index_obj, Object::ToLength(isolate, last_index_obj)); |
| 1566 const int last_index = Handle<Smi>::cast(last_index_obj)->value(); |
| 1567 |
| 1568 const int end = std::min(last_index, length); |
| 1569 if (end == prev_string_index) { |
| 1570 string_index += |
| 1571 AdvanceStringIndex(isolate, string, string_index, unicode); |
| 1572 continue; |
| 1573 } |
| 1574 |
| 1575 { |
| 1576 Handle<String> substr = |
| 1577 factory->NewSubString(string, prev_string_index, string_index); |
| 1578 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1579 if (num_elems == limit) { |
| 1580 return *NewJSArrayWithElements(isolate, elems, num_elems); |
| 1581 } |
| 1582 } |
| 1583 |
| 1584 prev_string_index = end; |
| 1585 |
| 1586 Handle<Object> num_captures_obj; |
| 1587 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1588 isolate, num_captures_obj, |
| 1589 Object::GetProperty(result, isolate->factory()->length_string())); |
| 1590 |
| 1591 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1592 isolate, num_captures_obj, Object::ToLength(isolate, num_captures_obj)); |
| 1593 const int num_captures = |
| 1594 std::max(Handle<Smi>::cast(num_captures_obj)->value(), 0); |
| 1595 |
| 1596 for (int i = 1; i < num_captures; i++) { |
| 1597 Handle<Object> capture; |
| 1598 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1599 isolate, capture, Object::GetElement(isolate, result, i)); |
| 1600 elems = FixedArray::SetAndGrow(elems, num_elems++, capture); |
| 1601 if (num_elems == limit) { |
| 1602 return *NewJSArrayWithElements(isolate, elems, num_elems); |
| 1603 } |
| 1604 } |
| 1605 |
| 1606 string_index = prev_string_index; |
| 1607 } |
| 1608 |
| 1609 { |
| 1610 Handle<String> substr = |
| 1611 factory->NewSubString(string, prev_string_index, length); |
| 1612 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1613 } |
| 1614 |
| 1615 return *NewJSArrayWithElements(isolate, elems, num_elems); |
| 1616 } |
| 1617 |
1238 } // namespace internal | 1618 } // namespace internal |
1239 } // namespace v8 | 1619 } // namespace v8 |
OLD | NEW |