22
22
#include " node_buffer.h"
23
23
#include " node.h"
24
24
#include " node_blob.h"
25
+ #include " node_debug.h"
25
26
#include " node_errors.h"
26
27
#include " node_external_reference.h"
27
28
#include " node_i18n.h"
@@ -1442,6 +1443,79 @@ void CopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
1442
1443
memcpy (dest, src, bytes_to_copy);
1443
1444
}
1444
1445
1446
+ size_t convert_latin1_to_utf8_s (const char * src,
1447
+ size_t src_len,
1448
+ char * dst,
1449
+ size_t dst_len) noexcept {
1450
+ size_t src_pos = 0 ;
1451
+ size_t dst_pos = 0 ;
1452
+
1453
+ const auto safe_len = std::min (src_len, dst_len >> 1 );
1454
+ if (safe_len > 16 ) {
1455
+ // convert_latin1_to_utf8 will never write more than input length * 2.
1456
+ dst_pos += simdutf::convert_latin1_to_utf8 (src, safe_len, dst);
1457
+ src_pos += safe_len;
1458
+ }
1459
+
1460
+ // Based on:
1461
+ // https://github.com/simdutf/simdutf/blob/master/src/scalar/latin1_to_utf8/latin1_to_utf8.h
1462
+ // with an upper limit on the number of bytes to write.
1463
+
1464
+ const auto src_ptr = reinterpret_cast <const uint8_t *>(src);
1465
+ const auto dst_ptr = reinterpret_cast <uint8_t *>(dst);
1466
+
1467
+ size_t skip_pos = src_pos;
1468
+ while (src_pos < src_len && dst_pos < dst_len) {
1469
+ if (skip_pos <= src_pos && src_pos + 16 <= src_len &&
1470
+ dst_pos + 16 <= dst_len) {
1471
+ uint64_t v1;
1472
+ memcpy (&v1, src_ptr + src_pos + 0 , 8 );
1473
+ uint64_t v2;
1474
+ memcpy (&v2, src_ptr + src_pos + 8 , 8 );
1475
+ if (((v1 | v2) & UINT64_C (0x8080808080808080 )) == 0 ) {
1476
+ memcpy (dst_ptr + dst_pos, src_ptr + src_pos, 16 );
1477
+ dst_pos += 16 ;
1478
+ src_pos += 16 ;
1479
+ } else {
1480
+ skip_pos = src_pos + 16 ;
1481
+ }
1482
+ } else {
1483
+ const auto byte = src_ptr[src_pos++];
1484
+ if ((byte & 0x80 ) == 0 ) {
1485
+ dst_ptr[dst_pos++] = byte;
1486
+ } else if (dst_pos + 2 <= dst_len) {
1487
+ dst_ptr[dst_pos++] = (byte >> 6 ) | 0b11000000 ;
1488
+ dst_ptr[dst_pos++] = (byte & 0b111111 ) | 0b10000000 ;
1489
+ } else {
1490
+ break ;
1491
+ }
1492
+ }
1493
+ }
1494
+
1495
+ return dst_pos;
1496
+ }
1497
+
1498
+ template <encoding encoding>
1499
+ uint32_t WriteOneByteString (const char * src,
1500
+ uint32_t src_len,
1501
+ char * dst,
1502
+ uint32_t dst_len) {
1503
+ if (dst_len == 0 ) {
1504
+ return 0 ;
1505
+ }
1506
+
1507
+ if (encoding == UTF8) {
1508
+ return convert_latin1_to_utf8_s (src, src_len, dst, dst_len);
1509
+ } else if (encoding == LATIN1 || encoding == ASCII) {
1510
+ const auto size = std::min (src_len, dst_len);
1511
+ memcpy (dst, src, size);
1512
+ return size;
1513
+ } else {
1514
+ // TODO(ronag): Add support for more encoding.
1515
+ UNREACHABLE ();
1516
+ }
1517
+ }
1518
+
1445
1519
template <encoding encoding>
1446
1520
void SlowWriteString (const FunctionCallbackInfo<Value>& args) {
1447
1521
Environment* env = Environment::GetCurrent (args);
@@ -1464,11 +1538,22 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) {
1464
1538
1465
1539
if (max_length == 0 ) return args.GetReturnValue ().Set (0 );
1466
1540
1467
- uint32_t written = StringBytes::Write (
1468
- env->isolate (), ts_obj_data + offset, max_length, str, encoding);
1541
+ uint32_t written = 0 ;
1542
+
1543
+ if ((encoding == UTF8 || encoding == LATIN1 || encoding == ASCII) &&
1544
+ str->IsExternalOneByte ()) {
1545
+ const auto src = str->GetExternalOneByteStringResource ();
1546
+ written = WriteOneByteString<encoding>(
1547
+ src->data (), src->length (), ts_obj_data + offset, max_length);
1548
+ } else {
1549
+ written = StringBytes::Write (
1550
+ env->isolate (), ts_obj_data + offset, max_length, str, encoding);
1551
+ }
1552
+
1469
1553
args.GetReturnValue ().Set (written);
1470
1554
}
1471
1555
1556
+ template <encoding encoding>
1472
1557
uint32_t FastWriteString (Local<Value> receiver,
1473
1558
const v8::FastApiTypedArray<uint8_t >& dst,
1474
1559
const v8::FastOneByteString& src,
@@ -1478,16 +1563,21 @@ uint32_t FastWriteString(Local<Value> receiver,
1478
1563
CHECK (dst.getStorageIfAligned (&dst_data));
1479
1564
CHECK (offset <= dst.length ());
1480
1565
CHECK (dst.length () - offset <= std::numeric_limits<uint32_t >::max ());
1566
+ TRACK_V8_FAST_API_CALL (" buffer.writeString" );
1481
1567
1482
- const auto size = std::min (
1483
- {static_cast <uint32_t >(dst.length () - offset), max_length, src.length });
1484
-
1485
- memcpy (dst_data + offset, src.data , size);
1486
-
1487
- return size;
1568
+ return WriteOneByteString<encoding>(
1569
+ src.data ,
1570
+ src.length ,
1571
+ reinterpret_cast <char *>(dst_data + offset),
1572
+ std::min<uint32_t >(dst.length () - offset, max_length));
1488
1573
}
1489
1574
1490
- static v8::CFunction fast_write_string (v8::CFunction::Make(FastWriteString));
1575
+ static v8::CFunction fast_write_string_ascii (
1576
+ v8::CFunction::Make (FastWriteString<ASCII>));
1577
+ static v8::CFunction fast_write_string_latin1 (
1578
+ v8::CFunction::Make (FastWriteString<LATIN1>));
1579
+ static v8::CFunction fast_write_string_utf8 (
1580
+ v8::CFunction::Make (FastWriteString<UTF8>));
1491
1581
1492
1582
void Initialize (Local<Object> target,
1493
1583
Local<Value> unused,
@@ -1554,9 +1644,21 @@ void Initialize(Local<Object> target,
1554
1644
SetMethod (context, target, " hexWrite" , StringWrite<HEX>);
1555
1645
SetMethod (context, target, " ucs2Write" , StringWrite<UCS2>);
1556
1646
1557
- SetMethod (context, target, " asciiWriteStatic" , SlowWriteString<ASCII>);
1558
- SetMethod (context, target, " latin1WriteStatic" , SlowWriteString<LATIN1>);
1559
- SetMethod (context, target, " utf8WriteStatic" , SlowWriteString<UTF8>);
1647
+ SetFastMethod (context,
1648
+ target,
1649
+ " asciiWriteStatic" ,
1650
+ SlowWriteString<ASCII>,
1651
+ &fast_write_string_ascii);
1652
+ SetFastMethod (context,
1653
+ target,
1654
+ " latin1WriteStatic" ,
1655
+ SlowWriteString<LATIN1>,
1656
+ &fast_write_string_latin1);
1657
+ SetFastMethod (context,
1658
+ target,
1659
+ " utf8WriteStatic" ,
1660
+ SlowWriteString<UTF8>,
1661
+ &fast_write_string_utf8);
1560
1662
1561
1663
SetMethod (context, target, " getZeroFillToggle" , GetZeroFillToggle);
1562
1664
}
@@ -1601,8 +1703,12 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1601
1703
registry->Register (SlowWriteString<ASCII>);
1602
1704
registry->Register (SlowWriteString<LATIN1>);
1603
1705
registry->Register (SlowWriteString<UTF8>);
1604
- registry->Register (fast_write_string.GetTypeInfo ());
1605
- registry->Register (FastWriteString);
1706
+ registry->Register (FastWriteString<ASCII>);
1707
+ registry->Register (fast_write_string_ascii.GetTypeInfo ());
1708
+ registry->Register (FastWriteString<LATIN1>);
1709
+ registry->Register (fast_write_string_latin1.GetTypeInfo ());
1710
+ registry->Register (FastWriteString<UTF8>);
1711
+ registry->Register (fast_write_string_utf8.GetTypeInfo ());
1606
1712
registry->Register (StringWrite<ASCII>);
1607
1713
registry->Register (StringWrite<BASE64>);
1608
1714
registry->Register (StringWrite<BASE64URL>);
0 commit comments