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 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
945 return *target; | 945 return *target; |
946 } | 946 } |
947 | 947 |
948 | 948 |
949 static Object* CharCodeAt(String* subject, Object* index) { | 949 static Object* CharCodeAt(String* subject, Object* index) { |
950 uint32_t i = 0; | 950 uint32_t i = 0; |
951 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); | 951 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); |
952 // Flatten the string. If someone wants to get a char at an index | 952 // Flatten the string. If someone wants to get a char at an index |
953 // in a cons string, it is likely that more indices will be | 953 // in a cons string, it is likely that more indices will be |
954 // accessed. | 954 // accessed. |
955 subject->TryFlatten(); | 955 StringShape shape(subject); |
956 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value(); | 956 subject->TryFlatten(shape); // shape no longer valid! |
957 return Smi::FromInt(subject->Get(i)); | 957 if (i >= static_cast<uint32_t>(subject->length(StringShape(subject)))) { |
958 return Heap::nan_value(); | |
959 } | |
960 return Smi::FromInt(subject->Get(StringShape(subject), i)); | |
958 } | 961 } |
959 | 962 |
960 | 963 |
961 static Object* Runtime_StringCharCodeAt(Arguments args) { | 964 static Object* Runtime_StringCharCodeAt(Arguments args) { |
962 NoHandleAllocation ha; | 965 NoHandleAllocation ha; |
963 ASSERT(args.length() == 2); | 966 ASSERT(args.length() == 2); |
964 | 967 |
965 CONVERT_CHECKED(String, subject, args[0]); | 968 CONVERT_CHECKED(String, subject, args[0]); |
966 Object* index = args[1]; | 969 Object* index = args[1]; |
967 return CharCodeAt(subject, index); | 970 return CharCodeAt(subject, index); |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1327 return BoyerMooreIndexOf(sub, pat, idx); | 1330 return BoyerMooreIndexOf(sub, pat, idx); |
1328 } | 1331 } |
1329 | 1332 |
1330 // Perform string match of pattern on subject, starting at start index. | 1333 // Perform string match of pattern on subject, starting at start index. |
1331 // Caller must ensure that 0 <= start_index <= sub->length(), | 1334 // Caller must ensure that 0 <= start_index <= sub->length(), |
1332 // and should check that pat->length() + start_index <= sub->length() | 1335 // and should check that pat->length() + start_index <= sub->length() |
1333 int Runtime::StringMatch(Handle<String> sub, | 1336 int Runtime::StringMatch(Handle<String> sub, |
1334 Handle<String> pat, | 1337 Handle<String> pat, |
1335 int start_index) { | 1338 int start_index) { |
1336 ASSERT(0 <= start_index); | 1339 ASSERT(0 <= start_index); |
1337 ASSERT(start_index <= sub->length()); | 1340 StringShape sub_shape(*sub); |
1341 StringShape pat_shape(*pat); | |
1342 ASSERT(start_index <= sub->length(sub_shape)); | |
1338 | 1343 |
1339 int pattern_length = pat->length(); | 1344 int pattern_length = pat->length(pat_shape); |
1340 if (pattern_length == 0) return start_index; | 1345 if (pattern_length == 0) return start_index; |
1341 | 1346 |
1342 int subject_length = sub->length(); | 1347 int subject_length = sub->length(sub_shape); |
1343 if (start_index + pattern_length > subject_length) return -1; | 1348 if (start_index + pattern_length > subject_length) return -1; |
1344 | 1349 |
1345 FlattenString(sub); | 1350 if (!sub->IsFlat(sub_shape)) { |
1351 FlattenString(sub); | |
1352 sub_shape = StringShape(*sub); | |
1353 } | |
1346 // Searching for one specific character is common. For one | 1354 // Searching for one specific character is common. For one |
1347 // character patterns linear search is necessary, so any smart | 1355 // character patterns linear search is necessary, so any smart |
1348 // algorithm is unnecessary overhead. | 1356 // algorithm is unnecessary overhead. |
1349 if (pattern_length == 1) { | 1357 if (pattern_length == 1) { |
1350 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 1358 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
1351 if (sub->is_ascii_representation()) { | 1359 if (sub_shape.IsAsciiRepresentation()) { |
1352 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index); | 1360 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(pat_shape, 0), sta rt_index); |
1353 } | 1361 } |
1354 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); | 1362 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(pat_shape, 0), start_ index); |
1355 } | 1363 } |
1356 | 1364 |
1357 FlattenString(pat); | 1365 if (!pat->IsFlat(pat_shape)) { |
1366 FlattenString(pat); | |
1367 pat_shape = StringShape(*pat); | |
1368 } | |
1358 | 1369 |
1359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 1370 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
1360 // dispatch on type of strings | 1371 // dispatch on type of strings |
1361 if (pat->is_ascii_representation()) { | 1372 if (pat_shape.IsAsciiRepresentation()) { |
1362 Vector<const char> pat_vector = pat->ToAsciiVector(); | 1373 Vector<const char> pat_vector = pat->ToAsciiVector(); |
1363 if (sub->is_ascii_representation()) { | 1374 if (sub_shape.IsAsciiRepresentation()) { |
1364 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 1375 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
1365 } | 1376 } |
1366 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 1377 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
1367 } | 1378 } |
1368 Vector<const uc16> pat_vector = pat->ToUC16Vector(); | 1379 Vector<const uc16> pat_vector = pat->ToUC16Vector(); |
1369 if (sub->is_ascii_representation()) { | 1380 if (sub_shape.IsAsciiRepresentation()) { |
1370 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 1381 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
1371 } | 1382 } |
1372 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 1383 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
1373 } | 1384 } |
1374 | 1385 |
1375 | 1386 |
1376 static Object* Runtime_StringIndexOf(Arguments args) { | 1387 static Object* Runtime_StringIndexOf(Arguments args) { |
1377 HandleScope scope; // create a new handle scope | 1388 HandleScope scope; // create a new handle scope |
1378 ASSERT(args.length() == 3); | 1389 ASSERT(args.length() == 3); |
1379 | 1390 |
(...skipping 10 matching lines...) Expand all Loading... | |
1390 | 1401 |
1391 | 1402 |
1392 static Object* Runtime_StringLastIndexOf(Arguments args) { | 1403 static Object* Runtime_StringLastIndexOf(Arguments args) { |
1393 NoHandleAllocation ha; | 1404 NoHandleAllocation ha; |
1394 ASSERT(args.length() == 3); | 1405 ASSERT(args.length() == 3); |
1395 | 1406 |
1396 CONVERT_CHECKED(String, sub, args[0]); | 1407 CONVERT_CHECKED(String, sub, args[0]); |
1397 CONVERT_CHECKED(String, pat, args[1]); | 1408 CONVERT_CHECKED(String, pat, args[1]); |
1398 Object* index = args[2]; | 1409 Object* index = args[2]; |
1399 | 1410 |
1400 sub->TryFlatten(); | 1411 sub->TryFlatten(StringShape(sub)); |
1401 pat->TryFlatten(); | 1412 pat->TryFlatten(StringShape(pat)); |
1413 | |
1414 StringShape sub_shape(sub); | |
1415 StringShape pat_shape(pat); | |
1402 | 1416 |
1403 uint32_t start_index; | 1417 uint32_t start_index; |
1404 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); | 1418 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); |
1405 | 1419 |
1406 uint32_t pattern_length = pat->length(); | 1420 uint32_t pattern_length = pat->length(pat_shape); |
1407 uint32_t sub_length = sub->length(); | 1421 uint32_t sub_length = sub->length(sub_shape); |
1408 | 1422 |
1409 if (start_index + pattern_length > sub_length) { | 1423 if (start_index + pattern_length > sub_length) { |
1410 start_index = sub_length - pattern_length; | 1424 start_index = sub_length - pattern_length; |
1411 } | 1425 } |
1412 | 1426 |
1413 for (int i = start_index; i >= 0; i--) { | 1427 for (int i = start_index; i >= 0; i--) { |
1414 bool found = true; | 1428 bool found = true; |
1415 for (uint32_t j = 0; j < pattern_length; j++) { | 1429 for (uint32_t j = 0; j < pattern_length; j++) { |
1416 if (sub->Get(i + j) != pat->Get(j)) { | 1430 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) { |
1417 found = false; | 1431 found = false; |
1418 break; | 1432 break; |
1419 } | 1433 } |
1420 } | 1434 } |
1421 if (found) return Smi::FromInt(i); | 1435 if (found) return Smi::FromInt(i); |
1422 } | 1436 } |
1423 | 1437 |
1424 return Smi::FromInt(-1); | 1438 return Smi::FromInt(-1); |
1425 } | 1439 } |
1426 | 1440 |
1427 | 1441 |
1428 static Object* Runtime_StringLocaleCompare(Arguments args) { | 1442 static Object* Runtime_StringLocaleCompare(Arguments args) { |
1429 NoHandleAllocation ha; | 1443 NoHandleAllocation ha; |
1430 ASSERT(args.length() == 2); | 1444 ASSERT(args.length() == 2); |
1431 | 1445 |
1432 CONVERT_CHECKED(String, str1, args[0]); | 1446 CONVERT_CHECKED(String, str1, args[0]); |
1433 CONVERT_CHECKED(String, str2, args[1]); | 1447 CONVERT_CHECKED(String, str2, args[1]); |
1434 | 1448 |
1435 if (str1 == str2) return Smi::FromInt(0); // Equal. | 1449 if (str1 == str2) return Smi::FromInt(0); // Equal. |
1436 int str1_length = str1->length(); | 1450 StringShape shape1(str1); |
1437 int str2_length = str2->length(); | 1451 StringShape shape2(str2); |
1452 int str1_length = str1->length(shape1); | |
1453 int str2_length = str2->length(shape2); | |
1438 | 1454 |
1439 // Decide trivial cases without flattening. | 1455 // Decide trivial cases without flattening. |
1440 if (str1_length == 0) { | 1456 if (str1_length == 0) { |
1441 if (str2_length == 0) return Smi::FromInt(0); // Equal. | 1457 if (str2_length == 0) return Smi::FromInt(0); // Equal. |
1442 return Smi::FromInt(-str2_length); | 1458 return Smi::FromInt(-str2_length); |
1443 } else { | 1459 } else { |
1444 if (str2_length == 0) return Smi::FromInt(str1_length); | 1460 if (str2_length == 0) return Smi::FromInt(str1_length); |
1445 } | 1461 } |
1446 | 1462 |
1447 int end = str1_length < str2_length ? str1_length : str2_length; | 1463 int end = str1_length < str2_length ? str1_length : str2_length; |
1448 | 1464 |
1449 // No need to flatten if we are going to find the answer on the first | 1465 // No need to flatten if we are going to find the answer on the first |
1450 // character. At this point we know there is at least one character | 1466 // character. At this point we know there is at least one character |
1451 // in each string, due to the trivial case handling above. | 1467 // in each string, due to the trivial case handling above. |
1452 int d = str1->Get(0) - str2->Get(0); | 1468 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0); |
1453 if (d != 0) return Smi::FromInt(d); | 1469 if (d != 0) return Smi::FromInt(d); |
1454 | 1470 |
1455 str1->TryFlatten(); | 1471 str1->TryFlatten(shape1); // Shapes are no longer valid now! |
1456 str2->TryFlatten(); | 1472 str2->TryFlatten(shape2); |
1457 | 1473 |
1458 static StringInputBuffer buf1; | 1474 static StringInputBuffer buf1; |
1459 static StringInputBuffer buf2; | 1475 static StringInputBuffer buf2; |
1460 | 1476 |
1461 buf1.Reset(str1); | 1477 buf1.Reset(str1); |
1462 buf2.Reset(str2); | 1478 buf2.Reset(str2); |
1463 | 1479 |
1464 for (int i = 0; i < end; i++) { | 1480 for (int i = 0; i < end; i++) { |
1465 uint16_t char1 = buf1.GetNext(); | 1481 uint16_t char1 = buf1.GetNext(); |
1466 uint16_t char2 = buf2.GetNext(); | 1482 uint16_t char2 = buf2.GetNext(); |
1467 if (char1 != char2) return Smi::FromInt(char1 - char2); | 1483 if (char1 != char2) return Smi::FromInt(char1 - char2); |
1468 } | 1484 } |
1469 | 1485 |
1470 return Smi::FromInt(str1_length - str2_length); | 1486 return Smi::FromInt(str1_length - str2_length); |
1471 } | 1487 } |
1472 | 1488 |
1473 | 1489 |
1474 static Object* Runtime_StringSlice(Arguments args) { | 1490 static Object* Runtime_StringSlice(Arguments args) { |
1475 NoHandleAllocation ha; | 1491 NoHandleAllocation ha; |
1476 ASSERT(args.length() == 3); | 1492 ASSERT(args.length() == 3); |
1477 | 1493 |
1478 CONVERT_CHECKED(String, value, args[0]); | 1494 CONVERT_CHECKED(String, value, args[0]); |
1479 CONVERT_DOUBLE_CHECKED(from_number, args[1]); | 1495 CONVERT_DOUBLE_CHECKED(from_number, args[1]); |
1480 CONVERT_DOUBLE_CHECKED(to_number, args[2]); | 1496 CONVERT_DOUBLE_CHECKED(to_number, args[2]); |
1481 | 1497 |
1482 int start = FastD2I(from_number); | 1498 int start = FastD2I(from_number); |
1483 int end = FastD2I(to_number); | 1499 int end = FastD2I(to_number); |
1484 | 1500 |
1501 StringShape shape(value); | |
1502 | |
1485 RUNTIME_ASSERT(end >= start); | 1503 RUNTIME_ASSERT(end >= start); |
1486 RUNTIME_ASSERT(start >= 0); | 1504 RUNTIME_ASSERT(start >= 0); |
1487 RUNTIME_ASSERT(end <= value->length()); | 1505 RUNTIME_ASSERT(end <= value->length(shape)); |
1488 return value->Slice(start, end); | 1506 return value->Slice(shape, start, end); |
1489 } | 1507 } |
1490 | 1508 |
1491 | 1509 |
1492 static Object* Runtime_NumberToRadixString(Arguments args) { | 1510 static Object* Runtime_NumberToRadixString(Arguments args) { |
1493 NoHandleAllocation ha; | 1511 NoHandleAllocation ha; |
1494 ASSERT(args.length() == 2); | 1512 ASSERT(args.length() == 2); |
1495 | 1513 |
1496 CONVERT_DOUBLE_CHECKED(value, args[0]); | 1514 CONVERT_DOUBLE_CHECKED(value, args[0]); |
1497 if (isnan(value)) { | 1515 if (isnan(value)) { |
1498 return Heap::AllocateStringFromAscii(CStrVector("NaN")); | 1516 return Heap::AllocateStringFromAscii(CStrVector("NaN")); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1581 char* str = DoubleToPrecisionCString(value, f); | 1599 char* str = DoubleToPrecisionCString(value, f); |
1582 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); | 1600 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); |
1583 DeleteArray(str); | 1601 DeleteArray(str); |
1584 return res; | 1602 return res; |
1585 } | 1603 } |
1586 | 1604 |
1587 | 1605 |
1588 // Returns a single character string where first character equals | 1606 // Returns a single character string where first character equals |
1589 // string->Get(index). | 1607 // string->Get(index). |
1590 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 1608 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
1591 if (index < static_cast<uint32_t>(string->length())) { | 1609 StringShape shape(*string); |
1592 string->TryFlatten(); | 1610 if (index < static_cast<uint32_t>(string->length(shape))) { |
1593 return LookupSingleCharacterStringFromCode(string->Get(index)); | 1611 string->TryFlatten(shape); // Invalidates shape! |
1612 return LookupSingleCharacterStringFromCode( | |
1613 string->Get(StringShape(*string), index)); | |
1594 } | 1614 } |
1595 return Execution::CharAt(string, index); | 1615 return Execution::CharAt(string, index); |
1596 } | 1616 } |
1597 | 1617 |
1598 | 1618 |
1599 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { | 1619 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { |
1600 // Handle [] indexing on Strings | 1620 // Handle [] indexing on Strings |
1601 if (object->IsString()) { | 1621 if (object->IsString()) { |
1602 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 1622 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
1603 if (!result->IsUndefined()) return *result; | 1623 if (!result->IsUndefined()) return *result; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1768 return *value; | 1788 return *value; |
1769 } | 1789 } |
1770 | 1790 |
1771 if (key->IsString()) { | 1791 if (key->IsString()) { |
1772 Handle<Object> result; | 1792 Handle<Object> result; |
1773 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 1793 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
1774 ASSERT(attr == NONE); | 1794 ASSERT(attr == NONE); |
1775 result = SetElement(js_object, index, value); | 1795 result = SetElement(js_object, index, value); |
1776 } else { | 1796 } else { |
1777 Handle<String> key_string = Handle<String>::cast(key); | 1797 Handle<String> key_string = Handle<String>::cast(key); |
1778 key_string->TryFlatten(); | 1798 key_string->TryFlatten(StringShape(*key_string)); |
1779 result = SetProperty(js_object, key_string, value, attr); | 1799 result = SetProperty(js_object, key_string, value, attr); |
1780 } | 1800 } |
1781 if (result.is_null()) return Failure::Exception(); | 1801 if (result.is_null()) return Failure::Exception(); |
1782 return *value; | 1802 return *value; |
1783 } | 1803 } |
1784 | 1804 |
1785 // Call-back into JavaScript to convert the key to a string. | 1805 // Call-back into JavaScript to convert the key to a string. |
1786 bool has_pending_exception = false; | 1806 bool has_pending_exception = false; |
1787 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 1807 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
1788 if (has_pending_exception) return Failure::Exception(); | 1808 if (has_pending_exception) return Failure::Exception(); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1859 | 1879 |
1860 // Only JS objects can have properties. | 1880 // Only JS objects can have properties. |
1861 if (args[0]->IsJSObject()) { | 1881 if (args[0]->IsJSObject()) { |
1862 JSObject* object = JSObject::cast(args[0]); | 1882 JSObject* object = JSObject::cast(args[0]); |
1863 if (object->HasLocalProperty(key)) return Heap::true_value(); | 1883 if (object->HasLocalProperty(key)) return Heap::true_value(); |
1864 } else if (args[0]->IsString()) { | 1884 } else if (args[0]->IsString()) { |
1865 // Well, there is one exception: Handle [] on strings. | 1885 // Well, there is one exception: Handle [] on strings. |
1866 uint32_t index; | 1886 uint32_t index; |
1867 if (key->AsArrayIndex(&index)) { | 1887 if (key->AsArrayIndex(&index)) { |
1868 String* string = String::cast(args[0]); | 1888 String* string = String::cast(args[0]); |
1869 if (index < static_cast<uint32_t>(string->length())) | 1889 StringShape shape(string); |
1890 if (index < static_cast<uint32_t>(string->length(shape))) | |
1870 return Heap::true_value(); | 1891 return Heap::true_value(); |
1871 } | 1892 } |
1872 } | 1893 } |
1873 return Heap::false_value(); | 1894 return Heap::false_value(); |
1874 } | 1895 } |
1875 | 1896 |
1876 | 1897 |
1877 static Object* Runtime_HasProperty(Arguments args) { | 1898 static Object* Runtime_HasProperty(Arguments args) { |
1878 NoHandleAllocation na; | 1899 NoHandleAllocation na; |
1879 ASSERT(args.length() == 2); | 1900 ASSERT(args.length() == 2); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2042 // host objects gives that it is okay to return "object" | 2063 // host objects gives that it is okay to return "object" |
2043 return Heap::object_symbol(); | 2064 return Heap::object_symbol(); |
2044 } | 2065 } |
2045 } | 2066 } |
2046 | 2067 |
2047 | 2068 |
2048 static Object* Runtime_StringToNumber(Arguments args) { | 2069 static Object* Runtime_StringToNumber(Arguments args) { |
2049 NoHandleAllocation ha; | 2070 NoHandleAllocation ha; |
2050 ASSERT(args.length() == 1); | 2071 ASSERT(args.length() == 1); |
2051 CONVERT_CHECKED(String, subject, args[0]); | 2072 CONVERT_CHECKED(String, subject, args[0]); |
2052 subject->TryFlatten(); | 2073 subject->TryFlatten(StringShape(subject)); |
2053 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); | 2074 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); |
2054 } | 2075 } |
2055 | 2076 |
2056 | 2077 |
2057 static Object* Runtime_StringFromCharCodeArray(Arguments args) { | 2078 static Object* Runtime_StringFromCharCodeArray(Arguments args) { |
2058 NoHandleAllocation ha; | 2079 NoHandleAllocation ha; |
2059 ASSERT(args.length() == 1); | 2080 ASSERT(args.length() == 1); |
2060 | 2081 |
2061 CONVERT_CHECKED(JSArray, codes, args[0]); | 2082 CONVERT_CHECKED(JSArray, codes, args[0]); |
2062 int length = Smi::cast(codes->length())->value(); | 2083 int length = Smi::cast(codes->length())->value(); |
2063 | 2084 |
2064 // Check if the string can be ASCII. | 2085 // Check if the string can be ASCII. |
2065 int i; | 2086 int i; |
2066 for (i = 0; i < length; i++) { | 2087 for (i = 0; i < length; i++) { |
2067 Object* element = codes->GetElement(i); | 2088 Object* element = codes->GetElement(i); |
2068 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2089 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
2069 if ((chr & 0xffff) > String::kMaxAsciiCharCode) | 2090 if ((chr & 0xffff) > String::kMaxAsciiCharCode) |
2070 break; | 2091 break; |
2071 } | 2092 } |
2072 | 2093 |
2073 Object* object = NULL; | 2094 Object* object = NULL; |
2074 if (i == length) { // The string is ASCII. | 2095 if (i == length) { // The string is ASCII. |
2075 object = Heap::AllocateRawAsciiString(length); | 2096 object = Heap::AllocateRawAsciiString(length); |
2076 } else { // The string is not ASCII. | 2097 } else { // The string is not ASCII. |
2077 object = Heap::AllocateRawTwoByteString(length); | 2098 object = Heap::AllocateRawTwoByteString(length); |
2078 } | 2099 } |
2079 | 2100 |
2080 if (object->IsFailure()) return object; | 2101 if (object->IsFailure()) return object; |
2081 String* result = String::cast(object); | 2102 String* result = String::cast(object); |
2103 StringShape result_shape(result); | |
2082 for (int i = 0; i < length; i++) { | 2104 for (int i = 0; i < length; i++) { |
2083 Object* element = codes->GetElement(i); | 2105 Object* element = codes->GetElement(i); |
2084 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2106 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
2085 result->Set(i, chr & 0xffff); | 2107 result->Set(result_shape, i, chr & 0xffff); |
2086 } | 2108 } |
2087 return result; | 2109 return result; |
2088 } | 2110 } |
2089 | 2111 |
2090 | 2112 |
2091 // kNotEscaped is generated by the following: | 2113 // kNotEscaped is generated by the following: |
2092 // | 2114 // |
2093 // #!/bin/perl | 2115 // #!/bin/perl |
2094 // for (my $i = 0; $i < 256; $i++) { | 2116 // for (my $i = 0; $i < 256; $i++) { |
2095 // print "\n" if $i % 16 == 0; | 2117 // print "\n" if $i % 16 == 0; |
(...skipping 28 matching lines...) Expand all Loading... | |
2124 return kNotEscaped[character] != 0; | 2146 return kNotEscaped[character] != 0; |
2125 } | 2147 } |
2126 | 2148 |
2127 | 2149 |
2128 static Object* Runtime_URIEscape(Arguments args) { | 2150 static Object* Runtime_URIEscape(Arguments args) { |
2129 const char hex_chars[] = "0123456789ABCDEF"; | 2151 const char hex_chars[] = "0123456789ABCDEF"; |
2130 NoHandleAllocation ha; | 2152 NoHandleAllocation ha; |
2131 ASSERT(args.length() == 1); | 2153 ASSERT(args.length() == 1); |
2132 CONVERT_CHECKED(String, source, args[0]); | 2154 CONVERT_CHECKED(String, source, args[0]); |
2133 | 2155 |
2134 source->TryFlatten(); | 2156 source->TryFlatten(StringShape(source)); |
2135 | 2157 |
2158 StringShape sshape(source); | |
Mads Ager (chromium)
2008/11/03 08:45:49
How about source_shape?
| |
2136 int escaped_length = 0; | 2159 int escaped_length = 0; |
2137 int length = source->length(); | 2160 int length = source->length(sshape); |
2138 { | 2161 { |
2139 Access<StringInputBuffer> buffer(&string_input_buffer); | 2162 Access<StringInputBuffer> buffer(&string_input_buffer); |
2140 buffer->Reset(source); | 2163 buffer->Reset(source); |
2141 while (buffer->has_more()) { | 2164 while (buffer->has_more()) { |
2142 uint16_t character = buffer->GetNext(); | 2165 uint16_t character = buffer->GetNext(); |
2143 if (character >= 256) { | 2166 if (character >= 256) { |
2144 escaped_length += 6; | 2167 escaped_length += 6; |
2145 } else if (IsNotEscaped(character)) { | 2168 } else if (IsNotEscaped(character)) { |
2146 escaped_length++; | 2169 escaped_length++; |
2147 } else { | 2170 } else { |
2148 escaped_length += 3; | 2171 escaped_length += 3; |
2149 } | 2172 } |
2150 // We don't allow strings that are longer than Smi range. | 2173 // We don't allow strings that are longer than Smi range. |
2151 if (!Smi::IsValid(escaped_length)) { | 2174 if (!Smi::IsValid(escaped_length)) { |
2152 Top::context()->mark_out_of_memory(); | 2175 Top::context()->mark_out_of_memory(); |
2153 return Failure::OutOfMemoryException(); | 2176 return Failure::OutOfMemoryException(); |
2154 } | 2177 } |
2155 } | 2178 } |
2156 } | 2179 } |
2157 // No length change implies no change. Return original string if no change. | 2180 // No length change implies no change. Return original string if no change. |
2158 if (escaped_length == length) { | 2181 if (escaped_length == length) { |
2159 return source; | 2182 return source; |
2160 } | 2183 } |
2161 Object* o = Heap::AllocateRawAsciiString(escaped_length); | 2184 Object* o = Heap::AllocateRawAsciiString(escaped_length); |
2162 if (o->IsFailure()) return o; | 2185 if (o->IsFailure()) return o; |
2163 String* destination = String::cast(o); | 2186 String* destination = String::cast(o); |
2187 StringShape dshape(destination); | |
Mads Ager (chromium)
2008/11/03 08:45:49
dest_shape or even destination_shape?
Erik Corry
2008/11/03 09:33:54
I changed the other one, but I left this in, becau
| |
2164 int dest_position = 0; | 2188 int dest_position = 0; |
2165 | 2189 |
2166 Access<StringInputBuffer> buffer(&string_input_buffer); | 2190 Access<StringInputBuffer> buffer(&string_input_buffer); |
2167 buffer->Rewind(); | 2191 buffer->Rewind(); |
2168 while (buffer->has_more()) { | 2192 while (buffer->has_more()) { |
2169 uint16_t character = buffer->GetNext(); | 2193 uint16_t chr = buffer->GetNext(); |
2170 if (character >= 256) { | 2194 if (chr >= 256) { |
2171 destination->Set(dest_position, '%'); | 2195 destination->Set(dshape, dest_position, '%'); |
2172 destination->Set(dest_position+1, 'u'); | 2196 destination->Set(dshape, dest_position+1, 'u'); |
2173 destination->Set(dest_position+2, hex_chars[character >> 12]); | 2197 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]); |
2174 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]); | 2198 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
2175 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]); | 2199 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
2176 destination->Set(dest_position+5, hex_chars[character & 0xf]); | 2200 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]); |
2177 dest_position += 6; | 2201 dest_position += 6; |
2178 } else if (IsNotEscaped(character)) { | 2202 } else if (IsNotEscaped(chr)) { |
2179 destination->Set(dest_position, character); | 2203 destination->Set(dshape, dest_position, chr); |
2180 dest_position++; | 2204 dest_position++; |
2181 } else { | 2205 } else { |
2182 destination->Set(dest_position, '%'); | 2206 destination->Set(dshape, dest_position, '%'); |
2183 destination->Set(dest_position+1, hex_chars[character >> 4]); | 2207 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]); |
2184 destination->Set(dest_position+2, hex_chars[character & 0xf]); | 2208 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]); |
2185 dest_position += 3; | 2209 dest_position += 3; |
2186 } | 2210 } |
2187 } | 2211 } |
2188 return destination; | 2212 return destination; |
2189 } | 2213 } |
2190 | 2214 |
2191 | 2215 |
2192 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { | 2216 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { |
2193 static const signed char kHexValue['g'] = { | 2217 static const signed char kHexValue['g'] = { |
2194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2218 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2219 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2196 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2220 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2197 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, | 2221 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
2198 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2222 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2199 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2223 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2200 -1, 10, 11, 12, 13, 14, 15 }; | 2224 -1, 10, 11, 12, 13, 14, 15 }; |
2201 | 2225 |
2202 if (character1 > 'f') return -1; | 2226 if (character1 > 'f') return -1; |
2203 int hi = kHexValue[character1]; | 2227 int hi = kHexValue[character1]; |
2204 if (hi == -1) return -1; | 2228 if (hi == -1) return -1; |
2205 if (character2 > 'f') return -1; | 2229 if (character2 > 'f') return -1; |
2206 int lo = kHexValue[character2]; | 2230 int lo = kHexValue[character2]; |
2207 if (lo == -1) return -1; | 2231 if (lo == -1) return -1; |
2208 return (hi << 4) + lo; | 2232 return (hi << 4) + lo; |
2209 } | 2233 } |
2210 | 2234 |
2211 | 2235 |
2212 static inline int Unescape(String* source, int i, int length, int* step) { | 2236 static inline int Unescape(String* source, |
2213 uint16_t character = source->Get(i); | 2237 StringShape shape, |
2238 int i, | |
2239 int length, | |
2240 int* step) { | |
2241 uint16_t character = source->Get(shape, i); | |
2214 int32_t hi, lo; | 2242 int32_t hi, lo; |
2215 if (character == '%' && | 2243 if (character == '%' && |
2216 i <= length - 6 && | 2244 i <= length - 6 && |
2217 source->Get(i + 1) == 'u' && | 2245 source->Get(shape, i + 1) == 'u' && |
2218 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 && | 2246 (hi = TwoDigitHex(source->Get(shape, i + 2), |
2219 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) { | 2247 source->Get(shape, i + 3))) != -1 && |
2248 (lo = TwoDigitHex(source->Get(shape, i + 4), | |
2249 source->Get(shape, i + 5))) != -1) { | |
2220 *step = 6; | 2250 *step = 6; |
2221 return (hi << 8) + lo; | 2251 return (hi << 8) + lo; |
2222 } else if (character == '%' && | 2252 } else if (character == '%' && |
2223 i <= length - 3 && | 2253 i <= length - 3 && |
2224 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) { | 2254 (lo = TwoDigitHex(source->Get(shape, i + 1), |
2255 source->Get(shape, i + 2))) != -1) { | |
2225 *step = 3; | 2256 *step = 3; |
2226 return lo; | 2257 return lo; |
2227 } else { | 2258 } else { |
2228 *step = 1; | 2259 *step = 1; |
2229 return character; | 2260 return character; |
2230 } | 2261 } |
2231 } | 2262 } |
2232 | 2263 |
2233 | 2264 |
2234 static Object* Runtime_URIUnescape(Arguments args) { | 2265 static Object* Runtime_URIUnescape(Arguments args) { |
2235 NoHandleAllocation ha; | 2266 NoHandleAllocation ha; |
2236 ASSERT(args.length() == 1); | 2267 ASSERT(args.length() == 1); |
2237 CONVERT_CHECKED(String, source, args[0]); | 2268 CONVERT_CHECKED(String, source, args[0]); |
2238 | 2269 |
2239 source->TryFlatten(); | 2270 source->TryFlatten(StringShape(source)); |
2271 StringShape sshape(source); | |
Mads Ager (chromium)
2008/11/03 08:45:49
source_shape?
| |
2240 | 2272 |
2241 bool ascii = true; | 2273 bool ascii = true; |
2242 int length = source->length(); | 2274 int length = source->length(sshape); |
2243 | 2275 |
2244 int unescaped_length = 0; | 2276 int unescaped_length = 0; |
2245 for (int i = 0; i < length; unescaped_length++) { | 2277 for (int i = 0; i < length; unescaped_length++) { |
2246 int step; | 2278 int step; |
2247 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) | 2279 if (Unescape(source, sshape, i, length, &step) > String::kMaxAsciiCharCode) |
2248 ascii = false; | 2280 ascii = false; |
2249 i += step; | 2281 i += step; |
2250 } | 2282 } |
2251 | 2283 |
2252 // No length change implies no change. Return original string if no change. | 2284 // No length change implies no change. Return original string if no change. |
2253 if (unescaped_length == length) | 2285 if (unescaped_length == length) |
2254 return source; | 2286 return source; |
2255 | 2287 |
2256 Object* o = ascii ? | 2288 Object* o = ascii ? |
2257 Heap::AllocateRawAsciiString(unescaped_length) : | 2289 Heap::AllocateRawAsciiString(unescaped_length) : |
2258 Heap::AllocateRawTwoByteString(unescaped_length); | 2290 Heap::AllocateRawTwoByteString(unescaped_length); |
2259 if (o->IsFailure()) return o; | 2291 if (o->IsFailure()) return o; |
2260 String* destination = String::cast(o); | 2292 String* destination = String::cast(o); |
2293 StringShape dshape(destination); | |
Mads Ager (chromium)
2008/11/03 08:45:49
destination_shape?
| |
2261 | 2294 |
2262 int dest_position = 0; | 2295 int dest_position = 0; |
2263 for (int i = 0; i < length; dest_position++) { | 2296 for (int i = 0; i < length; dest_position++) { |
2264 int step; | 2297 int step; |
2265 destination->Set(dest_position, Unescape(source, i, length, &step)); | 2298 destination->Set(dshape, |
2299 dest_position, | |
2300 Unescape(source, sshape, i, length, &step)); | |
2266 i += step; | 2301 i += step; |
2267 } | 2302 } |
2268 return destination; | 2303 return destination; |
2269 } | 2304 } |
2270 | 2305 |
2271 | 2306 |
2272 static Object* Runtime_StringParseInt(Arguments args) { | 2307 static Object* Runtime_StringParseInt(Arguments args) { |
2273 NoHandleAllocation ha; | 2308 NoHandleAllocation ha; |
2274 | 2309 |
2275 CONVERT_CHECKED(String, s, args[0]); | 2310 CONVERT_CHECKED(String, s, args[0]); |
2276 CONVERT_DOUBLE_CHECKED(n, args[1]); | 2311 CONVERT_DOUBLE_CHECKED(n, args[1]); |
2277 int radix = FastD2I(n); | 2312 int radix = FastD2I(n); |
2278 | 2313 |
2279 s->TryFlatten(); | 2314 s->TryFlatten(StringShape(s)); |
2280 | 2315 |
2281 int len = s->length(); | 2316 StringShape shape(s); |
2317 | |
2318 int len = s->length(shape); | |
2282 int i; | 2319 int i; |
2283 | 2320 |
2284 // Skip leading white space. | 2321 // Skip leading white space. |
2285 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; | 2322 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ; |
2286 if (i == len) return Heap::nan_value(); | 2323 if (i == len) return Heap::nan_value(); |
2287 | 2324 |
2288 // Compute the sign (default to +). | 2325 // Compute the sign (default to +). |
2289 int sign = 1; | 2326 int sign = 1; |
2290 if (s->Get(i) == '-') { | 2327 if (s->Get(shape, i) == '-') { |
2291 sign = -1; | 2328 sign = -1; |
2292 i++; | 2329 i++; |
2293 } else if (s->Get(i) == '+') { | 2330 } else if (s->Get(shape, i) == '+') { |
2294 i++; | 2331 i++; |
2295 } | 2332 } |
2296 | 2333 |
2297 // Compute the radix if 0. | 2334 // Compute the radix if 0. |
2298 if (radix == 0) { | 2335 if (radix == 0) { |
2299 radix = 10; | 2336 radix = 10; |
2300 if (i < len && s->Get(i) == '0') { | 2337 if (i < len && s->Get(shape, i) == '0') { |
2301 radix = 8; | 2338 radix = 8; |
2302 if (i + 1 < len) { | 2339 if (i + 1 < len) { |
2303 int c = s->Get(i + 1); | 2340 int c = s->Get(shape, i + 1); |
2304 if (c == 'x' || c == 'X') { | 2341 if (c == 'x' || c == 'X') { |
2305 radix = 16; | 2342 radix = 16; |
2306 i += 2; | 2343 i += 2; |
2307 } | 2344 } |
2308 } | 2345 } |
2309 } | 2346 } |
2310 } else if (radix == 16) { | 2347 } else if (radix == 16) { |
2311 // Allow 0x or 0X prefix if radix is 16. | 2348 // Allow 0x or 0X prefix if radix is 16. |
2312 if (i + 1 < len && s->Get(i) == '0') { | 2349 if (i + 1 < len && s->Get(shape, i) == '0') { |
2313 int c = s->Get(i + 1); | 2350 int c = s->Get(shape, i + 1); |
2314 if (c == 'x' || c == 'X') i += 2; | 2351 if (c == 'x' || c == 'X') i += 2; |
2315 } | 2352 } |
2316 } | 2353 } |
2317 | 2354 |
2318 RUNTIME_ASSERT(2 <= radix && radix <= 36); | 2355 RUNTIME_ASSERT(2 <= radix && radix <= 36); |
2319 double value; | 2356 double value; |
2320 int end_index = StringToInt(s, i, radix, &value); | 2357 int end_index = StringToInt(s, i, radix, &value); |
2321 if (end_index != i) { | 2358 if (end_index != i) { |
2322 return Heap::NumberFromDouble(sign * value); | 2359 return Heap::NumberFromDouble(sign * value); |
2323 } | 2360 } |
(...skipping 16 matching lines...) Expand all Loading... | |
2340 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; | 2377 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; |
2341 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; | 2378 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; |
2342 | 2379 |
2343 | 2380 |
2344 template <class Converter> | 2381 template <class Converter> |
2345 static Object* ConvertCase(Arguments args, | 2382 static Object* ConvertCase(Arguments args, |
2346 unibrow::Mapping<Converter, 128>* mapping) { | 2383 unibrow::Mapping<Converter, 128>* mapping) { |
2347 NoHandleAllocation ha; | 2384 NoHandleAllocation ha; |
2348 | 2385 |
2349 CONVERT_CHECKED(String, s, args[0]); | 2386 CONVERT_CHECKED(String, s, args[0]); |
2350 int raw_string_length = s->length(); | 2387 s->TryFlatten(StringShape(s)); |
2388 StringShape shape(s); | |
2389 | |
2390 int raw_string_length = s->length(shape); | |
2351 // Assume that the string is not empty; we need this assumption later | 2391 // Assume that the string is not empty; we need this assumption later |
2352 if (raw_string_length == 0) return s; | 2392 if (raw_string_length == 0) return s; |
2353 int length = raw_string_length; | 2393 int length = raw_string_length; |
2354 | 2394 |
2355 s->TryFlatten(); | |
2356 | 2395 |
2357 // We try this twice, once with the assumption that the result is | 2396 // We try this twice, once with the assumption that the result is |
2358 // no longer than the input and, if that assumption breaks, again | 2397 // no longer than the input and, if that assumption breaks, again |
2359 // with the exact length. This is implemented using a goto back | 2398 // with the exact length. This is implemented using a goto back |
2360 // to this label if we discover that the assumption doesn't hold. | 2399 // to this label if we discover that the assumption doesn't hold. |
2361 // I apologize sincerely for this and will give a vaffel-is to | 2400 // I apologize sincerely for this and will give a vaffel-is to |
2362 // the first person who can implement it in a nicer way. | 2401 // the first person who can implement it in a nicer way. |
2363 try_convert: | 2402 try_convert: |
2364 | 2403 |
2365 // Allocate the resulting string. | 2404 // Allocate the resulting string. |
2366 // | 2405 // |
2367 // NOTE: This assumes that the upper/lower case of an ascii | 2406 // NOTE: This assumes that the upper/lower case of an ascii |
2368 // character is also ascii. This is currently the case, but it | 2407 // character is also ascii. This is currently the case, but it |
2369 // might break in the future if we implement more context and locale | 2408 // might break in the future if we implement more context and locale |
2370 // dependent upper/lower conversions. | 2409 // dependent upper/lower conversions. |
2371 Object* o = s->IsAsciiRepresentation() | 2410 Object* o = shape.IsAsciiRepresentation() |
2372 ? Heap::AllocateRawAsciiString(length) | 2411 ? Heap::AllocateRawAsciiString(length) |
2373 : Heap::AllocateRawTwoByteString(length); | 2412 : Heap::AllocateRawTwoByteString(length); |
2374 if (o->IsFailure()) return o; | 2413 if (o->IsFailure()) return o; |
2375 String* result = String::cast(o); | 2414 String* result = String::cast(o); |
2415 StringShape result_shape(result); | |
2376 bool has_changed_character = false; | 2416 bool has_changed_character = false; |
2377 | 2417 |
2378 // Convert all characters to upper case, assuming that they will fit | 2418 // Convert all characters to upper case, assuming that they will fit |
2379 // in the buffer | 2419 // in the buffer |
2380 Access<StringInputBuffer> buffer(&string_input_buffer); | 2420 Access<StringInputBuffer> buffer(&string_input_buffer); |
2381 buffer->Reset(s); | 2421 buffer->Reset(s); |
2382 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize]; | 2422 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize]; |
2383 int i = 0; | 2423 int i = 0; |
2384 // We can assume that the string is not empty | 2424 // We can assume that the string is not empty |
2385 uc32 current = buffer->GetNext(); | 2425 uc32 current = buffer->GetNext(); |
2386 while (i < length) { | 2426 while (i < length) { |
2387 bool has_next = buffer->has_more(); | 2427 bool has_next = buffer->has_more(); |
2388 uc32 next = has_next ? buffer->GetNext() : 0; | 2428 uc32 next = has_next ? buffer->GetNext() : 0; |
2389 int char_length = mapping->get(current, next, chars); | 2429 int char_length = mapping->get(current, next, chars); |
2390 if (char_length == 0) { | 2430 if (char_length == 0) { |
2391 // The case conversion of this character is the character itself. | 2431 // The case conversion of this character is the character itself. |
2392 result->Set(i, current); | 2432 result->Set(result_shape, i, current); |
2393 i++; | 2433 i++; |
2394 } else if (char_length == 1) { | 2434 } else if (char_length == 1) { |
2395 // Common case: converting the letter resulted in one character. | 2435 // Common case: converting the letter resulted in one character. |
2396 ASSERT(static_cast<uc32>(chars[0]) != current); | 2436 ASSERT(static_cast<uc32>(chars[0]) != current); |
2397 result->Set(i, chars[0]); | 2437 result->Set(result_shape, i, chars[0]); |
2398 has_changed_character = true; | 2438 has_changed_character = true; |
2399 i++; | 2439 i++; |
2400 } else if (length == raw_string_length) { | 2440 } else if (length == raw_string_length) { |
2401 // We've assumed that the result would be as long as the | 2441 // We've assumed that the result would be as long as the |
2402 // input but here is a character that converts to several | 2442 // input but here is a character that converts to several |
2403 // characters. No matter, we calculate the exact length | 2443 // characters. No matter, we calculate the exact length |
2404 // of the result and try the whole thing again. | 2444 // of the result and try the whole thing again. |
2405 // | 2445 // |
2406 // Note that this leaves room for optimization. We could just | 2446 // Note that this leaves room for optimization. We could just |
2407 // memcpy what we already have to the result string. Also, | 2447 // memcpy what we already have to the result string. Also, |
(...skipping 14 matching lines...) Expand all Loading... | |
2422 // it does not in any case affect the length of what it convert | 2462 // it does not in any case affect the length of what it convert |
2423 // to. | 2463 // to. |
2424 int char_length = mapping->get(current, 0, chars); | 2464 int char_length = mapping->get(current, 0, chars); |
2425 if (char_length == 0) char_length = 1; | 2465 if (char_length == 0) char_length = 1; |
2426 current_length += char_length; | 2466 current_length += char_length; |
2427 } | 2467 } |
2428 length = current_length; | 2468 length = current_length; |
2429 goto try_convert; | 2469 goto try_convert; |
2430 } else { | 2470 } else { |
2431 for (int j = 0; j < char_length; j++) { | 2471 for (int j = 0; j < char_length; j++) { |
2432 result->Set(i, chars[j]); | 2472 result->Set(result_shape, i, chars[j]); |
2433 i++; | 2473 i++; |
2434 } | 2474 } |
2435 has_changed_character = true; | 2475 has_changed_character = true; |
2436 } | 2476 } |
2437 current = next; | 2477 current = next; |
2438 } | 2478 } |
2439 if (has_changed_character) { | 2479 if (has_changed_character) { |
2440 return result; | 2480 return result; |
2441 } else { | 2481 } else { |
2442 // If we didn't actually change anything in doing the conversion | 2482 // If we didn't actually change anything in doing the conversion |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2606 return Heap::NewNumberFromDouble(x); | 2646 return Heap::NewNumberFromDouble(x); |
2607 } | 2647 } |
2608 | 2648 |
2609 | 2649 |
2610 static Object* Runtime_StringAdd(Arguments args) { | 2650 static Object* Runtime_StringAdd(Arguments args) { |
2611 NoHandleAllocation ha; | 2651 NoHandleAllocation ha; |
2612 ASSERT(args.length() == 2); | 2652 ASSERT(args.length() == 2); |
2613 | 2653 |
2614 CONVERT_CHECKED(String, str1, args[0]); | 2654 CONVERT_CHECKED(String, str1, args[0]); |
2615 CONVERT_CHECKED(String, str2, args[1]); | 2655 CONVERT_CHECKED(String, str2, args[1]); |
2616 int len1 = str1->length(); | 2656 StringShape shape1(str1); |
2617 int len2 = str2->length(); | 2657 StringShape shape2(str2); |
2658 int len1 = str1->length(shape1); | |
2659 int len2 = str2->length(shape2); | |
2618 if (len1 == 0) return str2; | 2660 if (len1 == 0) return str2; |
2619 if (len2 == 0) return str1; | 2661 if (len2 == 0) return str1; |
2620 int length_sum = len1 + len2; | 2662 int length_sum = len1 + len2; |
2621 // Make sure that an out of memory exception is thrown if the length | 2663 // Make sure that an out of memory exception is thrown if the length |
2622 // of the new cons string is too large to fit in a Smi. | 2664 // of the new cons string is too large to fit in a Smi. |
2623 if (length_sum > Smi::kMaxValue || length_sum < 0) { | 2665 if (length_sum > Smi::kMaxValue || length_sum < 0) { |
2624 Top::context()->mark_out_of_memory(); | 2666 Top::context()->mark_out_of_memory(); |
2625 return Failure::OutOfMemoryException(); | 2667 return Failure::OutOfMemoryException(); |
2626 } | 2668 } |
2627 return Heap::AllocateConsString(str1, str2); | 2669 return Heap::AllocateConsString(str1, shape1, str2, shape2); |
2628 } | 2670 } |
2629 | 2671 |
2630 | 2672 |
2631 template<typename sinkchar> | 2673 template<typename sinkchar> |
2632 static inline void StringBuilderConcatHelper(String* special, | 2674 static inline void StringBuilderConcatHelper(String* special, |
2675 StringShape special_shape, | |
2633 sinkchar* sink, | 2676 sinkchar* sink, |
2634 FixedArray* fixed_array, | 2677 FixedArray* fixed_array, |
2635 int array_length) { | 2678 int array_length) { |
2636 int position = 0; | 2679 int position = 0; |
2637 for (int i = 0; i < array_length; i++) { | 2680 for (int i = 0; i < array_length; i++) { |
2638 Object* element = fixed_array->get(i); | 2681 Object* element = fixed_array->get(i); |
2639 if (element->IsSmi()) { | 2682 if (element->IsSmi()) { |
2640 int len = Smi::cast(element)->value(); | 2683 int len = Smi::cast(element)->value(); |
2641 int pos = len >> 11; | 2684 int pos = len >> 11; |
2642 len &= 0x7ff; | 2685 len &= 0x7ff; |
2643 String::WriteToFlat(special, sink + position, pos, pos + len); | 2686 String::WriteToFlat(special, |
2687 special_shape, | |
2688 sink + position, | |
2689 pos, | |
2690 pos + len); | |
2644 position += len; | 2691 position += len; |
2645 } else { | 2692 } else { |
2646 String* string = String::cast(element); | 2693 String* string = String::cast(element); |
2647 int element_length = string->length(); | 2694 StringShape shape(string); |
2648 String::WriteToFlat(string, sink + position, 0, element_length); | 2695 int element_length = string->length(shape); |
2696 String::WriteToFlat(string, shape, sink + position, 0, element_length); | |
2649 position += element_length; | 2697 position += element_length; |
2650 } | 2698 } |
2651 } | 2699 } |
2652 } | 2700 } |
2653 | 2701 |
2654 | 2702 |
2655 static Object* Runtime_StringBuilderConcat(Arguments args) { | 2703 static Object* Runtime_StringBuilderConcat(Arguments args) { |
2656 NoHandleAllocation ha; | 2704 NoHandleAllocation ha; |
2657 ASSERT(args.length() == 2); | 2705 ASSERT(args.length() == 2); |
2658 CONVERT_CHECKED(JSArray, array, args[0]); | 2706 CONVERT_CHECKED(JSArray, array, args[0]); |
2659 CONVERT_CHECKED(String, special, args[1]); | 2707 CONVERT_CHECKED(String, special, args[1]); |
2660 int special_length = special->length(); | 2708 StringShape special_shape(special); |
2709 int special_length = special->length(special_shape); | |
2661 Object* smi_array_length = array->length(); | 2710 Object* smi_array_length = array->length(); |
2662 if (!smi_array_length->IsSmi()) { | 2711 if (!smi_array_length->IsSmi()) { |
2663 Top::context()->mark_out_of_memory(); | 2712 Top::context()->mark_out_of_memory(); |
2664 return Failure::OutOfMemoryException(); | 2713 return Failure::OutOfMemoryException(); |
2665 } | 2714 } |
2666 int array_length = Smi::cast(smi_array_length)->value(); | 2715 int array_length = Smi::cast(smi_array_length)->value(); |
2667 if (!array->HasFastElements()) { | 2716 if (!array->HasFastElements()) { |
2668 return Top::Throw(Heap::illegal_argument_symbol()); | 2717 return Top::Throw(Heap::illegal_argument_symbol()); |
2669 } | 2718 } |
2670 FixedArray* fixed_array = FixedArray::cast(array->elements()); | 2719 FixedArray* fixed_array = FixedArray::cast(array->elements()); |
2671 if (fixed_array->length() < array_length) { | 2720 if (fixed_array->length() < array_length) { |
2672 array_length = fixed_array->length(); | 2721 array_length = fixed_array->length(); |
2673 } | 2722 } |
2674 | 2723 |
2675 if (array_length == 0) { | 2724 if (array_length == 0) { |
2676 return Heap::empty_string(); | 2725 return Heap::empty_string(); |
2677 } else if (array_length == 1) { | 2726 } else if (array_length == 1) { |
2678 Object* first = fixed_array->get(0); | 2727 Object* first = fixed_array->get(0); |
2679 if (first->IsString()) return first; | 2728 if (first->IsString()) return first; |
2680 } | 2729 } |
2681 | 2730 |
2682 bool ascii = special->IsAsciiRepresentation(); | 2731 bool ascii = special_shape.IsAsciiRepresentation(); |
2683 int position = 0; | 2732 int position = 0; |
2684 for (int i = 0; i < array_length; i++) { | 2733 for (int i = 0; i < array_length; i++) { |
2685 Object* elt = fixed_array->get(i); | 2734 Object* elt = fixed_array->get(i); |
2686 if (elt->IsSmi()) { | 2735 if (elt->IsSmi()) { |
2687 int len = Smi::cast(elt)->value(); | 2736 int len = Smi::cast(elt)->value(); |
2688 int pos = len >> 11; | 2737 int pos = len >> 11; |
2689 len &= 0x7ff; | 2738 len &= 0x7ff; |
2690 if (pos + len > special_length) { | 2739 if (pos + len > special_length) { |
2691 return Top::Throw(Heap::illegal_argument_symbol()); | 2740 return Top::Throw(Heap::illegal_argument_symbol()); |
2692 } | 2741 } |
2693 position += len; | 2742 position += len; |
2694 } else if (elt->IsString()) { | 2743 } else if (elt->IsString()) { |
2695 String* element = String::cast(elt); | 2744 String* element = String::cast(elt); |
2696 int element_length = element->length(); | 2745 StringShape element_shape(element); |
2746 int element_length = element->length(element_shape); | |
2697 if (!Smi::IsValid(element_length + position)) { | 2747 if (!Smi::IsValid(element_length + position)) { |
2698 Top::context()->mark_out_of_memory(); | 2748 Top::context()->mark_out_of_memory(); |
2699 return Failure::OutOfMemoryException(); | 2749 return Failure::OutOfMemoryException(); |
2700 } | 2750 } |
2701 position += element_length; | 2751 position += element_length; |
2702 if (ascii && !element->IsAsciiRepresentation()) { | 2752 if (ascii && !element_shape.IsAsciiRepresentation()) { |
2703 ascii = false; | 2753 ascii = false; |
2704 } | 2754 } |
2705 } else { | 2755 } else { |
2706 return Top::Throw(Heap::illegal_argument_symbol()); | 2756 return Top::Throw(Heap::illegal_argument_symbol()); |
2707 } | 2757 } |
2708 } | 2758 } |
2709 | 2759 |
2710 int length = position; | 2760 int length = position; |
2711 Object* object; | 2761 Object* object; |
2712 | 2762 |
2713 if (ascii) { | 2763 if (ascii) { |
2714 object = Heap::AllocateRawAsciiString(length); | 2764 object = Heap::AllocateRawAsciiString(length); |
2715 if (object->IsFailure()) return object; | 2765 if (object->IsFailure()) return object; |
2716 SeqAsciiString* answer = SeqAsciiString::cast(object); | 2766 SeqAsciiString* answer = SeqAsciiString::cast(object); |
2717 StringBuilderConcatHelper(special, | 2767 StringBuilderConcatHelper(special, |
2768 special_shape, | |
2718 answer->GetChars(), | 2769 answer->GetChars(), |
2719 fixed_array, | 2770 fixed_array, |
2720 array_length); | 2771 array_length); |
2721 return answer; | 2772 return answer; |
2722 } else { | 2773 } else { |
2723 object = Heap::AllocateRawTwoByteString(length); | 2774 object = Heap::AllocateRawTwoByteString(length); |
2724 if (object->IsFailure()) return object; | 2775 if (object->IsFailure()) return object; |
2725 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 2776 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
2726 StringBuilderConcatHelper(special, | 2777 StringBuilderConcatHelper(special, |
2778 special_shape, | |
2727 answer->GetChars(), | 2779 answer->GetChars(), |
2728 fixed_array, | 2780 fixed_array, |
2729 array_length); | 2781 array_length); |
2730 return answer; | 2782 return answer; |
2731 } | 2783 } |
2732 } | 2784 } |
2733 | 2785 |
2734 | 2786 |
2735 static Object* Runtime_NumberOr(Arguments args) { | 2787 static Object* Runtime_NumberOr(Arguments args) { |
2736 NoHandleAllocation ha; | 2788 NoHandleAllocation ha; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2911 } | 2963 } |
2912 | 2964 |
2913 | 2965 |
2914 static Object* Runtime_StringCompare(Arguments args) { | 2966 static Object* Runtime_StringCompare(Arguments args) { |
2915 NoHandleAllocation ha; | 2967 NoHandleAllocation ha; |
2916 ASSERT(args.length() == 2); | 2968 ASSERT(args.length() == 2); |
2917 | 2969 |
2918 CONVERT_CHECKED(String, x, args[0]); | 2970 CONVERT_CHECKED(String, x, args[0]); |
2919 CONVERT_CHECKED(String, y, args[1]); | 2971 CONVERT_CHECKED(String, y, args[1]); |
2920 | 2972 |
2973 StringShape x_shape(x); | |
2974 StringShape y_shape(y); | |
2975 | |
2921 // A few fast case tests before we flatten. | 2976 // A few fast case tests before we flatten. |
2922 if (x == y) return Smi::FromInt(EQUAL); | 2977 if (x == y) return Smi::FromInt(EQUAL); |
2923 if (y->length() == 0) { | 2978 if (y->length(y_shape) == 0) { |
2924 if (x->length() == 0) return Smi::FromInt(EQUAL); | 2979 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL); |
2925 return Smi::FromInt(GREATER); | 2980 return Smi::FromInt(GREATER); |
2926 } else if (x->length() == 0) { | 2981 } else if (x->length(x_shape) == 0) { |
2927 return Smi::FromInt(LESS); | 2982 return Smi::FromInt(LESS); |
2928 } | 2983 } |
2929 | 2984 |
2930 int d = x->Get(0) - y->Get(0); | 2985 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0); |
2931 if (d < 0) return Smi::FromInt(LESS); | 2986 if (d < 0) return Smi::FromInt(LESS); |
2932 else if (d > 0) return Smi::FromInt(GREATER); | 2987 else if (d > 0) return Smi::FromInt(GREATER); |
2933 | 2988 |
2934 x->TryFlatten(); | 2989 x->TryFlatten(x_shape); // Shapes are no longer valid! |
2935 y->TryFlatten(); | 2990 y->TryFlatten(y_shape); |
2936 | 2991 |
2937 static StringInputBuffer bufx; | 2992 static StringInputBuffer bufx; |
2938 static StringInputBuffer bufy; | 2993 static StringInputBuffer bufy; |
2939 bufx.Reset(x); | 2994 bufx.Reset(x); |
2940 bufy.Reset(y); | 2995 bufy.Reset(y); |
2941 while (bufx.has_more() && bufy.has_more()) { | 2996 while (bufx.has_more() && bufy.has_more()) { |
2942 int d = bufx.GetNext() - bufy.GetNext(); | 2997 int d = bufx.GetNext() - bufy.GetNext(); |
2943 if (d < 0) return Smi::FromInt(LESS); | 2998 if (d < 0) return Smi::FromInt(LESS); |
2944 else if (d > 0) return Smi::FromInt(GREATER); | 2999 else if (d > 0) return Smi::FromInt(GREATER); |
2945 } | 3000 } |
(...skipping 2841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5787 } else { | 5842 } else { |
5788 // Handle last resort GC and make sure to allow future allocations | 5843 // Handle last resort GC and make sure to allow future allocations |
5789 // to grow the heap without causing GCs (if possible). | 5844 // to grow the heap without causing GCs (if possible). |
5790 Counters::gc_last_resort_from_js.Increment(); | 5845 Counters::gc_last_resort_from_js.Increment(); |
5791 Heap::CollectAllGarbage(); | 5846 Heap::CollectAllGarbage(); |
5792 } | 5847 } |
5793 } | 5848 } |
5794 | 5849 |
5795 | 5850 |
5796 } } // namespace v8::internal | 5851 } } // namespace v8::internal |
OLD | NEW |