| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 951 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 return *target; | 962 return *target; |
| 963 } | 963 } |
| 964 | 964 |
| 965 | 965 |
| 966 static Object* CharCodeAt(String* subject, Object* index) { | 966 static Object* CharCodeAt(String* subject, Object* index) { |
| 967 uint32_t i = 0; | 967 uint32_t i = 0; |
| 968 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); | 968 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); |
| 969 // Flatten the string. If someone wants to get a char at an index | 969 // Flatten the string. If someone wants to get a char at an index |
| 970 // in a cons string, it is likely that more indices will be | 970 // in a cons string, it is likely that more indices will be |
| 971 // accessed. | 971 // accessed. |
| 972 subject->TryFlatten(); | 972 StringShape shape(subject); |
| 973 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value(); | 973 subject->TryFlatten(shape); // shape no longer valid! |
| 974 return Smi::FromInt(subject->Get(i)); | 974 if (i >= static_cast<uint32_t>(subject->length(StringShape(subject)))) { |
| 975 return Heap::nan_value(); |
| 976 } |
| 977 return Smi::FromInt(subject->Get(StringShape(subject), i)); |
| 975 } | 978 } |
| 976 | 979 |
| 977 | 980 |
| 978 static Object* Runtime_StringCharCodeAt(Arguments args) { | 981 static Object* Runtime_StringCharCodeAt(Arguments args) { |
| 979 NoHandleAllocation ha; | 982 NoHandleAllocation ha; |
| 980 ASSERT(args.length() == 2); | 983 ASSERT(args.length() == 2); |
| 981 | 984 |
| 982 CONVERT_CHECKED(String, subject, args[0]); | 985 CONVERT_CHECKED(String, subject, args[0]); |
| 983 Object* index = args[1]; | 986 Object* index = args[1]; |
| 984 return CharCodeAt(subject, index); | 987 return CharCodeAt(subject, index); |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 return BoyerMooreIndexOf(sub, pat, idx); | 1347 return BoyerMooreIndexOf(sub, pat, idx); |
| 1345 } | 1348 } |
| 1346 | 1349 |
| 1347 // Perform string match of pattern on subject, starting at start index. | 1350 // Perform string match of pattern on subject, starting at start index. |
| 1348 // Caller must ensure that 0 <= start_index <= sub->length(), | 1351 // Caller must ensure that 0 <= start_index <= sub->length(), |
| 1349 // and should check that pat->length() + start_index <= sub->length() | 1352 // and should check that pat->length() + start_index <= sub->length() |
| 1350 int Runtime::StringMatch(Handle<String> sub, | 1353 int Runtime::StringMatch(Handle<String> sub, |
| 1351 Handle<String> pat, | 1354 Handle<String> pat, |
| 1352 int start_index) { | 1355 int start_index) { |
| 1353 ASSERT(0 <= start_index); | 1356 ASSERT(0 <= start_index); |
| 1354 ASSERT(start_index <= sub->length()); | 1357 StringShape sub_shape(*sub); |
| 1358 StringShape pat_shape(*pat); |
| 1359 ASSERT(start_index <= sub->length(sub_shape)); |
| 1355 | 1360 |
| 1356 int pattern_length = pat->length(); | 1361 int pattern_length = pat->length(pat_shape); |
| 1357 if (pattern_length == 0) return start_index; | 1362 if (pattern_length == 0) return start_index; |
| 1358 | 1363 |
| 1359 int subject_length = sub->length(); | 1364 int subject_length = sub->length(sub_shape); |
| 1360 if (start_index + pattern_length > subject_length) return -1; | 1365 if (start_index + pattern_length > subject_length) return -1; |
| 1361 | 1366 |
| 1362 FlattenString(sub); | 1367 if (!sub->IsFlat(sub_shape)) { |
| 1368 FlattenString(sub); |
| 1369 sub_shape = StringShape(*sub); |
| 1370 } |
| 1363 // Searching for one specific character is common. For one | 1371 // Searching for one specific character is common. For one |
| 1364 // character patterns linear search is necessary, so any smart | 1372 // character patterns linear search is necessary, so any smart |
| 1365 // algorithm is unnecessary overhead. | 1373 // algorithm is unnecessary overhead. |
| 1366 if (pattern_length == 1) { | 1374 if (pattern_length == 1) { |
| 1367 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 1375 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
| 1368 if (sub->is_ascii_representation()) { | 1376 if (sub_shape.IsAsciiRepresentation()) { |
| 1369 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index); | 1377 return SingleCharIndexOf(sub->ToAsciiVector(), |
| 1378 pat->Get(pat_shape, 0), |
| 1379 start_index); |
| 1370 } | 1380 } |
| 1371 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); | 1381 return SingleCharIndexOf(sub->ToUC16Vector(), |
| 1382 pat->Get(pat_shape, 0), |
| 1383 start_index); |
| 1372 } | 1384 } |
| 1373 | 1385 |
| 1374 FlattenString(pat); | 1386 if (!pat->IsFlat(pat_shape)) { |
| 1387 FlattenString(pat); |
| 1388 pat_shape = StringShape(*pat); |
| 1389 } |
| 1375 | 1390 |
| 1376 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 1391 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
| 1377 // dispatch on type of strings | 1392 // dispatch on type of strings |
| 1378 if (pat->is_ascii_representation()) { | 1393 if (pat_shape.IsAsciiRepresentation()) { |
| 1379 Vector<const char> pat_vector = pat->ToAsciiVector(); | 1394 Vector<const char> pat_vector = pat->ToAsciiVector(); |
| 1380 if (sub->is_ascii_representation()) { | 1395 if (sub_shape.IsAsciiRepresentation()) { |
| 1381 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 1396 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
| 1382 } | 1397 } |
| 1383 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 1398 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
| 1384 } | 1399 } |
| 1385 Vector<const uc16> pat_vector = pat->ToUC16Vector(); | 1400 Vector<const uc16> pat_vector = pat->ToUC16Vector(); |
| 1386 if (sub->is_ascii_representation()) { | 1401 if (sub_shape.IsAsciiRepresentation()) { |
| 1387 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 1402 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
| 1388 } | 1403 } |
| 1389 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 1404 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
| 1390 } | 1405 } |
| 1391 | 1406 |
| 1392 | 1407 |
| 1393 static Object* Runtime_StringIndexOf(Arguments args) { | 1408 static Object* Runtime_StringIndexOf(Arguments args) { |
| 1394 HandleScope scope; // create a new handle scope | 1409 HandleScope scope; // create a new handle scope |
| 1395 ASSERT(args.length() == 3); | 1410 ASSERT(args.length() == 3); |
| 1396 | 1411 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1408 | 1423 |
| 1409 | 1424 |
| 1410 static Object* Runtime_StringLastIndexOf(Arguments args) { | 1425 static Object* Runtime_StringLastIndexOf(Arguments args) { |
| 1411 NoHandleAllocation ha; | 1426 NoHandleAllocation ha; |
| 1412 ASSERT(args.length() == 3); | 1427 ASSERT(args.length() == 3); |
| 1413 | 1428 |
| 1414 CONVERT_CHECKED(String, sub, args[0]); | 1429 CONVERT_CHECKED(String, sub, args[0]); |
| 1415 CONVERT_CHECKED(String, pat, args[1]); | 1430 CONVERT_CHECKED(String, pat, args[1]); |
| 1416 Object* index = args[2]; | 1431 Object* index = args[2]; |
| 1417 | 1432 |
| 1418 sub->TryFlatten(); | 1433 sub->TryFlatten(StringShape(sub)); |
| 1419 pat->TryFlatten(); | 1434 pat->TryFlatten(StringShape(pat)); |
| 1435 |
| 1436 StringShape sub_shape(sub); |
| 1437 StringShape pat_shape(pat); |
| 1420 | 1438 |
| 1421 uint32_t start_index; | 1439 uint32_t start_index; |
| 1422 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); | 1440 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); |
| 1423 | 1441 |
| 1424 uint32_t pattern_length = pat->length(); | 1442 uint32_t pattern_length = pat->length(pat_shape); |
| 1425 uint32_t sub_length = sub->length(); | 1443 uint32_t sub_length = sub->length(sub_shape); |
| 1426 | 1444 |
| 1427 if (start_index + pattern_length > sub_length) { | 1445 if (start_index + pattern_length > sub_length) { |
| 1428 start_index = sub_length - pattern_length; | 1446 start_index = sub_length - pattern_length; |
| 1429 } | 1447 } |
| 1430 | 1448 |
| 1431 for (int i = start_index; i >= 0; i--) { | 1449 for (int i = start_index; i >= 0; i--) { |
| 1432 bool found = true; | 1450 bool found = true; |
| 1433 for (uint32_t j = 0; j < pattern_length; j++) { | 1451 for (uint32_t j = 0; j < pattern_length; j++) { |
| 1434 if (sub->Get(i + j) != pat->Get(j)) { | 1452 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) { |
| 1435 found = false; | 1453 found = false; |
| 1436 break; | 1454 break; |
| 1437 } | 1455 } |
| 1438 } | 1456 } |
| 1439 if (found) return Smi::FromInt(i); | 1457 if (found) return Smi::FromInt(i); |
| 1440 } | 1458 } |
| 1441 | 1459 |
| 1442 return Smi::FromInt(-1); | 1460 return Smi::FromInt(-1); |
| 1443 } | 1461 } |
| 1444 | 1462 |
| 1445 | 1463 |
| 1446 static Object* Runtime_StringLocaleCompare(Arguments args) { | 1464 static Object* Runtime_StringLocaleCompare(Arguments args) { |
| 1447 NoHandleAllocation ha; | 1465 NoHandleAllocation ha; |
| 1448 ASSERT(args.length() == 2); | 1466 ASSERT(args.length() == 2); |
| 1449 | 1467 |
| 1450 CONVERT_CHECKED(String, str1, args[0]); | 1468 CONVERT_CHECKED(String, str1, args[0]); |
| 1451 CONVERT_CHECKED(String, str2, args[1]); | 1469 CONVERT_CHECKED(String, str2, args[1]); |
| 1452 | 1470 |
| 1453 if (str1 == str2) return Smi::FromInt(0); // Equal. | 1471 if (str1 == str2) return Smi::FromInt(0); // Equal. |
| 1454 int str1_length = str1->length(); | 1472 StringShape shape1(str1); |
| 1455 int str2_length = str2->length(); | 1473 StringShape shape2(str2); |
| 1474 int str1_length = str1->length(shape1); |
| 1475 int str2_length = str2->length(shape2); |
| 1456 | 1476 |
| 1457 // Decide trivial cases without flattening. | 1477 // Decide trivial cases without flattening. |
| 1458 if (str1_length == 0) { | 1478 if (str1_length == 0) { |
| 1459 if (str2_length == 0) return Smi::FromInt(0); // Equal. | 1479 if (str2_length == 0) return Smi::FromInt(0); // Equal. |
| 1460 return Smi::FromInt(-str2_length); | 1480 return Smi::FromInt(-str2_length); |
| 1461 } else { | 1481 } else { |
| 1462 if (str2_length == 0) return Smi::FromInt(str1_length); | 1482 if (str2_length == 0) return Smi::FromInt(str1_length); |
| 1463 } | 1483 } |
| 1464 | 1484 |
| 1465 int end = str1_length < str2_length ? str1_length : str2_length; | 1485 int end = str1_length < str2_length ? str1_length : str2_length; |
| 1466 | 1486 |
| 1467 // No need to flatten if we are going to find the answer on the first | 1487 // No need to flatten if we are going to find the answer on the first |
| 1468 // character. At this point we know there is at least one character | 1488 // character. At this point we know there is at least one character |
| 1469 // in each string, due to the trivial case handling above. | 1489 // in each string, due to the trivial case handling above. |
| 1470 int d = str1->Get(0) - str2->Get(0); | 1490 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0); |
| 1471 if (d != 0) return Smi::FromInt(d); | 1491 if (d != 0) return Smi::FromInt(d); |
| 1472 | 1492 |
| 1473 str1->TryFlatten(); | 1493 str1->TryFlatten(shape1); // Shapes are no longer valid now! |
| 1474 str2->TryFlatten(); | 1494 str2->TryFlatten(shape2); |
| 1475 | 1495 |
| 1476 static StringInputBuffer buf1; | 1496 static StringInputBuffer buf1; |
| 1477 static StringInputBuffer buf2; | 1497 static StringInputBuffer buf2; |
| 1478 | 1498 |
| 1479 buf1.Reset(str1); | 1499 buf1.Reset(str1); |
| 1480 buf2.Reset(str2); | 1500 buf2.Reset(str2); |
| 1481 | 1501 |
| 1482 for (int i = 0; i < end; i++) { | 1502 for (int i = 0; i < end; i++) { |
| 1483 uint16_t char1 = buf1.GetNext(); | 1503 uint16_t char1 = buf1.GetNext(); |
| 1484 uint16_t char2 = buf2.GetNext(); | 1504 uint16_t char2 = buf2.GetNext(); |
| 1485 if (char1 != char2) return Smi::FromInt(char1 - char2); | 1505 if (char1 != char2) return Smi::FromInt(char1 - char2); |
| 1486 } | 1506 } |
| 1487 | 1507 |
| 1488 return Smi::FromInt(str1_length - str2_length); | 1508 return Smi::FromInt(str1_length - str2_length); |
| 1489 } | 1509 } |
| 1490 | 1510 |
| 1491 | 1511 |
| 1492 static Object* Runtime_StringSlice(Arguments args) { | 1512 static Object* Runtime_StringSlice(Arguments args) { |
| 1493 NoHandleAllocation ha; | 1513 NoHandleAllocation ha; |
| 1494 ASSERT(args.length() == 3); | 1514 ASSERT(args.length() == 3); |
| 1495 | 1515 |
| 1496 CONVERT_CHECKED(String, value, args[0]); | 1516 CONVERT_CHECKED(String, value, args[0]); |
| 1497 CONVERT_DOUBLE_CHECKED(from_number, args[1]); | 1517 CONVERT_DOUBLE_CHECKED(from_number, args[1]); |
| 1498 CONVERT_DOUBLE_CHECKED(to_number, args[2]); | 1518 CONVERT_DOUBLE_CHECKED(to_number, args[2]); |
| 1499 | 1519 |
| 1500 int start = FastD2I(from_number); | 1520 int start = FastD2I(from_number); |
| 1501 int end = FastD2I(to_number); | 1521 int end = FastD2I(to_number); |
| 1502 | 1522 |
| 1523 StringShape shape(value); |
| 1524 |
| 1503 RUNTIME_ASSERT(end >= start); | 1525 RUNTIME_ASSERT(end >= start); |
| 1504 RUNTIME_ASSERT(start >= 0); | 1526 RUNTIME_ASSERT(start >= 0); |
| 1505 RUNTIME_ASSERT(end <= value->length()); | 1527 RUNTIME_ASSERT(end <= value->length(shape)); |
| 1506 return value->Slice(start, end); | 1528 return value->Slice(shape, start, end); |
| 1507 } | 1529 } |
| 1508 | 1530 |
| 1509 | 1531 |
| 1510 static Object* Runtime_NumberToRadixString(Arguments args) { | 1532 static Object* Runtime_NumberToRadixString(Arguments args) { |
| 1511 NoHandleAllocation ha; | 1533 NoHandleAllocation ha; |
| 1512 ASSERT(args.length() == 2); | 1534 ASSERT(args.length() == 2); |
| 1513 | 1535 |
| 1514 CONVERT_DOUBLE_CHECKED(value, args[0]); | 1536 CONVERT_DOUBLE_CHECKED(value, args[0]); |
| 1515 if (isnan(value)) { | 1537 if (isnan(value)) { |
| 1516 return Heap::AllocateStringFromAscii(CStrVector("NaN")); | 1538 return Heap::AllocateStringFromAscii(CStrVector("NaN")); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1599 char* str = DoubleToPrecisionCString(value, f); | 1621 char* str = DoubleToPrecisionCString(value, f); |
| 1600 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); | 1622 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); |
| 1601 DeleteArray(str); | 1623 DeleteArray(str); |
| 1602 return res; | 1624 return res; |
| 1603 } | 1625 } |
| 1604 | 1626 |
| 1605 | 1627 |
| 1606 // Returns a single character string where first character equals | 1628 // Returns a single character string where first character equals |
| 1607 // string->Get(index). | 1629 // string->Get(index). |
| 1608 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 1630 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
| 1609 if (index < static_cast<uint32_t>(string->length())) { | 1631 StringShape shape(*string); |
| 1610 string->TryFlatten(); | 1632 if (index < static_cast<uint32_t>(string->length(shape))) { |
| 1611 return LookupSingleCharacterStringFromCode(string->Get(index)); | 1633 string->TryFlatten(shape); // Invalidates shape! |
| 1634 return LookupSingleCharacterStringFromCode( |
| 1635 string->Get(StringShape(*string), index)); |
| 1612 } | 1636 } |
| 1613 return Execution::CharAt(string, index); | 1637 return Execution::CharAt(string, index); |
| 1614 } | 1638 } |
| 1615 | 1639 |
| 1616 | 1640 |
| 1617 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { | 1641 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { |
| 1618 // Handle [] indexing on Strings | 1642 // Handle [] indexing on Strings |
| 1619 if (object->IsString()) { | 1643 if (object->IsString()) { |
| 1620 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 1644 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
| 1621 if (!result->IsUndefined()) return *result; | 1645 if (!result->IsUndefined()) return *result; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1786 return *value; | 1810 return *value; |
| 1787 } | 1811 } |
| 1788 | 1812 |
| 1789 if (key->IsString()) { | 1813 if (key->IsString()) { |
| 1790 Handle<Object> result; | 1814 Handle<Object> result; |
| 1791 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 1815 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
| 1792 ASSERT(attr == NONE); | 1816 ASSERT(attr == NONE); |
| 1793 result = SetElement(js_object, index, value); | 1817 result = SetElement(js_object, index, value); |
| 1794 } else { | 1818 } else { |
| 1795 Handle<String> key_string = Handle<String>::cast(key); | 1819 Handle<String> key_string = Handle<String>::cast(key); |
| 1796 key_string->TryFlatten(); | 1820 key_string->TryFlatten(StringShape(*key_string)); |
| 1797 result = SetProperty(js_object, key_string, value, attr); | 1821 result = SetProperty(js_object, key_string, value, attr); |
| 1798 } | 1822 } |
| 1799 if (result.is_null()) return Failure::Exception(); | 1823 if (result.is_null()) return Failure::Exception(); |
| 1800 return *value; | 1824 return *value; |
| 1801 } | 1825 } |
| 1802 | 1826 |
| 1803 // Call-back into JavaScript to convert the key to a string. | 1827 // Call-back into JavaScript to convert the key to a string. |
| 1804 bool has_pending_exception = false; | 1828 bool has_pending_exception = false; |
| 1805 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 1829 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
| 1806 if (has_pending_exception) return Failure::Exception(); | 1830 if (has_pending_exception) return Failure::Exception(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1877 | 1901 |
| 1878 // Only JS objects can have properties. | 1902 // Only JS objects can have properties. |
| 1879 if (args[0]->IsJSObject()) { | 1903 if (args[0]->IsJSObject()) { |
| 1880 JSObject* object = JSObject::cast(args[0]); | 1904 JSObject* object = JSObject::cast(args[0]); |
| 1881 if (object->HasLocalProperty(key)) return Heap::true_value(); | 1905 if (object->HasLocalProperty(key)) return Heap::true_value(); |
| 1882 } else if (args[0]->IsString()) { | 1906 } else if (args[0]->IsString()) { |
| 1883 // Well, there is one exception: Handle [] on strings. | 1907 // Well, there is one exception: Handle [] on strings. |
| 1884 uint32_t index; | 1908 uint32_t index; |
| 1885 if (key->AsArrayIndex(&index)) { | 1909 if (key->AsArrayIndex(&index)) { |
| 1886 String* string = String::cast(args[0]); | 1910 String* string = String::cast(args[0]); |
| 1887 if (index < static_cast<uint32_t>(string->length())) | 1911 StringShape shape(string); |
| 1912 if (index < static_cast<uint32_t>(string->length(shape))) |
| 1888 return Heap::true_value(); | 1913 return Heap::true_value(); |
| 1889 } | 1914 } |
| 1890 } | 1915 } |
| 1891 return Heap::false_value(); | 1916 return Heap::false_value(); |
| 1892 } | 1917 } |
| 1893 | 1918 |
| 1894 | 1919 |
| 1895 static Object* Runtime_HasProperty(Arguments args) { | 1920 static Object* Runtime_HasProperty(Arguments args) { |
| 1896 NoHandleAllocation na; | 1921 NoHandleAllocation na; |
| 1897 ASSERT(args.length() == 2); | 1922 ASSERT(args.length() == 2); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1926 ASSERT(args.length() == 2); | 1951 ASSERT(args.length() == 2); |
| 1927 | 1952 |
| 1928 CONVERT_CHECKED(JSObject, object, args[0]); | 1953 CONVERT_CHECKED(JSObject, object, args[0]); |
| 1929 CONVERT_CHECKED(String, key, args[1]); | 1954 CONVERT_CHECKED(String, key, args[1]); |
| 1930 | 1955 |
| 1931 uint32_t index; | 1956 uint32_t index; |
| 1932 if (key->AsArrayIndex(&index)) { | 1957 if (key->AsArrayIndex(&index)) { |
| 1933 return Heap::ToBoolean(object->HasElement(index)); | 1958 return Heap::ToBoolean(object->HasElement(index)); |
| 1934 } | 1959 } |
| 1935 | 1960 |
| 1936 LookupResult result; | 1961 PropertyAttributes att = object->GetLocalPropertyAttribute(key); |
| 1937 object->LocalLookup(key, &result); | 1962 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); |
| 1938 if (!result.IsProperty()) return Heap::false_value(); | |
| 1939 return Heap::ToBoolean(!result.IsDontEnum()); | |
| 1940 } | 1963 } |
| 1941 | 1964 |
| 1942 | 1965 |
| 1943 static Object* Runtime_GetPropertyNames(Arguments args) { | 1966 static Object* Runtime_GetPropertyNames(Arguments args) { |
| 1944 HandleScope scope; | 1967 HandleScope scope; |
| 1945 ASSERT(args.length() == 1); | 1968 ASSERT(args.length() == 1); |
| 1946 | 1969 |
| 1947 CONVERT_CHECKED(JSObject, raw_object, args[0]); | 1970 CONVERT_CHECKED(JSObject, raw_object, args[0]); |
| 1948 Handle<JSObject> object(raw_object); | 1971 Handle<JSObject> object(raw_object); |
| 1949 return *GetKeysFor(object); | 1972 return *GetKeysFor(object); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2060 // host objects gives that it is okay to return "object" | 2083 // host objects gives that it is okay to return "object" |
| 2061 return Heap::object_symbol(); | 2084 return Heap::object_symbol(); |
| 2062 } | 2085 } |
| 2063 } | 2086 } |
| 2064 | 2087 |
| 2065 | 2088 |
| 2066 static Object* Runtime_StringToNumber(Arguments args) { | 2089 static Object* Runtime_StringToNumber(Arguments args) { |
| 2067 NoHandleAllocation ha; | 2090 NoHandleAllocation ha; |
| 2068 ASSERT(args.length() == 1); | 2091 ASSERT(args.length() == 1); |
| 2069 CONVERT_CHECKED(String, subject, args[0]); | 2092 CONVERT_CHECKED(String, subject, args[0]); |
| 2070 subject->TryFlatten(); | 2093 subject->TryFlatten(StringShape(subject)); |
| 2071 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); | 2094 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); |
| 2072 } | 2095 } |
| 2073 | 2096 |
| 2074 | 2097 |
| 2075 static Object* Runtime_StringFromCharCodeArray(Arguments args) { | 2098 static Object* Runtime_StringFromCharCodeArray(Arguments args) { |
| 2076 NoHandleAllocation ha; | 2099 NoHandleAllocation ha; |
| 2077 ASSERT(args.length() == 1); | 2100 ASSERT(args.length() == 1); |
| 2078 | 2101 |
| 2079 CONVERT_CHECKED(JSArray, codes, args[0]); | 2102 CONVERT_CHECKED(JSArray, codes, args[0]); |
| 2080 int length = Smi::cast(codes->length())->value(); | 2103 int length = Smi::cast(codes->length())->value(); |
| 2081 | 2104 |
| 2082 // Check if the string can be ASCII. | 2105 // Check if the string can be ASCII. |
| 2083 int i; | 2106 int i; |
| 2084 for (i = 0; i < length; i++) { | 2107 for (i = 0; i < length; i++) { |
| 2085 Object* element = codes->GetElement(i); | 2108 Object* element = codes->GetElement(i); |
| 2086 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2109 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
| 2087 if ((chr & 0xffff) > String::kMaxAsciiCharCode) | 2110 if ((chr & 0xffff) > String::kMaxAsciiCharCode) |
| 2088 break; | 2111 break; |
| 2089 } | 2112 } |
| 2090 | 2113 |
| 2091 Object* object = NULL; | 2114 Object* object = NULL; |
| 2092 if (i == length) { // The string is ASCII. | 2115 if (i == length) { // The string is ASCII. |
| 2093 object = Heap::AllocateRawAsciiString(length); | 2116 object = Heap::AllocateRawAsciiString(length); |
| 2094 } else { // The string is not ASCII. | 2117 } else { // The string is not ASCII. |
| 2095 object = Heap::AllocateRawTwoByteString(length); | 2118 object = Heap::AllocateRawTwoByteString(length); |
| 2096 } | 2119 } |
| 2097 | 2120 |
| 2098 if (object->IsFailure()) return object; | 2121 if (object->IsFailure()) return object; |
| 2099 String* result = String::cast(object); | 2122 String* result = String::cast(object); |
| 2123 StringShape result_shape(result); |
| 2100 for (int i = 0; i < length; i++) { | 2124 for (int i = 0; i < length; i++) { |
| 2101 Object* element = codes->GetElement(i); | 2125 Object* element = codes->GetElement(i); |
| 2102 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2126 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
| 2103 result->Set(i, chr & 0xffff); | 2127 result->Set(result_shape, i, chr & 0xffff); |
| 2104 } | 2128 } |
| 2105 return result; | 2129 return result; |
| 2106 } | 2130 } |
| 2107 | 2131 |
| 2108 | 2132 |
| 2109 // kNotEscaped is generated by the following: | 2133 // kNotEscaped is generated by the following: |
| 2110 // | 2134 // |
| 2111 // #!/bin/perl | 2135 // #!/bin/perl |
| 2112 // for (my $i = 0; $i < 256; $i++) { | 2136 // for (my $i = 0; $i < 256; $i++) { |
| 2113 // print "\n" if $i % 16 == 0; | 2137 // print "\n" if $i % 16 == 0; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2142 return kNotEscaped[character] != 0; | 2166 return kNotEscaped[character] != 0; |
| 2143 } | 2167 } |
| 2144 | 2168 |
| 2145 | 2169 |
| 2146 static Object* Runtime_URIEscape(Arguments args) { | 2170 static Object* Runtime_URIEscape(Arguments args) { |
| 2147 const char hex_chars[] = "0123456789ABCDEF"; | 2171 const char hex_chars[] = "0123456789ABCDEF"; |
| 2148 NoHandleAllocation ha; | 2172 NoHandleAllocation ha; |
| 2149 ASSERT(args.length() == 1); | 2173 ASSERT(args.length() == 1); |
| 2150 CONVERT_CHECKED(String, source, args[0]); | 2174 CONVERT_CHECKED(String, source, args[0]); |
| 2151 | 2175 |
| 2152 source->TryFlatten(); | 2176 source->TryFlatten(StringShape(source)); |
| 2153 | 2177 |
| 2154 int escaped_length = 0; | 2178 int escaped_length = 0; |
| 2155 int length = source->length(); | 2179 int length = source->length(); |
| 2156 { | 2180 { |
| 2157 Access<StringInputBuffer> buffer(&string_input_buffer); | 2181 Access<StringInputBuffer> buffer(&string_input_buffer); |
| 2158 buffer->Reset(source); | 2182 buffer->Reset(source); |
| 2159 while (buffer->has_more()) { | 2183 while (buffer->has_more()) { |
| 2160 uint16_t character = buffer->GetNext(); | 2184 uint16_t character = buffer->GetNext(); |
| 2161 if (character >= 256) { | 2185 if (character >= 256) { |
| 2162 escaped_length += 6; | 2186 escaped_length += 6; |
| 2163 } else if (IsNotEscaped(character)) { | 2187 } else if (IsNotEscaped(character)) { |
| 2164 escaped_length++; | 2188 escaped_length++; |
| 2165 } else { | 2189 } else { |
| 2166 escaped_length += 3; | 2190 escaped_length += 3; |
| 2167 } | 2191 } |
| 2168 // We don't allow strings that are longer than Smi range. | 2192 // We don't allow strings that are longer than Smi range. |
| 2169 if (!Smi::IsValid(escaped_length)) { | 2193 if (!Smi::IsValid(escaped_length)) { |
| 2170 Top::context()->mark_out_of_memory(); | 2194 Top::context()->mark_out_of_memory(); |
| 2171 return Failure::OutOfMemoryException(); | 2195 return Failure::OutOfMemoryException(); |
| 2172 } | 2196 } |
| 2173 } | 2197 } |
| 2174 } | 2198 } |
| 2175 // No length change implies no change. Return original string if no change. | 2199 // No length change implies no change. Return original string if no change. |
| 2176 if (escaped_length == length) { | 2200 if (escaped_length == length) { |
| 2177 return source; | 2201 return source; |
| 2178 } | 2202 } |
| 2179 Object* o = Heap::AllocateRawAsciiString(escaped_length); | 2203 Object* o = Heap::AllocateRawAsciiString(escaped_length); |
| 2180 if (o->IsFailure()) return o; | 2204 if (o->IsFailure()) return o; |
| 2181 String* destination = String::cast(o); | 2205 String* destination = String::cast(o); |
| 2206 StringShape dshape(destination); |
| 2182 int dest_position = 0; | 2207 int dest_position = 0; |
| 2183 | 2208 |
| 2184 Access<StringInputBuffer> buffer(&string_input_buffer); | 2209 Access<StringInputBuffer> buffer(&string_input_buffer); |
| 2185 buffer->Rewind(); | 2210 buffer->Rewind(); |
| 2186 while (buffer->has_more()) { | 2211 while (buffer->has_more()) { |
| 2187 uint16_t character = buffer->GetNext(); | 2212 uint16_t chr = buffer->GetNext(); |
| 2188 if (character >= 256) { | 2213 if (chr >= 256) { |
| 2189 destination->Set(dest_position, '%'); | 2214 destination->Set(dshape, dest_position, '%'); |
| 2190 destination->Set(dest_position+1, 'u'); | 2215 destination->Set(dshape, dest_position+1, 'u'); |
| 2191 destination->Set(dest_position+2, hex_chars[character >> 12]); | 2216 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]); |
| 2192 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]); | 2217 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
| 2193 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]); | 2218 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
| 2194 destination->Set(dest_position+5, hex_chars[character & 0xf]); | 2219 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]); |
| 2195 dest_position += 6; | 2220 dest_position += 6; |
| 2196 } else if (IsNotEscaped(character)) { | 2221 } else if (IsNotEscaped(chr)) { |
| 2197 destination->Set(dest_position, character); | 2222 destination->Set(dshape, dest_position, chr); |
| 2198 dest_position++; | 2223 dest_position++; |
| 2199 } else { | 2224 } else { |
| 2200 destination->Set(dest_position, '%'); | 2225 destination->Set(dshape, dest_position, '%'); |
| 2201 destination->Set(dest_position+1, hex_chars[character >> 4]); | 2226 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]); |
| 2202 destination->Set(dest_position+2, hex_chars[character & 0xf]); | 2227 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]); |
| 2203 dest_position += 3; | 2228 dest_position += 3; |
| 2204 } | 2229 } |
| 2205 } | 2230 } |
| 2206 return destination; | 2231 return destination; |
| 2207 } | 2232 } |
| 2208 | 2233 |
| 2209 | 2234 |
| 2210 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { | 2235 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { |
| 2211 static const signed char kHexValue['g'] = { | 2236 static const signed char kHexValue['g'] = { |
| 2212 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2237 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 2213 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2238 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 2214 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2239 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 2215 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, | 2240 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
| 2216 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2241 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 2217 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2242 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 2218 -1, 10, 11, 12, 13, 14, 15 }; | 2243 -1, 10, 11, 12, 13, 14, 15 }; |
| 2219 | 2244 |
| 2220 if (character1 > 'f') return -1; | 2245 if (character1 > 'f') return -1; |
| 2221 int hi = kHexValue[character1]; | 2246 int hi = kHexValue[character1]; |
| 2222 if (hi == -1) return -1; | 2247 if (hi == -1) return -1; |
| 2223 if (character2 > 'f') return -1; | 2248 if (character2 > 'f') return -1; |
| 2224 int lo = kHexValue[character2]; | 2249 int lo = kHexValue[character2]; |
| 2225 if (lo == -1) return -1; | 2250 if (lo == -1) return -1; |
| 2226 return (hi << 4) + lo; | 2251 return (hi << 4) + lo; |
| 2227 } | 2252 } |
| 2228 | 2253 |
| 2229 | 2254 |
| 2230 static inline int Unescape(String* source, int i, int length, int* step) { | 2255 static inline int Unescape(String* source, |
| 2231 uint16_t character = source->Get(i); | 2256 StringShape shape, |
| 2232 int32_t hi, lo; | 2257 int i, |
| 2258 int length, |
| 2259 int* step) { |
| 2260 uint16_t character = source->Get(shape, i); |
| 2261 int32_t hi = 0; |
| 2262 int32_t lo = 0; |
| 2233 if (character == '%' && | 2263 if (character == '%' && |
| 2234 i <= length - 6 && | 2264 i <= length - 6 && |
| 2235 source->Get(i + 1) == 'u' && | 2265 source->Get(shape, i + 1) == 'u' && |
| 2236 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 && | 2266 (hi = TwoDigitHex(source->Get(shape, i + 2), |
| 2237 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) { | 2267 source->Get(shape, i + 3))) != -1 && |
| 2268 (lo = TwoDigitHex(source->Get(shape, i + 4), |
| 2269 source->Get(shape, i + 5))) != -1) { |
| 2238 *step = 6; | 2270 *step = 6; |
| 2239 return (hi << 8) + lo; | 2271 return (hi << 8) + lo; |
| 2240 } else if (character == '%' && | 2272 } else if (character == '%' && |
| 2241 i <= length - 3 && | 2273 i <= length - 3 && |
| 2242 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) { | 2274 (lo = TwoDigitHex(source->Get(shape, i + 1), |
| 2275 source->Get(shape, i + 2))) != -1) { |
| 2243 *step = 3; | 2276 *step = 3; |
| 2244 return lo; | 2277 return lo; |
| 2245 } else { | 2278 } else { |
| 2246 *step = 1; | 2279 *step = 1; |
| 2247 return character; | 2280 return character; |
| 2248 } | 2281 } |
| 2249 } | 2282 } |
| 2250 | 2283 |
| 2251 | 2284 |
| 2252 static Object* Runtime_URIUnescape(Arguments args) { | 2285 static Object* Runtime_URIUnescape(Arguments args) { |
| 2253 NoHandleAllocation ha; | 2286 NoHandleAllocation ha; |
| 2254 ASSERT(args.length() == 1); | 2287 ASSERT(args.length() == 1); |
| 2255 CONVERT_CHECKED(String, source, args[0]); | 2288 CONVERT_CHECKED(String, source, args[0]); |
| 2256 | 2289 |
| 2257 source->TryFlatten(); | 2290 source->TryFlatten(StringShape(source)); |
| 2291 StringShape source_shape(source); |
| 2258 | 2292 |
| 2259 bool ascii = true; | 2293 bool ascii = true; |
| 2260 int length = source->length(); | 2294 int length = source->length(source_shape); |
| 2261 | 2295 |
| 2262 int unescaped_length = 0; | 2296 int unescaped_length = 0; |
| 2263 for (int i = 0; i < length; unescaped_length++) { | 2297 for (int i = 0; i < length; unescaped_length++) { |
| 2264 int step; | 2298 int step; |
| 2265 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) | 2299 if (Unescape(source, |
| 2300 source_shape, |
| 2301 i, |
| 2302 length, |
| 2303 &step) > |
| 2304 String::kMaxAsciiCharCode) |
| 2266 ascii = false; | 2305 ascii = false; |
| 2267 i += step; | 2306 i += step; |
| 2268 } | 2307 } |
| 2269 | 2308 |
| 2270 // No length change implies no change. Return original string if no change. | 2309 // No length change implies no change. Return original string if no change. |
| 2271 if (unescaped_length == length) | 2310 if (unescaped_length == length) |
| 2272 return source; | 2311 return source; |
| 2273 | 2312 |
| 2274 Object* o = ascii ? | 2313 Object* o = ascii ? |
| 2275 Heap::AllocateRawAsciiString(unescaped_length) : | 2314 Heap::AllocateRawAsciiString(unescaped_length) : |
| 2276 Heap::AllocateRawTwoByteString(unescaped_length); | 2315 Heap::AllocateRawTwoByteString(unescaped_length); |
| 2277 if (o->IsFailure()) return o; | 2316 if (o->IsFailure()) return o; |
| 2278 String* destination = String::cast(o); | 2317 String* destination = String::cast(o); |
| 2318 StringShape destination_shape(destination); |
| 2279 | 2319 |
| 2280 int dest_position = 0; | 2320 int dest_position = 0; |
| 2281 for (int i = 0; i < length; dest_position++) { | 2321 for (int i = 0; i < length; dest_position++) { |
| 2282 int step; | 2322 int step; |
| 2283 destination->Set(dest_position, Unescape(source, i, length, &step)); | 2323 destination->Set(destination_shape, |
| 2324 dest_position, |
| 2325 Unescape(source, source_shape, i, length, &step)); |
| 2284 i += step; | 2326 i += step; |
| 2285 } | 2327 } |
| 2286 return destination; | 2328 return destination; |
| 2287 } | 2329 } |
| 2288 | 2330 |
| 2289 | 2331 |
| 2290 static Object* Runtime_StringParseInt(Arguments args) { | 2332 static Object* Runtime_StringParseInt(Arguments args) { |
| 2291 NoHandleAllocation ha; | 2333 NoHandleAllocation ha; |
| 2292 | 2334 |
| 2293 CONVERT_CHECKED(String, s, args[0]); | 2335 CONVERT_CHECKED(String, s, args[0]); |
| 2294 CONVERT_DOUBLE_CHECKED(n, args[1]); | 2336 CONVERT_DOUBLE_CHECKED(n, args[1]); |
| 2295 int radix = FastD2I(n); | 2337 int radix = FastD2I(n); |
| 2296 | 2338 |
| 2297 s->TryFlatten(); | 2339 s->TryFlatten(StringShape(s)); |
| 2298 | 2340 |
| 2299 int len = s->length(); | 2341 StringShape shape(s); |
| 2342 |
| 2343 int len = s->length(shape); |
| 2300 int i; | 2344 int i; |
| 2301 | 2345 |
| 2302 // Skip leading white space. | 2346 // Skip leading white space. |
| 2303 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; | 2347 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ; |
| 2304 if (i == len) return Heap::nan_value(); | 2348 if (i == len) return Heap::nan_value(); |
| 2305 | 2349 |
| 2306 // Compute the sign (default to +). | 2350 // Compute the sign (default to +). |
| 2307 int sign = 1; | 2351 int sign = 1; |
| 2308 if (s->Get(i) == '-') { | 2352 if (s->Get(shape, i) == '-') { |
| 2309 sign = -1; | 2353 sign = -1; |
| 2310 i++; | 2354 i++; |
| 2311 } else if (s->Get(i) == '+') { | 2355 } else if (s->Get(shape, i) == '+') { |
| 2312 i++; | 2356 i++; |
| 2313 } | 2357 } |
| 2314 | 2358 |
| 2315 // Compute the radix if 0. | 2359 // Compute the radix if 0. |
| 2316 if (radix == 0) { | 2360 if (radix == 0) { |
| 2317 radix = 10; | 2361 radix = 10; |
| 2318 if (i < len && s->Get(i) == '0') { | 2362 if (i < len && s->Get(shape, i) == '0') { |
| 2319 radix = 8; | 2363 radix = 8; |
| 2320 if (i + 1 < len) { | 2364 if (i + 1 < len) { |
| 2321 int c = s->Get(i + 1); | 2365 int c = s->Get(shape, i + 1); |
| 2322 if (c == 'x' || c == 'X') { | 2366 if (c == 'x' || c == 'X') { |
| 2323 radix = 16; | 2367 radix = 16; |
| 2324 i += 2; | 2368 i += 2; |
| 2325 } | 2369 } |
| 2326 } | 2370 } |
| 2327 } | 2371 } |
| 2328 } else if (radix == 16) { | 2372 } else if (radix == 16) { |
| 2329 // Allow 0x or 0X prefix if radix is 16. | 2373 // Allow 0x or 0X prefix if radix is 16. |
| 2330 if (i + 1 < len && s->Get(i) == '0') { | 2374 if (i + 1 < len && s->Get(shape, i) == '0') { |
| 2331 int c = s->Get(i + 1); | 2375 int c = s->Get(shape, i + 1); |
| 2332 if (c == 'x' || c == 'X') i += 2; | 2376 if (c == 'x' || c == 'X') i += 2; |
| 2333 } | 2377 } |
| 2334 } | 2378 } |
| 2335 | 2379 |
| 2336 RUNTIME_ASSERT(2 <= radix && radix <= 36); | 2380 RUNTIME_ASSERT(2 <= radix && radix <= 36); |
| 2337 double value; | 2381 double value; |
| 2338 int end_index = StringToInt(s, i, radix, &value); | 2382 int end_index = StringToInt(s, i, radix, &value); |
| 2339 if (end_index != i) { | 2383 if (end_index != i) { |
| 2340 return Heap::NumberFromDouble(sign * value); | 2384 return Heap::NumberFromDouble(sign * value); |
| 2341 } | 2385 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2358 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; | 2402 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; |
| 2359 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; | 2403 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; |
| 2360 | 2404 |
| 2361 | 2405 |
| 2362 template <class Converter> | 2406 template <class Converter> |
| 2363 static Object* ConvertCase(Arguments args, | 2407 static Object* ConvertCase(Arguments args, |
| 2364 unibrow::Mapping<Converter, 128>* mapping) { | 2408 unibrow::Mapping<Converter, 128>* mapping) { |
| 2365 NoHandleAllocation ha; | 2409 NoHandleAllocation ha; |
| 2366 | 2410 |
| 2367 CONVERT_CHECKED(String, s, args[0]); | 2411 CONVERT_CHECKED(String, s, args[0]); |
| 2368 int raw_string_length = s->length(); | 2412 s->TryFlatten(StringShape(s)); |
| 2413 StringShape shape(s); |
| 2414 |
| 2415 int raw_string_length = s->length(shape); |
| 2369 // Assume that the string is not empty; we need this assumption later | 2416 // Assume that the string is not empty; we need this assumption later |
| 2370 if (raw_string_length == 0) return s; | 2417 if (raw_string_length == 0) return s; |
| 2371 int length = raw_string_length; | 2418 int length = raw_string_length; |
| 2372 | 2419 |
| 2373 s->TryFlatten(); | |
| 2374 | 2420 |
| 2375 // We try this twice, once with the assumption that the result is | 2421 // We try this twice, once with the assumption that the result is |
| 2376 // no longer than the input and, if that assumption breaks, again | 2422 // no longer than the input and, if that assumption breaks, again |
| 2377 // with the exact length. This is implemented using a goto back | 2423 // with the exact length. This is implemented using a goto back |
| 2378 // to this label if we discover that the assumption doesn't hold. | 2424 // to this label if we discover that the assumption doesn't hold. |
| 2379 // I apologize sincerely for this and will give a vaffel-is to | 2425 // I apologize sincerely for this and will give a vaffel-is to |
| 2380 // the first person who can implement it in a nicer way. | 2426 // the first person who can implement it in a nicer way. |
| 2381 try_convert: | 2427 try_convert: |
| 2382 | 2428 |
| 2383 // Allocate the resulting string. | 2429 // Allocate the resulting string. |
| 2384 // | 2430 // |
| 2385 // NOTE: This assumes that the upper/lower case of an ascii | 2431 // NOTE: This assumes that the upper/lower case of an ascii |
| 2386 // character is also ascii. This is currently the case, but it | 2432 // character is also ascii. This is currently the case, but it |
| 2387 // might break in the future if we implement more context and locale | 2433 // might break in the future if we implement more context and locale |
| 2388 // dependent upper/lower conversions. | 2434 // dependent upper/lower conversions. |
| 2389 Object* o = s->IsAsciiRepresentation() | 2435 Object* o = shape.IsAsciiRepresentation() |
| 2390 ? Heap::AllocateRawAsciiString(length) | 2436 ? Heap::AllocateRawAsciiString(length) |
| 2391 : Heap::AllocateRawTwoByteString(length); | 2437 : Heap::AllocateRawTwoByteString(length); |
| 2392 if (o->IsFailure()) return o; | 2438 if (o->IsFailure()) return o; |
| 2393 String* result = String::cast(o); | 2439 String* result = String::cast(o); |
| 2440 StringShape result_shape(result); |
| 2394 bool has_changed_character = false; | 2441 bool has_changed_character = false; |
| 2395 | 2442 |
| 2396 // Convert all characters to upper case, assuming that they will fit | 2443 // Convert all characters to upper case, assuming that they will fit |
| 2397 // in the buffer | 2444 // in the buffer |
| 2398 Access<StringInputBuffer> buffer(&string_input_buffer); | 2445 Access<StringInputBuffer> buffer(&string_input_buffer); |
| 2399 buffer->Reset(s); | 2446 buffer->Reset(s); |
| 2400 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize]; | 2447 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize]; |
| 2401 int i = 0; | 2448 int i = 0; |
| 2402 // We can assume that the string is not empty | 2449 // We can assume that the string is not empty |
| 2403 uc32 current = buffer->GetNext(); | 2450 uc32 current = buffer->GetNext(); |
| 2404 while (i < length) { | 2451 while (i < length) { |
| 2405 bool has_next = buffer->has_more(); | 2452 bool has_next = buffer->has_more(); |
| 2406 uc32 next = has_next ? buffer->GetNext() : 0; | 2453 uc32 next = has_next ? buffer->GetNext() : 0; |
| 2407 int char_length = mapping->get(current, next, chars); | 2454 int char_length = mapping->get(current, next, chars); |
| 2408 if (char_length == 0) { | 2455 if (char_length == 0) { |
| 2409 // The case conversion of this character is the character itself. | 2456 // The case conversion of this character is the character itself. |
| 2410 result->Set(i, current); | 2457 result->Set(result_shape, i, current); |
| 2411 i++; | 2458 i++; |
| 2412 } else if (char_length == 1) { | 2459 } else if (char_length == 1) { |
| 2413 // Common case: converting the letter resulted in one character. | 2460 // Common case: converting the letter resulted in one character. |
| 2414 ASSERT(static_cast<uc32>(chars[0]) != current); | 2461 ASSERT(static_cast<uc32>(chars[0]) != current); |
| 2415 result->Set(i, chars[0]); | 2462 result->Set(result_shape, i, chars[0]); |
| 2416 has_changed_character = true; | 2463 has_changed_character = true; |
| 2417 i++; | 2464 i++; |
| 2418 } else if (length == raw_string_length) { | 2465 } else if (length == raw_string_length) { |
| 2419 // We've assumed that the result would be as long as the | 2466 // We've assumed that the result would be as long as the |
| 2420 // input but here is a character that converts to several | 2467 // input but here is a character that converts to several |
| 2421 // characters. No matter, we calculate the exact length | 2468 // characters. No matter, we calculate the exact length |
| 2422 // of the result and try the whole thing again. | 2469 // of the result and try the whole thing again. |
| 2423 // | 2470 // |
| 2424 // Note that this leaves room for optimization. We could just | 2471 // Note that this leaves room for optimization. We could just |
| 2425 // memcpy what we already have to the result string. Also, | 2472 // memcpy what we already have to the result string. Also, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2440 // it does not in any case affect the length of what it convert | 2487 // it does not in any case affect the length of what it convert |
| 2441 // to. | 2488 // to. |
| 2442 int char_length = mapping->get(current, 0, chars); | 2489 int char_length = mapping->get(current, 0, chars); |
| 2443 if (char_length == 0) char_length = 1; | 2490 if (char_length == 0) char_length = 1; |
| 2444 current_length += char_length; | 2491 current_length += char_length; |
| 2445 } | 2492 } |
| 2446 length = current_length; | 2493 length = current_length; |
| 2447 goto try_convert; | 2494 goto try_convert; |
| 2448 } else { | 2495 } else { |
| 2449 for (int j = 0; j < char_length; j++) { | 2496 for (int j = 0; j < char_length; j++) { |
| 2450 result->Set(i, chars[j]); | 2497 result->Set(result_shape, i, chars[j]); |
| 2451 i++; | 2498 i++; |
| 2452 } | 2499 } |
| 2453 has_changed_character = true; | 2500 has_changed_character = true; |
| 2454 } | 2501 } |
| 2455 current = next; | 2502 current = next; |
| 2456 } | 2503 } |
| 2457 if (has_changed_character) { | 2504 if (has_changed_character) { |
| 2458 return result; | 2505 return result; |
| 2459 } else { | 2506 } else { |
| 2460 // If we didn't actually change anything in doing the conversion | 2507 // If we didn't actually change anything in doing the conversion |
| 2461 // we simple return the result and let the converted string | 2508 // we simple return the result and let the converted string |
| 2462 // become garbage; there is no reason to keep two identical strings | 2509 // become garbage; there is no reason to keep two identical strings |
| 2463 // alive. | 2510 // alive. |
| 2464 return s; | 2511 return s; |
| 2465 } | 2512 } |
| 2466 } | 2513 } |
| 2467 | 2514 |
| 2468 | 2515 |
| 2469 static Object* Runtime_StringToLowerCase(Arguments args) { | 2516 static Object* Runtime_StringToLowerCase(Arguments args) { |
| 2470 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); | 2517 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); |
| 2471 } | 2518 } |
| 2472 | 2519 |
| 2473 | 2520 |
| 2474 static Object* Runtime_StringToUpperCase(Arguments args) { | 2521 static Object* Runtime_StringToUpperCase(Arguments args) { |
| 2475 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); | 2522 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); |
| 2476 } | 2523 } |
| 2477 | 2524 |
| 2478 | 2525 |
| 2479 static Object* Runtime_ConsStringFst(Arguments args) { | |
| 2480 NoHandleAllocation ha; | |
| 2481 | |
| 2482 CONVERT_CHECKED(ConsString, str, args[0]); | |
| 2483 return str->first(); | |
| 2484 } | |
| 2485 | |
| 2486 | |
| 2487 static Object* Runtime_ConsStringSnd(Arguments args) { | |
| 2488 NoHandleAllocation ha; | |
| 2489 | |
| 2490 CONVERT_CHECKED(ConsString, str, args[0]); | |
| 2491 return str->second(); | |
| 2492 } | |
| 2493 | |
| 2494 | |
| 2495 static Object* Runtime_NumberToString(Arguments args) { | 2526 static Object* Runtime_NumberToString(Arguments args) { |
| 2496 NoHandleAllocation ha; | 2527 NoHandleAllocation ha; |
| 2497 ASSERT(args.length() == 1); | 2528 ASSERT(args.length() == 1); |
| 2498 | 2529 |
| 2499 Object* number = args[0]; | 2530 Object* number = args[0]; |
| 2500 RUNTIME_ASSERT(number->IsNumber()); | 2531 RUNTIME_ASSERT(number->IsNumber()); |
| 2501 | 2532 |
| 2502 Object* cached = Heap::GetNumberStringCache(number); | 2533 Object* cached = Heap::GetNumberStringCache(number); |
| 2503 if (cached != Heap::undefined_value()) { | 2534 if (cached != Heap::undefined_value()) { |
| 2504 return cached; | 2535 return cached; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2549 NoHandleAllocation ha; | 2580 NoHandleAllocation ha; |
| 2550 ASSERT(args.length() == 1); | 2581 ASSERT(args.length() == 1); |
| 2551 | 2582 |
| 2552 Object* obj = args[0]; | 2583 Object* obj = args[0]; |
| 2553 if (obj->IsSmi()) return obj; | 2584 if (obj->IsSmi()) return obj; |
| 2554 CONVERT_DOUBLE_CHECKED(number, obj); | 2585 CONVERT_DOUBLE_CHECKED(number, obj); |
| 2555 return Heap::NumberFromInt32(DoubleToInt32(number)); | 2586 return Heap::NumberFromInt32(DoubleToInt32(number)); |
| 2556 } | 2587 } |
| 2557 | 2588 |
| 2558 | 2589 |
| 2590 // Converts a Number to a Smi, if possible. Returns NaN if the number is not |
| 2591 // a small integer. |
| 2592 static Object* Runtime_NumberToSmi(Arguments args) { |
| 2593 NoHandleAllocation ha; |
| 2594 ASSERT(args.length() == 1); |
| 2595 |
| 2596 Object* obj = args[0]; |
| 2597 if (obj->IsSmi()) { |
| 2598 return obj; |
| 2599 } |
| 2600 if (obj->IsHeapNumber()) { |
| 2601 double value = HeapNumber::cast(obj)->value(); |
| 2602 int int_value = FastD2I(value); |
| 2603 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { |
| 2604 return Smi::FromInt(int_value); |
| 2605 } |
| 2606 } |
| 2607 return Heap::nan_value(); |
| 2608 } |
| 2609 |
| 2559 static Object* Runtime_NumberAdd(Arguments args) { | 2610 static Object* Runtime_NumberAdd(Arguments args) { |
| 2560 NoHandleAllocation ha; | 2611 NoHandleAllocation ha; |
| 2561 ASSERT(args.length() == 2); | 2612 ASSERT(args.length() == 2); |
| 2562 | 2613 |
| 2563 CONVERT_DOUBLE_CHECKED(x, args[0]); | 2614 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 2564 CONVERT_DOUBLE_CHECKED(y, args[1]); | 2615 CONVERT_DOUBLE_CHECKED(y, args[1]); |
| 2565 return Heap::AllocateHeapNumber(x + y); | 2616 return Heap::AllocateHeapNumber(x + y); |
| 2566 } | 2617 } |
| 2567 | 2618 |
| 2568 | 2619 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2624 return Heap::NewNumberFromDouble(x); | 2675 return Heap::NewNumberFromDouble(x); |
| 2625 } | 2676 } |
| 2626 | 2677 |
| 2627 | 2678 |
| 2628 static Object* Runtime_StringAdd(Arguments args) { | 2679 static Object* Runtime_StringAdd(Arguments args) { |
| 2629 NoHandleAllocation ha; | 2680 NoHandleAllocation ha; |
| 2630 ASSERT(args.length() == 2); | 2681 ASSERT(args.length() == 2); |
| 2631 | 2682 |
| 2632 CONVERT_CHECKED(String, str1, args[0]); | 2683 CONVERT_CHECKED(String, str1, args[0]); |
| 2633 CONVERT_CHECKED(String, str2, args[1]); | 2684 CONVERT_CHECKED(String, str2, args[1]); |
| 2634 int len1 = str1->length(); | 2685 StringShape shape1(str1); |
| 2635 int len2 = str2->length(); | 2686 StringShape shape2(str2); |
| 2687 int len1 = str1->length(shape1); |
| 2688 int len2 = str2->length(shape2); |
| 2636 if (len1 == 0) return str2; | 2689 if (len1 == 0) return str2; |
| 2637 if (len2 == 0) return str1; | 2690 if (len2 == 0) return str1; |
| 2638 int length_sum = len1 + len2; | 2691 int length_sum = len1 + len2; |
| 2639 // Make sure that an out of memory exception is thrown if the length | 2692 // Make sure that an out of memory exception is thrown if the length |
| 2640 // of the new cons string is too large to fit in a Smi. | 2693 // of the new cons string is too large to fit in a Smi. |
| 2641 if (length_sum > Smi::kMaxValue || length_sum < 0) { | 2694 if (length_sum > Smi::kMaxValue || length_sum < 0) { |
| 2642 Top::context()->mark_out_of_memory(); | 2695 Top::context()->mark_out_of_memory(); |
| 2643 return Failure::OutOfMemoryException(); | 2696 return Failure::OutOfMemoryException(); |
| 2644 } | 2697 } |
| 2645 return Heap::AllocateConsString(str1, str2); | 2698 return Heap::AllocateConsString(str1, shape1, str2, shape2); |
| 2646 } | 2699 } |
| 2647 | 2700 |
| 2648 | 2701 |
| 2649 template<typename sinkchar> | 2702 template<typename sinkchar> |
| 2650 static inline void StringBuilderConcatHelper(String* special, | 2703 static inline void StringBuilderConcatHelper(String* special, |
| 2704 StringShape special_shape, |
| 2651 sinkchar* sink, | 2705 sinkchar* sink, |
| 2652 FixedArray* fixed_array, | 2706 FixedArray* fixed_array, |
| 2653 int array_length) { | 2707 int array_length) { |
| 2654 int position = 0; | 2708 int position = 0; |
| 2655 for (int i = 0; i < array_length; i++) { | 2709 for (int i = 0; i < array_length; i++) { |
| 2656 Object* element = fixed_array->get(i); | 2710 Object* element = fixed_array->get(i); |
| 2657 if (element->IsSmi()) { | 2711 if (element->IsSmi()) { |
| 2658 int len = Smi::cast(element)->value(); | 2712 int len = Smi::cast(element)->value(); |
| 2659 int pos = len >> 11; | 2713 int pos = len >> 11; |
| 2660 len &= 0x7ff; | 2714 len &= 0x7ff; |
| 2661 String::WriteToFlat(special, sink + position, pos, pos + len); | 2715 String::WriteToFlat(special, |
| 2716 special_shape, |
| 2717 sink + position, |
| 2718 pos, |
| 2719 pos + len); |
| 2662 position += len; | 2720 position += len; |
| 2663 } else { | 2721 } else { |
| 2664 String* string = String::cast(element); | 2722 String* string = String::cast(element); |
| 2665 int element_length = string->length(); | 2723 StringShape shape(string); |
| 2666 String::WriteToFlat(string, sink + position, 0, element_length); | 2724 int element_length = string->length(shape); |
| 2725 String::WriteToFlat(string, shape, sink + position, 0, element_length); |
| 2667 position += element_length; | 2726 position += element_length; |
| 2668 } | 2727 } |
| 2669 } | 2728 } |
| 2670 } | 2729 } |
| 2671 | 2730 |
| 2672 | 2731 |
| 2673 static Object* Runtime_StringBuilderConcat(Arguments args) { | 2732 static Object* Runtime_StringBuilderConcat(Arguments args) { |
| 2674 NoHandleAllocation ha; | 2733 NoHandleAllocation ha; |
| 2675 ASSERT(args.length() == 2); | 2734 ASSERT(args.length() == 2); |
| 2676 CONVERT_CHECKED(JSArray, array, args[0]); | 2735 CONVERT_CHECKED(JSArray, array, args[0]); |
| 2677 CONVERT_CHECKED(String, special, args[1]); | 2736 CONVERT_CHECKED(String, special, args[1]); |
| 2678 int special_length = special->length(); | 2737 StringShape special_shape(special); |
| 2738 int special_length = special->length(special_shape); |
| 2679 Object* smi_array_length = array->length(); | 2739 Object* smi_array_length = array->length(); |
| 2680 if (!smi_array_length->IsSmi()) { | 2740 if (!smi_array_length->IsSmi()) { |
| 2681 Top::context()->mark_out_of_memory(); | 2741 Top::context()->mark_out_of_memory(); |
| 2682 return Failure::OutOfMemoryException(); | 2742 return Failure::OutOfMemoryException(); |
| 2683 } | 2743 } |
| 2684 int array_length = Smi::cast(smi_array_length)->value(); | 2744 int array_length = Smi::cast(smi_array_length)->value(); |
| 2685 if (!array->HasFastElements()) { | 2745 if (!array->HasFastElements()) { |
| 2686 return Top::Throw(Heap::illegal_argument_symbol()); | 2746 return Top::Throw(Heap::illegal_argument_symbol()); |
| 2687 } | 2747 } |
| 2688 FixedArray* fixed_array = FixedArray::cast(array->elements()); | 2748 FixedArray* fixed_array = FixedArray::cast(array->elements()); |
| 2689 if (fixed_array->length() < array_length) { | 2749 if (fixed_array->length() < array_length) { |
| 2690 array_length = fixed_array->length(); | 2750 array_length = fixed_array->length(); |
| 2691 } | 2751 } |
| 2692 | 2752 |
| 2693 if (array_length == 0) { | 2753 if (array_length == 0) { |
| 2694 return Heap::empty_string(); | 2754 return Heap::empty_string(); |
| 2695 } else if (array_length == 1) { | 2755 } else if (array_length == 1) { |
| 2696 Object* first = fixed_array->get(0); | 2756 Object* first = fixed_array->get(0); |
| 2697 if (first->IsString()) return first; | 2757 if (first->IsString()) return first; |
| 2698 } | 2758 } |
| 2699 | 2759 |
| 2700 bool ascii = special->IsAsciiRepresentation(); | 2760 bool ascii = special_shape.IsAsciiRepresentation(); |
| 2701 int position = 0; | 2761 int position = 0; |
| 2702 for (int i = 0; i < array_length; i++) { | 2762 for (int i = 0; i < array_length; i++) { |
| 2703 Object* elt = fixed_array->get(i); | 2763 Object* elt = fixed_array->get(i); |
| 2704 if (elt->IsSmi()) { | 2764 if (elt->IsSmi()) { |
| 2705 int len = Smi::cast(elt)->value(); | 2765 int len = Smi::cast(elt)->value(); |
| 2706 int pos = len >> 11; | 2766 int pos = len >> 11; |
| 2707 len &= 0x7ff; | 2767 len &= 0x7ff; |
| 2708 if (pos + len > special_length) { | 2768 if (pos + len > special_length) { |
| 2709 return Top::Throw(Heap::illegal_argument_symbol()); | 2769 return Top::Throw(Heap::illegal_argument_symbol()); |
| 2710 } | 2770 } |
| 2711 position += len; | 2771 position += len; |
| 2712 } else if (elt->IsString()) { | 2772 } else if (elt->IsString()) { |
| 2713 String* element = String::cast(elt); | 2773 String* element = String::cast(elt); |
| 2714 int element_length = element->length(); | 2774 StringShape element_shape(element); |
| 2775 int element_length = element->length(element_shape); |
| 2715 if (!Smi::IsValid(element_length + position)) { | 2776 if (!Smi::IsValid(element_length + position)) { |
| 2716 Top::context()->mark_out_of_memory(); | 2777 Top::context()->mark_out_of_memory(); |
| 2717 return Failure::OutOfMemoryException(); | 2778 return Failure::OutOfMemoryException(); |
| 2718 } | 2779 } |
| 2719 position += element_length; | 2780 position += element_length; |
| 2720 if (ascii && !element->IsAsciiRepresentation()) { | 2781 if (ascii && !element_shape.IsAsciiRepresentation()) { |
| 2721 ascii = false; | 2782 ascii = false; |
| 2722 } | 2783 } |
| 2723 } else { | 2784 } else { |
| 2724 return Top::Throw(Heap::illegal_argument_symbol()); | 2785 return Top::Throw(Heap::illegal_argument_symbol()); |
| 2725 } | 2786 } |
| 2726 } | 2787 } |
| 2727 | 2788 |
| 2728 int length = position; | 2789 int length = position; |
| 2729 Object* object; | 2790 Object* object; |
| 2730 | 2791 |
| 2731 if (ascii) { | 2792 if (ascii) { |
| 2732 object = Heap::AllocateRawAsciiString(length); | 2793 object = Heap::AllocateRawAsciiString(length); |
| 2733 if (object->IsFailure()) return object; | 2794 if (object->IsFailure()) return object; |
| 2734 SeqAsciiString* answer = SeqAsciiString::cast(object); | 2795 SeqAsciiString* answer = SeqAsciiString::cast(object); |
| 2735 StringBuilderConcatHelper(special, | 2796 StringBuilderConcatHelper(special, |
| 2797 special_shape, |
| 2736 answer->GetChars(), | 2798 answer->GetChars(), |
| 2737 fixed_array, | 2799 fixed_array, |
| 2738 array_length); | 2800 array_length); |
| 2739 return answer; | 2801 return answer; |
| 2740 } else { | 2802 } else { |
| 2741 object = Heap::AllocateRawTwoByteString(length); | 2803 object = Heap::AllocateRawTwoByteString(length); |
| 2742 if (object->IsFailure()) return object; | 2804 if (object->IsFailure()) return object; |
| 2743 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 2805 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
| 2744 StringBuilderConcatHelper(special, | 2806 StringBuilderConcatHelper(special, |
| 2807 special_shape, |
| 2745 answer->GetChars(), | 2808 answer->GetChars(), |
| 2746 fixed_array, | 2809 fixed_array, |
| 2747 array_length); | 2810 array_length); |
| 2748 return answer; | 2811 return answer; |
| 2749 } | 2812 } |
| 2750 } | 2813 } |
| 2751 | 2814 |
| 2752 | 2815 |
| 2753 static Object* Runtime_NumberOr(Arguments args) { | 2816 static Object* Runtime_NumberOr(Arguments args) { |
| 2754 NoHandleAllocation ha; | 2817 NoHandleAllocation ha; |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2929 } | 2992 } |
| 2930 | 2993 |
| 2931 | 2994 |
| 2932 static Object* Runtime_StringCompare(Arguments args) { | 2995 static Object* Runtime_StringCompare(Arguments args) { |
| 2933 NoHandleAllocation ha; | 2996 NoHandleAllocation ha; |
| 2934 ASSERT(args.length() == 2); | 2997 ASSERT(args.length() == 2); |
| 2935 | 2998 |
| 2936 CONVERT_CHECKED(String, x, args[0]); | 2999 CONVERT_CHECKED(String, x, args[0]); |
| 2937 CONVERT_CHECKED(String, y, args[1]); | 3000 CONVERT_CHECKED(String, y, args[1]); |
| 2938 | 3001 |
| 3002 StringShape x_shape(x); |
| 3003 StringShape y_shape(y); |
| 3004 |
| 2939 // A few fast case tests before we flatten. | 3005 // A few fast case tests before we flatten. |
| 2940 if (x == y) return Smi::FromInt(EQUAL); | 3006 if (x == y) return Smi::FromInt(EQUAL); |
| 2941 if (y->length() == 0) { | 3007 if (y->length(y_shape) == 0) { |
| 2942 if (x->length() == 0) return Smi::FromInt(EQUAL); | 3008 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL); |
| 2943 return Smi::FromInt(GREATER); | 3009 return Smi::FromInt(GREATER); |
| 2944 } else if (x->length() == 0) { | 3010 } else if (x->length(x_shape) == 0) { |
| 2945 return Smi::FromInt(LESS); | 3011 return Smi::FromInt(LESS); |
| 2946 } | 3012 } |
| 2947 | 3013 |
| 2948 int d = x->Get(0) - y->Get(0); | 3014 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0); |
| 2949 if (d < 0) return Smi::FromInt(LESS); | 3015 if (d < 0) return Smi::FromInt(LESS); |
| 2950 else if (d > 0) return Smi::FromInt(GREATER); | 3016 else if (d > 0) return Smi::FromInt(GREATER); |
| 2951 | 3017 |
| 2952 x->TryFlatten(); | 3018 x->TryFlatten(x_shape); // Shapes are no longer valid! |
| 2953 y->TryFlatten(); | 3019 y->TryFlatten(y_shape); |
| 2954 | 3020 |
| 2955 static StringInputBuffer bufx; | 3021 static StringInputBuffer bufx; |
| 2956 static StringInputBuffer bufy; | 3022 static StringInputBuffer bufy; |
| 2957 bufx.Reset(x); | 3023 bufx.Reset(x); |
| 2958 bufy.Reset(y); | 3024 bufy.Reset(y); |
| 2959 while (bufx.has_more() && bufy.has_more()) { | 3025 while (bufx.has_more() && bufy.has_more()) { |
| 2960 int d = bufx.GetNext() - bufy.GetNext(); | 3026 int d = bufx.GetNext() - bufy.GetNext(); |
| 2961 if (d < 0) return Smi::FromInt(LESS); | 3027 if (d < 0) return Smi::FromInt(LESS); |
| 2962 else if (d > 0) return Smi::FromInt(GREATER); | 3028 else if (d > 0) return Smi::FromInt(GREATER); |
| 2963 } | 3029 } |
| (...skipping 2841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5805 } else { | 5871 } else { |
| 5806 // Handle last resort GC and make sure to allow future allocations | 5872 // Handle last resort GC and make sure to allow future allocations |
| 5807 // to grow the heap without causing GCs (if possible). | 5873 // to grow the heap without causing GCs (if possible). |
| 5808 Counters::gc_last_resort_from_js.Increment(); | 5874 Counters::gc_last_resort_from_js.Increment(); |
| 5809 Heap::CollectAllGarbage(); | 5875 Heap::CollectAllGarbage(); |
| 5810 } | 5876 } |
| 5811 } | 5877 } |
| 5812 | 5878 |
| 5813 | 5879 |
| 5814 } } // namespace v8::internal | 5880 } } // namespace v8::internal |
| OLD | NEW |