| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 0342744 commit eda91b6
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -340,53 +340,44 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo<Value>& args) { | |||
| 340 | 340 | ||
| 341 | 341 | size_t length = source->Length(); | |
| 342 | 342 | size_t utf8_length = 0; | |
| 343 | - bool is_one_byte = source->IsOneByte(); | ||
| 344 | - | ||
| 345 | - if (is_one_byte) { | ||
| 346 | - // One-byte string (Latin1) - copy to buffer first, then process | ||
| 347 | - MaybeStackBuffer<uint8_t, MAX_SIZE_FOR_STACK_ALLOC> latin1_buffer(length); | ||
| 348 | - source->WriteOneByteV2(isolate, 0, length, latin1_buffer.out()); | ||
| 349 | - | ||
| 350 | - auto data = reinterpret_cast<const char*>(latin1_buffer.out()); | ||
| 351 | - | ||
| 352 | - // Check if it's pure ASCII - if so, we can just copy | ||
| 353 | - simdutf::result result = simdutf::validate_ascii_with_errors(data, length); | ||
| 354 | - if (result.error == simdutf::SUCCESS) { | ||
| 355 | - // Pure ASCII - direct copy | ||
| 356 | - std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore( | ||
| 357 | - isolate, length, BackingStoreInitializationMode::kUninitialized); | ||
| 358 | - CHECK(bs); | ||
| 359 | - memcpy(bs->Data(), data, length); | ||
| 360 | - Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs)); | ||
| 361 | - args.GetReturnValue().Set(Uint8Array::New(ab, 0, length)); | ||
| 362 | - return; | ||
| 363 | - } | ||
| 364 | 343 | ||
| 365 | - // Latin1 with non-ASCII characters - need conversion | ||
| 366 | - utf8_length = simdutf::utf8_length_from_latin1(data, length); | ||
| 367 | - std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore( | ||
| 368 | - isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); | ||
| 369 | - CHECK(bs); | ||
| 370 | - [[maybe_unused]] size_t written = simdutf::convert_latin1_to_utf8( | ||
| 371 | - data, length, static_cast<char*>(bs->Data())); | ||
| 372 | - DCHECK_EQ(written, utf8_length); | ||
| 373 | - Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs)); | ||
| 374 | - args.GetReturnValue().Set(Uint8Array::New(ab, 0, utf8_length)); | ||
| 375 | - return; | ||
| 344 | + // Inspect the string's flat content directly to determine the encoding and | ||
| 345 | + // the exact UTF-8 output size, without copying it out of the V8 heap. | ||
| 346 | + // | ||
| 347 | + // v8::String::ValueView holds a DisallowGarbageCollection scope, so it must | ||
| 348 | + // be released before allocating the backing store below. Flattening is cached | ||
| 349 | + // on the string, so re-acquiring the view for the conversion pass is cheap. | ||
| 350 | + bool is_one_byte; | ||
| 351 | + bool is_ascii = false; | ||
| 352 | + bool is_well_formed = true; | ||
| 353 | + { | ||
| 354 | + v8::String::ValueView view(isolate, source); | ||
| 355 | + is_one_byte = view.is_one_byte(); | ||
| 356 | + if (is_one_byte) { | ||
| 357 | + auto data = reinterpret_cast<const char*>(view.data8()); | ||
| 358 | + is_ascii = simdutf::validate_ascii_with_errors(data, length).error == | ||
| 359 | + simdutf::SUCCESS; | ||
| 360 | + utf8_length = | ||
| 361 | + is_ascii ? length : simdutf::utf8_length_from_latin1(data, length); | ||
| 362 | + } else { | ||
| 363 | + auto data = reinterpret_cast<const char16_t*>(view.data16()); | ||
| 364 | + is_well_formed = | ||
| 365 | + simdutf::validate_utf16_with_errors(data, length).error == | ||
| 366 | + simdutf::SUCCESS; | ||
| 367 | + if (is_well_formed) { | ||
| 368 | + utf8_length = simdutf::utf8_length_from_utf16(data, length); | ||
| 369 | + } | ||
| 370 | + } | ||
| 376 | 371 | } | |
| 377 | 372 | ||
| 378 | - // Two-byte string (UTF-16) - copy to buffer first | ||
| 379 | - MaybeStackBuffer<uint16_t, MAX_SIZE_FOR_STACK_ALLOC> utf16_buffer(length); | ||
| 380 | - source->WriteV2(isolate, 0, length, utf16_buffer.out()); | ||
| 381 | - | ||
| 382 | - auto data = reinterpret_cast<char16_t*>(utf16_buffer.out()); | ||
| 383 | - | ||
| 384 | - // Check for unpaired surrogates | ||
| 385 | - simdutf::result validation_result = | ||
| 386 | - simdutf::validate_utf16_with_errors(data, length); | ||
| 373 | + // Rare path: two-byte string with unpaired surrogates. Copy into a mutable | ||
| 374 | + // buffer, make it well-formed, then encode. | ||
| 375 | + if (!is_well_formed) { | ||
| 376 | + MaybeStackBuffer<uint16_t, MAX_SIZE_FOR_STACK_ALLOC> utf16_buffer(length); | ||
| 377 | + source->WriteV2(isolate, 0, length, utf16_buffer.out()); | ||
| 378 | + auto data = reinterpret_cast<char16_t*>(utf16_buffer.out()); | ||
| 379 | + simdutf::to_well_formed_utf16(data, length, data); | ||
| 387 | 380 | ||
| 388 | - if (validation_result.error == simdutf::SUCCESS) { | ||
| 389 | - // Valid UTF-16 - use the fast path | ||
| 390 | 381 | utf8_length = simdutf::utf8_length_from_utf16(data, length); | |
| 391 | 382 | std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore( | |
| 392 | 383 | isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); | |
@@ -399,16 +390,30 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo<Value>& args) { | |||
| 399 | 390 | return; | |
| 400 | 391 | } | |
| 401 | 392 | ||
| 402 | - // Invalid UTF-16 with unpaired surrogates - convert to well-formed in place | ||
| 403 | - simdutf::to_well_formed_utf16(data, length, data); | ||
| 404 | - | ||
| 405 | - utf8_length = simdutf::utf8_length_from_utf16(data, length); | ||
| 393 | + // Common path: allocate the exact-size output, then re-acquire the flat | ||
| 394 | + // content and encode directly into the backing store. | ||
| 406 | 395 | std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore( | |
| 407 | 396 | isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); | |
| 408 | 397 | CHECK(bs); | |
| 409 | - [[maybe_unused]] size_t written = simdutf::convert_utf16_to_utf8( | ||
| 410 | - data, length, static_cast<char*>(bs->Data())); | ||
| 411 | - DCHECK_EQ(written, utf8_length); | ||
| 398 | + char* out = static_cast<char*>(bs->Data()); | ||
| 399 | + { | ||
| 400 | + v8::String::ValueView view(isolate, source); | ||
| 401 | + if (is_one_byte) { | ||
| 402 | + auto data = reinterpret_cast<const char*>(view.data8()); | ||
| 403 | + if (is_ascii) { | ||
| 404 | + memcpy(out, data, length); | ||
| 405 | + } else { | ||
| 406 | + [[maybe_unused]] size_t written = | ||
| 407 | + simdutf::convert_latin1_to_utf8(data, length, out); | ||
| 408 | + DCHECK_EQ(written, utf8_length); | ||
| 409 | + } | ||
| 410 | + } else { | ||
| 411 | + auto data = reinterpret_cast<const char16_t*>(view.data16()); | ||
| 412 | + [[maybe_unused]] size_t written = | ||
| 413 | + simdutf::convert_utf16_to_utf8(data, length, out); | ||
| 414 | + DCHECK_EQ(written, utf8_length); | ||
| 415 | + } | ||
| 416 | + } | ||
| 412 | 417 | Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs)); | |
| 413 | 418 | args.GetReturnValue().Set(Uint8Array::New(ab, 0, utf8_length)); | |
| 414 | 419 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments