Commit b912d545 authored by Andy Wingo's avatar Andy Wingo Committed by V8 LUCI CQ

[stringrefs] Move WTF-8 string handling closer to UTF-8

No functional change.

Bug: v8:12868
Change-Id: I5f09861e2b5beb400dcc1656f80230404cf544b4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3693704Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andy Wingo <wingo@igalia.com>
Cr-Commit-Position: refs/heads/main@{#80996}
parent 9a5f1fa1
......@@ -2552,8 +2552,6 @@ filegroup(
"src/wasm/wasm-subtyping.h",
"src/wasm/wasm-tier.h",
"src/wasm/wasm-value.h",
"src/wasm/wtf8.cc",
"src/wasm/wtf8.h",
],
"//conditions:default": [],
}),
......
......@@ -3623,7 +3623,6 @@ v8_header_set("v8_internal_headers") {
"src/wasm/wasm-subtyping.h",
"src/wasm/wasm-tier.h",
"src/wasm/wasm-value.h",
"src/wasm/wtf8.h",
]
}
......@@ -4688,7 +4687,6 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/wasm-result.cc",
"src/wasm/wasm-serialization.cc",
"src/wasm/wasm-subtyping.cc",
"src/wasm/wtf8.cc",
]
}
......
......@@ -699,37 +699,75 @@ MaybeHandle<String> Factory::NewStringFromOneByte(
return result;
}
MaybeHandle<String> Factory::NewStringFromUtf8(
const base::Vector<const char>& string, AllocationType allocation) {
base::Vector<const uint8_t> utf8_data =
base::Vector<const uint8_t>::cast(string);
Utf8Decoder decoder(utf8_data);
namespace {
template <typename Decoder, typename Handler>
MaybeHandle<String> NewStringFromBytes(Isolate* isolate,
const base::Vector<const uint8_t>& data,
AllocationType allocation,
Handler throw_invalid) {
Decoder decoder(data);
if (decoder.is_invalid()) {
throw_invalid();
DCHECK(isolate->has_pending_exception());
return MaybeHandle<String>();
}
if (decoder.utf16_length() == 0) return empty_string();
if (decoder.utf16_length() == 0) return isolate->factory()->empty_string();
if (decoder.is_one_byte()) {
if (data.size() == 1) {
return isolate->factory()->LookupSingleCharacterStringFromCode(data[0]);
}
// Allocate string.
Handle<SeqOneByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result,
NewRawOneByteString(decoder.utf16_length(), allocation), String);
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
isolate->factory()->NewRawOneByteString(
decoder.utf16_length(), allocation),
String);
DisallowGarbageCollection no_gc;
decoder.Decode(result->GetChars(no_gc), utf8_data);
decoder.Decode(result->GetChars(no_gc), data);
return result;
}
// Allocate string.
Handle<SeqTwoByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result,
NewRawTwoByteString(decoder.utf16_length(), allocation), String);
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
isolate->factory()->NewRawTwoByteString(
decoder.utf16_length(), allocation),
String);
DisallowGarbageCollection no_gc;
decoder.Decode(result->GetChars(no_gc), utf8_data);
decoder.Decode(result->GetChars(no_gc), data);
return result;
}
} // namespace
MaybeHandle<String> Factory::NewStringFromUtf8(
const base::Vector<const char>& string, AllocationType allocation) {
auto handler = [&]() { UNREACHABLE(); };
return NewStringFromBytes<Utf8Decoder>(
isolate(), base::Vector<const uint8_t>::cast(string), allocation,
handler);
}
#if V8_ENABLE_WEBASSEMBLY
MaybeHandle<String> Factory::NewStringFromWtf8(
const base::Vector<const uint8_t>& string, AllocationType allocation) {
auto handler = [&]() {
Handle<JSObject> error_obj =
NewWasmRuntimeError(MessageTemplate::kWasmTrapStringInvalidWtf8);
JSObject::AddProperty(isolate(), error_obj, wasm_uncatchable_symbol(),
true_value(), NONE);
isolate()->Throw(*error_obj);
};
return NewStringFromBytes<Wtf8Decoder>(isolate(), string, allocation,
handler);
}
#endif // V8_ENABLE_WEBASSEMBLY
MaybeHandle<String> Factory::NewStringFromUtf8SubString(
Handle<SeqOneByteString> str, int begin, int length,
AllocationType allocation) {
......@@ -819,6 +857,21 @@ MaybeHandle<String> Factory::NewStringFromTwoByte(
allocation);
}
#if V8_ENABLE_WEBASSEMBLY
MaybeHandle<String> Factory::NewStringFromTwoByteLittleEndian(
const base::Vector<const base::uc16>& str, AllocationType allocation) {
#if defined(V8_TARGET_LITTLE_ENDIAN)
return NewStringFromTwoByte(str, allocation);
#elif defined(V8_TARGET_BIG_ENDIAN)
// TODO(12868): Duplicate the guts of NewStringFromTwoByte, so that
// copying and transcoding the data can be done in a single pass.
UNIMPLEMENTED();
#else
#error Unknown endianness
#endif
}
#endif // V8_ENABLE_WEBASSEMBLY
namespace {
inline void WriteOneByteData(Handle<String> s, uint8_t* chars, int len) {
......
......@@ -256,6 +256,15 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
const base::Vector<const char>& str,
AllocationType allocation = AllocationType::kYoung);
#if V8_ENABLE_WEBASSEMBLY
// The WTF-8 encoding is just like UTF-8 except that it can also represent
// isolated surrogate codepoints. It can represent all strings that
// JavaScript's strings can.
V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromWtf8(
const base::Vector<const uint8_t>& str,
AllocationType allocation = AllocationType::kYoung);
#endif // V8_ENABLE_WEBASSEMBLY
V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromUtf8SubString(
Handle<SeqOneByteString> str, int begin, int end,
AllocationType allocation = AllocationType::kYoung);
......@@ -268,6 +277,14 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
const ZoneVector<base::uc16>* str,
AllocationType allocation = AllocationType::kYoung);
#if V8_ENABLE_WEBASSEMBLY
// Usually the two-byte encodings are in the native endianness, but for
// WebAssembly linear memory, they are explicitly little-endian.
V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromTwoByteLittleEndian(
const base::Vector<const base::uc16>& str,
AllocationType allocation = AllocationType::kYoung);
#endif // V8_ENABLE_WEBASSEMBLY
Handle<JSStringIterator> NewJSStringIterator(Handle<String> string);
Handle<String> NewInternalizedStringImpl(Handle<String> string, int chars,
......
......@@ -26,7 +26,6 @@
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-subtyping.h"
#include "src/wasm/wasm-value.h"
#include "src/wasm/wtf8.h"
namespace v8 {
namespace internal {
......@@ -827,56 +826,6 @@ RUNTIME_FUNCTION(Runtime_WasmCreateResumePromise) {
return *result;
}
namespace {
Object NewStringFromWtf8(Isolate* isolate,
const base::Vector<const uint8_t>& data) {
wasm::Wtf8Decoder decoder(data);
if (!decoder.is_valid()) {
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapStringInvalidWtf8);
}
if (decoder.utf16_length() == 0) return *isolate->factory()->empty_string();
if (decoder.is_one_byte()) {
if (data.size() == 1) {
return *isolate->factory()->LookupSingleCharacterStringFromCode(data[0]);
}
Handle<SeqOneByteString> result;
// TODO(12868): Override any exception with an uncatchable-by-wasm trap.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewRawOneByteString(decoder.utf16_length()));
DisallowGarbageCollection no_gc;
decoder.Decode(result->GetChars(no_gc), data);
return *result;
}
Handle<SeqTwoByteString> result;
// TODO(12868): Override any exception with an uncatchable-by-wasm trap.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewRawTwoByteString(decoder.utf16_length()));
DisallowGarbageCollection no_gc;
decoder.Decode(result->GetChars(no_gc), data);
return *result;
}
Object NewStringFromWtf16(Isolate* isolate,
const base::Vector<const base::uc16>& data) {
#if defined(V8_TARGET_LITTLE_ENDIAN)
// TODO(12868): Override any exception with an uncatchable-by-wasm trap.
RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromTwoByte(
data, AllocationType::kYoung));
#elif defined(V8_TARGET_BIG_ENDIAN)
// TODO(12868): Duplicate the guts of NewStringFromTwoByte, so that
// copying and transcoding the data can be done in a single pass.
UNIMPLEMENTED();
#else
#error Unknown endianness
#endif
}
} // namespace
// Returns the new string if the operation succeeds. Otherwise throws an
// exception and returns an empty result.
RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8) {
......@@ -898,7 +847,11 @@ RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8) {
const base::Vector<const uint8_t> bytes{instance->memory_start() + offset,
size};
return NewStringFromWtf8(isolate, bytes);
// TODO(12868): Override any exception with an uncatchable-by-wasm trap.
Handle<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, isolate->factory()->NewStringFromWtf8(bytes));
return *result;
}
RUNTIME_FUNCTION(Runtime_WasmStringNewWtf16) {
......@@ -924,7 +877,13 @@ RUNTIME_FUNCTION(Runtime_WasmStringNewWtf16) {
const byte* bytes = instance->memory_start() + offset;
const base::uc16* codeunits = reinterpret_cast<const base::uc16*>(bytes);
return NewStringFromWtf16(isolate, {codeunits, size_in_codeunits});
// TODO(12868): Override any exception with an uncatchable-by-wasm trap.
Handle<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewStringFromTwoByteLittleEndian(
{codeunits, size_in_codeunits}));
return *result;
}
} // namespace internal
......
......@@ -7,6 +7,10 @@
#include "src/strings/unicode-inl.h"
#include "src/utils/memcopy.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/third_party/utf8-decoder/generalized-utf8-decoder.h"
#endif
namespace v8 {
namespace internal {
......@@ -77,5 +81,76 @@ template V8_EXPORT_PRIVATE void Utf8Decoder::Decode(
template V8_EXPORT_PRIVATE void Utf8Decoder::Decode(
uint16_t* out, const base::Vector<const uint8_t>& data);
#if V8_ENABLE_WEBASSEMBLY
Wtf8Decoder::Wtf8Decoder(const base::Vector<const uint8_t>& data)
: encoding_(Encoding::kAscii),
non_ascii_start_(NonAsciiStart(data.begin(), data.length())),
utf16_length_(non_ascii_start_) {
if (non_ascii_start_ == data.length()) return;
bool is_one_byte = true;
auto state = GeneralizedUtf8DfaDecoder::kAccept;
uint32_t current = 0;
uint32_t previous = 0;
for (size_t i = non_ascii_start_; i < data.size(); i++) {
GeneralizedUtf8DfaDecoder::Decode(data[i], &state, &current);
if (state < GeneralizedUtf8DfaDecoder::kAccept) {
DCHECK_EQ(state, GeneralizedUtf8DfaDecoder::kReject);
encoding_ = Encoding::kInvalid;
return;
}
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
if (unibrow::Utf16::IsTrailSurrogate(current) &&
unibrow::Utf16::IsLeadSurrogate(previous)) {
encoding_ = Encoding::kInvalid;
return;
}
is_one_byte = is_one_byte && current <= unibrow::Latin1::kMaxChar;
utf16_length_++;
if (current > unibrow::Utf16::kMaxNonSurrogateCharCode) utf16_length_++;
previous = current;
current = 0;
}
}
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
encoding_ = is_one_byte ? Encoding::kLatin1 : Encoding::kUtf16;
} else {
encoding_ = Encoding::kInvalid;
}
}
template <typename Char>
void Wtf8Decoder::Decode(Char* out, const base::Vector<const uint8_t>& data) {
DCHECK(!is_invalid());
CopyChars(out, data.begin(), non_ascii_start_);
out += non_ascii_start_;
auto state = GeneralizedUtf8DfaDecoder::kAccept;
uint32_t t = 0;
for (size_t i = non_ascii_start_; i < data.size(); i++) {
GeneralizedUtf8DfaDecoder::Decode(data[i], &state, &t);
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
if (sizeof(Char) == 1 || t <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
*(out++) = static_cast<Char>(t);
} else {
*(out++) = unibrow::Utf16::LeadSurrogate(t);
*(out++) = unibrow::Utf16::TrailSurrogate(t);
}
t = 0;
}
}
DCHECK_EQ(state, GeneralizedUtf8DfaDecoder::kAccept);
}
template void Wtf8Decoder::Decode(uint8_t* out,
const base::Vector<const uint8_t>& data);
template void Wtf8Decoder::Decode(uint16_t* out,
const base::Vector<const uint8_t>& data);
#endif // V8_ENABLE_WEBASSEMBLY
} // namespace internal
} // namespace v8
......@@ -54,6 +54,9 @@ class V8_EXPORT_PRIVATE Utf8Decoder final {
explicit Utf8Decoder(const base::Vector<const uint8_t>& chars);
// This decoder never fails; an invalid byte sequence decodes to U+FFFD and
// then the decode continues.
bool is_invalid() const { return false; }
bool is_ascii() const { return encoding_ == Encoding::kAscii; }
bool is_one_byte() const { return encoding_ <= Encoding::kLatin1; }
int utf16_length() const { return utf16_length_; }
......@@ -69,6 +72,38 @@ class V8_EXPORT_PRIVATE Utf8Decoder final {
int utf16_length_;
};
#if V8_ENABLE_WEBASSEMBLY
// Like Utf8Decoder above, except that instead of replacing invalid sequences
// with U+FFFD, we have a separate Encoding::kInvalid state.
class Wtf8Decoder {
public:
enum class Encoding : uint8_t { kAscii, kLatin1, kUtf16, kInvalid };
explicit Wtf8Decoder(const base::Vector<const uint8_t>& data);
bool is_invalid() const { return encoding_ == Encoding::kInvalid; }
bool is_ascii() const { return encoding_ == Encoding::kAscii; }
bool is_one_byte() const { return encoding_ <= Encoding::kLatin1; }
int utf16_length() const {
DCHECK(!is_invalid());
return utf16_length_;
}
int non_ascii_start() const {
DCHECK(!is_invalid());
return non_ascii_start_;
}
template <typename Char>
V8_EXPORT_PRIVATE void Decode(Char* out,
const base::Vector<const uint8_t>& data);
private:
Encoding encoding_;
int non_ascii_start_;
int utf16_length_;
};
#endif // V8_ENABLE_WEBASSEMBLY
} // namespace internal
} // namespace v8
......
......@@ -9,6 +9,10 @@
#include <stdlib.h>
#include "src/strings/unicode-inl.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/third_party/utf8-decoder/generalized-utf8-decoder.h"
#endif
#ifdef V8_INTL_SUPPORT
#include "unicode/uchar.h"
#endif
......@@ -231,6 +235,28 @@ bool Utf8::ValidateEncoding(const byte* bytes, size_t length) {
return state == State::kAccept;
}
#if V8_ENABLE_WEBASSEMBLY
bool Wtf8::ValidateEncoding(const byte* bytes, size_t length) {
using State = GeneralizedUtf8DfaDecoder::State;
auto state = State::kAccept;
uint32_t current = 0;
uint32_t previous = 0;
for (size_t i = 0; i < length; i++) {
GeneralizedUtf8DfaDecoder::Decode(bytes[i], &state, &current);
if (state == State::kReject) return false;
if (state == State::kAccept) {
if (Utf16::IsTrailSurrogate(current) &&
Utf16::IsLeadSurrogate(previous)) {
return false;
}
previous = current;
current = 0;
}
}
return state == State::kAccept;
}
#endif // V8_ENABLE_WEBASSEMBLY
// Uppercase: point.category == 'Lu'
// TODO(jshin): Check if it's ok to exclude Other_Uppercase characters.
#ifdef V8_INTL_SUPPORT
......
......@@ -200,6 +200,23 @@ class V8_EXPORT_PRIVATE Utf8 {
static bool ValidateEncoding(const byte* str, size_t length);
};
#if V8_ENABLE_WEBASSEMBLY
class Wtf8 {
public:
// Validate that the input has a valid WTF-8 encoding.
//
// This method checks for:
// - valid utf-8 endcoding (e.g. no over-long encodings),
// - absence of surrogate pairs,
// - valid code point range.
//
// In terms of the WTF-8 specification (https://simonsapin.github.io/wtf-8/),
// this function checks for a valid "generalized UTF-8" sequence, with the
// additional constraint that surrogate pairs are not allowed.
static bool ValidateEncoding(const byte* str, size_t length);
};
#endif // V8_ENABLE_WEBASSEMBLY
struct Uppercase {
static bool Is(uchar c);
};
......
......@@ -22,7 +22,6 @@
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-opcodes-inl.h"
#include "src/wasm/wtf8.h"
namespace v8 {
namespace internal {
......@@ -139,7 +138,7 @@ WireBytesRef consume_string(Decoder* decoder, StringValidation validation,
}
break;
case StringValidation::kWtf8:
if (!Wtf8::ValidateEncoding(string_start, length)) {
if (!unibrow::Wtf8::ValidateEncoding(string_start, length)) {
decoder->errorf(string_start, "%s: no valid WTF-8 string", name);
}
break;
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/wtf8.h"
#include "src/strings/unicode-decoder.h"
#include "src/strings/unicode.h"
#include "src/third_party/utf8-decoder/generalized-utf8-decoder.h"
#include "src/utils/memcopy.h"
namespace v8 {
namespace internal {
namespace wasm {
bool Wtf8::ValidateEncoding(const byte* bytes, size_t length) {
auto state = GeneralizedUtf8DfaDecoder::kAccept;
uint32_t current = 0;
uint32_t previous = 0;
for (size_t i = 0; i < length; i++) {
GeneralizedUtf8DfaDecoder::Decode(bytes[i], &state, &current);
if (state == GeneralizedUtf8DfaDecoder::kReject) return false;
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
if (unibrow::Utf16::IsTrailSurrogate(current) &&
unibrow::Utf16::IsLeadSurrogate(previous)) {
return false;
}
previous = current;
current = 0;
}
}
return state == GeneralizedUtf8DfaDecoder::kAccept;
}
Wtf8Decoder::Wtf8Decoder(const base::Vector<const uint8_t>& data)
: encoding_(Encoding::kAscii),
non_ascii_start_(NonAsciiStart(data.begin(), data.length())),
utf16_length_(non_ascii_start_) {
if (non_ascii_start_ == data.length()) return;
bool is_one_byte = true;
auto state = GeneralizedUtf8DfaDecoder::kAccept;
uint32_t current = 0;
uint32_t previous = 0;
for (size_t i = non_ascii_start_; i < data.size(); i++) {
GeneralizedUtf8DfaDecoder::Decode(data[i], &state, &current);
if (state < GeneralizedUtf8DfaDecoder::kAccept) {
DCHECK_EQ(state, GeneralizedUtf8DfaDecoder::kReject);
encoding_ = Encoding::kInvalid;
return;
}
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
if (unibrow::Utf16::IsTrailSurrogate(current) &&
unibrow::Utf16::IsLeadSurrogate(previous)) {
encoding_ = Encoding::kInvalid;
return;
}
is_one_byte = is_one_byte && current <= unibrow::Latin1::kMaxChar;
utf16_length_++;
if (current > unibrow::Utf16::kMaxNonSurrogateCharCode) utf16_length_++;
previous = current;
current = 0;
}
}
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
encoding_ = is_one_byte ? Encoding::kLatin1 : Encoding::kUtf16;
} else {
encoding_ = Encoding::kInvalid;
}
}
template <typename Char>
void Wtf8Decoder::Decode(Char* out, const base::Vector<const uint8_t>& data) {
DCHECK(is_valid());
CopyChars(out, data.begin(), non_ascii_start_);
out += non_ascii_start_;
auto state = GeneralizedUtf8DfaDecoder::kAccept;
uint32_t t = 0;
for (size_t i = non_ascii_start_; i < data.size(); i++) {
GeneralizedUtf8DfaDecoder::Decode(data[i], &state, &t);
if (state == GeneralizedUtf8DfaDecoder::kAccept) {
if (sizeof(Char) == 1 || t <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
*(out++) = static_cast<Char>(t);
} else {
*(out++) = unibrow::Utf16::LeadSurrogate(t);
*(out++) = unibrow::Utf16::TrailSurrogate(t);
}
t = 0;
}
}
DCHECK_EQ(state, GeneralizedUtf8DfaDecoder::kAccept);
}
template void Wtf8Decoder::Decode(uint8_t* out,
const base::Vector<const uint8_t>& data);
template void Wtf8Decoder::Decode(uint16_t* out,
const base::Vector<const uint8_t>& data);
} // namespace wasm
} // namespace internal
} // namespace v8
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#ifndef V8_WASM_WTF8_H_
#define V8_WASM_WTF8_H_
#include <cinttypes>
#include <cstdarg>
#include <memory>
#include "src/base/vector.h"
#include "src/strings/unicode.h"
namespace v8 {
namespace internal {
namespace wasm {
using byte = unibrow::byte;
class Wtf8 {
public:
// Validate that the input has a valid WTF-8 encoding.
//
// This method checks for:
// - valid utf-8 endcoding (e.g. no over-long encodings),
// - absence of surrogate pairs,
// - valid code point range.
//
// In terms of the WTF-8 specification (https://simonsapin.github.io/wtf-8/),
// this function checks for a valid "generalized UTF-8" sequence, with the
// additional constraint that surrogate pairs are not allowed.
static bool ValidateEncoding(const byte* str, size_t length);
};
// Like Utf8Decoder, except that instead of replacing invalid sequences with
// U+FFFD, we have a separate Encoding::kInvalid state.
class Wtf8Decoder {
public:
enum class Encoding : uint8_t { kAscii, kLatin1, kUtf16, kInvalid };
explicit Wtf8Decoder(const base::Vector<const uint8_t>& data);
bool is_valid() const { return encoding_ != Encoding::kInvalid; }
bool is_ascii() const { return encoding_ == Encoding::kAscii; }
bool is_one_byte() const { return encoding_ <= Encoding::kLatin1; }
int utf16_length() const {
DCHECK(is_valid());
return utf16_length_;
}
int non_ascii_start() const {
DCHECK(is_valid());
return non_ascii_start_;
}
template <typename Char>
V8_EXPORT_PRIVATE void Decode(Char* out,
const base::Vector<const uint8_t>& data);
private:
Encoding encoding_;
int non_ascii_start_;
int utf16_length_;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_WTF8_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment