[string-iswellformed] Implement String#{is,to}WellFormed
Bug: v8:13557 Change-Id: I6fa772c70d8307eca047fd839058279ce244f0e0 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4118066 Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Shu-yu Guo <syg@chromium.org> Cr-Commit-Position: refs/heads/main@{#85002}
This commit is contained in:
parent
c74a6cd257
commit
5c7fca4a61
@ -861,6 +861,7 @@ filegroup(
|
||||
"src/builtins/string-html.tq",
|
||||
"src/builtins/string-includes.tq",
|
||||
"src/builtins/string-indexof.tq",
|
||||
"src/builtins/string-iswellformed.tq",
|
||||
"src/builtins/string-iterator.tq",
|
||||
"src/builtins/string-match-search.tq",
|
||||
"src/builtins/string-pad.tq",
|
||||
@ -870,6 +871,7 @@ filegroup(
|
||||
"src/builtins/string-startswith.tq",
|
||||
"src/builtins/string-substr.tq",
|
||||
"src/builtins/string-substring.tq",
|
||||
"src/builtins/string-towellformed.tq",
|
||||
"src/builtins/string-trim.tq",
|
||||
"src/builtins/symbol.tq",
|
||||
"src/builtins/torque-internal.tq",
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -1801,6 +1801,7 @@ torque_files = [
|
||||
"src/builtins/string-html.tq",
|
||||
"src/builtins/string-includes.tq",
|
||||
"src/builtins/string-indexof.tq",
|
||||
"src/builtins/string-iswellformed.tq",
|
||||
"src/builtins/string-iterator.tq",
|
||||
"src/builtins/string-match-search.tq",
|
||||
"src/builtins/string-pad.tq",
|
||||
@ -1810,6 +1811,7 @@ torque_files = [
|
||||
"src/builtins/string-startswith.tq",
|
||||
"src/builtins/string-substr.tq",
|
||||
"src/builtins/string-substring.tq",
|
||||
"src/builtins/string-towellformed.tq",
|
||||
"src/builtins/string-trim.tq",
|
||||
"src/builtins/symbol.tq",
|
||||
"src/builtins/torque-internal.tq",
|
||||
|
@ -1492,6 +1492,61 @@ TNode<Int32T> StringBuiltinsAssembler::LoadSurrogatePairAt(
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<BoolT> StringBuiltinsAssembler::HasUnpairedSurrogate(TNode<String> string,
|
||||
Label* if_indirect) {
|
||||
TNode<Uint16T> instance_type = LoadInstanceType(string);
|
||||
CSA_DCHECK(this, Word32Equal(Word32And(instance_type,
|
||||
Int32Constant(kStringEncodingMask)),
|
||||
Int32Constant(kTwoByteStringTag)));
|
||||
GotoIfNot(Word32Equal(Word32And(instance_type,
|
||||
Int32Constant(kIsIndirectStringMask |
|
||||
kUncachedExternalStringMask)),
|
||||
Int32Constant(0)),
|
||||
if_indirect);
|
||||
|
||||
TNode<RawPtrT> string_data = DirectStringData(string, instance_type);
|
||||
TNode<IntPtrT> length = LoadStringLengthAsWord(string);
|
||||
|
||||
const TNode<ExternalReference> has_unpaired_surrogate =
|
||||
ExternalConstant(ExternalReference::has_unpaired_surrogate());
|
||||
return UncheckedCast<BoolT>(
|
||||
CallCFunction(has_unpaired_surrogate, MachineType::Uint32(),
|
||||
std::make_pair(MachineType::Pointer(), string_data),
|
||||
std::make_pair(MachineType::IntPtr(), length)));
|
||||
}
|
||||
|
||||
void StringBuiltinsAssembler::ReplaceUnpairedSurrogates(TNode<String> source,
|
||||
TNode<String> dest,
|
||||
Label* if_indirect) {
|
||||
TNode<Uint16T> source_instance_type = LoadInstanceType(source);
|
||||
CSA_DCHECK(this, Word32Equal(Word32And(source_instance_type,
|
||||
Int32Constant(kStringEncodingMask)),
|
||||
Int32Constant(kTwoByteStringTag)));
|
||||
GotoIfNot(Word32Equal(Word32And(source_instance_type,
|
||||
Int32Constant(kIsIndirectStringMask |
|
||||
kUncachedExternalStringMask)),
|
||||
Int32Constant(0)),
|
||||
if_indirect);
|
||||
|
||||
TNode<RawPtrT> source_data = DirectStringData(source, source_instance_type);
|
||||
// The destination string is a freshly allocated SeqString, and so is always
|
||||
// direct.
|
||||
TNode<Uint16T> dest_instance_type = LoadInstanceType(dest);
|
||||
CSA_DCHECK(this, Word32Equal(Word32And(dest_instance_type,
|
||||
Int32Constant(kStringEncodingMask)),
|
||||
Int32Constant(kTwoByteStringTag)));
|
||||
TNode<RawPtrT> dest_data = DirectStringData(dest, dest_instance_type);
|
||||
TNode<IntPtrT> length = LoadStringLengthAsWord(source);
|
||||
CSA_DCHECK(this, IntPtrEqual(length, LoadStringLengthAsWord(dest)));
|
||||
|
||||
const TNode<ExternalReference> replace_unpaired_surrogates =
|
||||
ExternalConstant(ExternalReference::replace_unpaired_surrogates());
|
||||
CallCFunction(replace_unpaired_surrogates, MachineType::Pointer(),
|
||||
std::make_pair(MachineType::Pointer(), source_data),
|
||||
std::make_pair(MachineType::Pointer(), dest_data),
|
||||
std::make_pair(MachineType::IntPtr(), length));
|
||||
}
|
||||
|
||||
void StringBuiltinsAssembler::BranchIfStringPrimitiveWithNoCustomIteration(
|
||||
TNode<Object> object, TNode<Context> context, Label* if_true,
|
||||
Label* if_false) {
|
||||
|
@ -33,6 +33,10 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<Int32T> LoadSurrogatePairAt(TNode<String> string, TNode<IntPtrT> length,
|
||||
TNode<IntPtrT> index,
|
||||
UnicodeEncoding encoding);
|
||||
TNode<BoolT> HasUnpairedSurrogate(TNode<String> string, Label* if_indirect);
|
||||
|
||||
void ReplaceUnpairedSurrogates(TNode<String> source, TNode<String> dest,
|
||||
Label* if_indirect);
|
||||
|
||||
TNode<String> StringFromSingleUTF16EncodedCodePoint(TNode<Int32T> codepoint);
|
||||
|
||||
|
45
src/builtins/string-iswellformed.tq
Normal file
45
src/builtins/string-iswellformed.tq
Normal file
@ -0,0 +1,45 @@
|
||||
// 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/builtins/builtins-string-gen.h'
|
||||
|
||||
namespace runtime {
|
||||
extern runtime StringIsWellFormed(Context, String): Boolean;
|
||||
}
|
||||
|
||||
namespace string {
|
||||
|
||||
extern macro StringBuiltinsAssembler::HasUnpairedSurrogate(String):
|
||||
bool labels Indirect;
|
||||
|
||||
transitioning javascript builtin
|
||||
StringPrototypeIsWellFormed(
|
||||
js-implicit context: NativeContext,
|
||||
receiver: JSAny)(...arguments): Boolean {
|
||||
const methodName: constexpr string = 'String.prototype.isWellFormed';
|
||||
|
||||
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||
// 2. Let S be ? ToString(O).
|
||||
const s = ToThisString(receiver, methodName);
|
||||
|
||||
// 3. Return IsStringWellFormedUnicode(S).
|
||||
|
||||
// Fast path: one-byte strings cannot have unpaired surrogates and are
|
||||
// definitionally well-formed.
|
||||
if (s.StringInstanceType().is_one_byte) return True;
|
||||
|
||||
// Slow path: flatten the string and look for unpaired surrogates.
|
||||
//
|
||||
// TODO(v8:13557): The two-byte case can be optimized by extending the
|
||||
// InstanceType. See
|
||||
// https://docs.google.com/document/d/15f-1c_Ysw3lvjy_Gx0SmmD9qeO8UuXuAbWIpWCnTDO8/
|
||||
const flat = Flatten(s);
|
||||
try {
|
||||
const illFormed = HasUnpairedSurrogate(flat) otherwise Indirect;
|
||||
return illFormed ? False : True;
|
||||
} label Indirect deferred {
|
||||
return runtime::StringIsWellFormed(context, flat);
|
||||
}
|
||||
}
|
||||
}
|
59
src/builtins/string-towellformed.tq
Normal file
59
src/builtins/string-towellformed.tq
Normal file
@ -0,0 +1,59 @@
|
||||
// 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/builtins/builtins-string-gen.h'
|
||||
|
||||
namespace runtime {
|
||||
extern runtime StringToWellFormed(Context, String): String;
|
||||
}
|
||||
|
||||
namespace string {
|
||||
|
||||
extern macro StringBuiltinsAssembler::ReplaceUnpairedSurrogates(
|
||||
String, String): void labels Indirect;
|
||||
|
||||
transitioning javascript builtin
|
||||
StringPrototypeToWellFormed(
|
||||
js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
|
||||
const methodName: constexpr string = 'String.prototype.toWellFormed';
|
||||
|
||||
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||
// 2. Let S be ? ToString(O).
|
||||
const s = ToThisString(receiver, methodName);
|
||||
|
||||
// Fast path: one-byte strings cannot have unpaired surrogates and are
|
||||
// definitionally well-formed.
|
||||
if (s.StringInstanceType().is_one_byte) return s;
|
||||
|
||||
// 3. Let strLen be the length of S.
|
||||
const strLen = s.length_uint32;
|
||||
|
||||
// 4. Let k be 0.
|
||||
// 5. Let result be the empty String.
|
||||
const flat = Flatten(s);
|
||||
let result = flat;
|
||||
|
||||
// 6. Repeat, while k < strLen,
|
||||
// a. Let cp be CodePointAt(S, k).
|
||||
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
||||
// i. Set result to the string-concatenation of result and
|
||||
// 0xFFFD (REPLACEMENT CHARACTER).
|
||||
// c. Else,
|
||||
// i. Set result to the string-concatenation of result and
|
||||
// UTF16EncodeCodePoint(cp.[[CodePoint]]).
|
||||
// d. Set k to k + cp.[[CodeUnitCount]].
|
||||
try {
|
||||
const illFormed = HasUnpairedSurrogate(flat) otherwise Indirect;
|
||||
if (illFormed) {
|
||||
result = AllocateSeqTwoByteString(strLen);
|
||||
ReplaceUnpairedSurrogates(flat, result) otherwise Indirect;
|
||||
}
|
||||
|
||||
// 7. Return result.
|
||||
return result;
|
||||
} label Indirect deferred {
|
||||
return runtime::StringToWellFormed(context, flat);
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@
|
||||
#include "src/regexp/regexp-macro-assembler-arch.h"
|
||||
#include "src/regexp/regexp-stack.h"
|
||||
#include "src/strings/string-search.h"
|
||||
#include "src/strings/unicode-inl.h"
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
#include "src/wasm/wasm-external-refs.h"
|
||||
@ -1153,6 +1154,24 @@ static Address LexicographicCompareWrapper(Isolate* isolate, Address smi_x,
|
||||
FUNCTION_REFERENCE(smi_lexicographic_compare_function,
|
||||
LexicographicCompareWrapper)
|
||||
|
||||
uint32_t HasUnpairedSurrogate(const uint16_t* code_units, size_t length) {
|
||||
// Use uint32_t to avoid complexity around bool return types.
|
||||
static constexpr uint32_t kTrue = 1;
|
||||
static constexpr uint32_t kFalse = 0;
|
||||
return unibrow::Utf16::HasUnpairedSurrogate(code_units, length) ? kTrue
|
||||
: kFalse;
|
||||
}
|
||||
|
||||
FUNCTION_REFERENCE(has_unpaired_surrogate, HasUnpairedSurrogate)
|
||||
|
||||
void ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
|
||||
uint16_t* dest_code_units, size_t length) {
|
||||
return unibrow::Utf16::ReplaceUnpairedSurrogates(source_code_units,
|
||||
dest_code_units, length);
|
||||
}
|
||||
|
||||
FUNCTION_REFERENCE(replace_unpaired_surrogates, ReplaceUnpairedSurrogates)
|
||||
|
||||
FUNCTION_REFERENCE(mutable_big_int_absolute_add_and_canonicalize_function,
|
||||
MutableBigInt_AbsoluteAddAndCanonicalize)
|
||||
|
||||
|
@ -231,6 +231,8 @@ class StatsCounter;
|
||||
V(array_indexof_includes_smi_or_object, \
|
||||
"array_indexof_includes_smi_or_object") \
|
||||
V(array_indexof_includes_double, "array_indexof_includes_double") \
|
||||
V(has_unpaired_surrogate, "Utf16::HasUnpairedSurrogate") \
|
||||
V(replace_unpaired_surrogates, "Utf16::ReplaceUnpairedSurrogates") \
|
||||
V(try_string_to_index_or_lookup_existing, \
|
||||
"try_string_to_index_or_lookup_existing") \
|
||||
V(string_from_forward_table, "string_from_forward_table") \
|
||||
|
@ -235,7 +235,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
||||
V(harmony_rab_gsab, \
|
||||
"harmony ResizableArrayBuffer / GrowableSharedArrayBuffer") \
|
||||
V(harmony_rab_gsab_transfer, "harmony ArrayBuffer.transfer") \
|
||||
V(harmony_array_grouping, "harmony array grouping")
|
||||
V(harmony_array_grouping, "harmony array grouping") \
|
||||
V(harmony_string_is_well_formed, "harmony String#{is,to}WellFormed")
|
||||
|
||||
DEFINE_IMPLICATION(harmony_rab_gsab_transfer, harmony_rab_gsab)
|
||||
|
||||
|
@ -4892,6 +4892,18 @@ void Genesis::InitializeGlobal_harmony_rab_gsab() {
|
||||
Builtin::kSharedArrayBufferPrototypeGrow, 1, true);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_string_is_well_formed() {
|
||||
if (!v8_flags.harmony_string_is_well_formed) return;
|
||||
Handle<JSFunction> string_function(native_context()->string_function(),
|
||||
isolate());
|
||||
Handle<JSObject> string_prototype(
|
||||
JSObject::cast(string_function->initial_map().prototype()), isolate());
|
||||
SimpleInstallFunction(isolate(), string_prototype, "isWellFormed",
|
||||
Builtin::kStringPrototypeIsWellFormed, 0, false);
|
||||
SimpleInstallFunction(isolate(), string_prototype, "toWellFormed",
|
||||
Builtin::kStringPrototypeToWellFormed, 0, false);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_temporal() {
|
||||
if (!v8_flags.harmony_temporal) return;
|
||||
// -- T e m p o r a l
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/sandbox/external-pointer-inl.h"
|
||||
#include "src/sandbox/external-pointer.h"
|
||||
#include "src/strings/string-hasher-inl.h"
|
||||
#include "src/strings/unicode-inl.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
@ -956,6 +957,21 @@ ConsString String::VisitFlat(
|
||||
}
|
||||
}
|
||||
|
||||
bool String::IsWellFormedUnicode(Isolate* isolate, Handle<String> string) {
|
||||
// One-byte strings are definitionally well formed and cannot have unpaired
|
||||
// surrogates.
|
||||
if (string->IsOneByteRepresentation()) return true;
|
||||
|
||||
// TODO(v8:13557): The two-byte case can be optimized by extending the
|
||||
// InstanceType. See
|
||||
// https://docs.google.com/document/d/15f-1c_Ysw3lvjy_Gx0SmmD9qeO8UuXuAbWIpWCnTDO8/
|
||||
string = Flatten(isolate, string);
|
||||
DCHECK(string->IsTwoByteRepresentation());
|
||||
DisallowGarbageCollection no_gc;
|
||||
const uint16_t* data = string->template GetChars<uint16_t>(isolate, no_gc);
|
||||
return !unibrow::Utf16::HasUnpairedSurrogate(data, string->length());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline base::Vector<const uint8_t> String::GetCharVector(
|
||||
const DisallowGarbageCollection& no_gc) {
|
||||
|
@ -526,6 +526,10 @@ class String : public TorqueGeneratedString<String, Name> {
|
||||
PtrComprCageBase cage_base,
|
||||
const SharedStringAccessGuardIfNeeded&);
|
||||
|
||||
// Returns true if this string has no unpaired surrogates and false otherwise.
|
||||
static inline bool IsWellFormedUnicode(Isolate* isolate,
|
||||
Handle<String> string);
|
||||
|
||||
static inline bool IsAscii(const char* chars, int length) {
|
||||
return IsAscii(reinterpret_cast<const uint8_t*>(chars), length);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/objects/slots.h"
|
||||
#include "src/objects/smi.h"
|
||||
#include "src/strings/string-builder-inl.h"
|
||||
#include "src/strings/unicode-inl.h"
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
// TODO(chromium:1236668): Drop this when the "SaveAndClearThreadInWasmFlag"
|
||||
@ -471,5 +472,30 @@ RUNTIME_FUNCTION(Runtime_StringEscapeQuotes) {
|
||||
return *builder.ToString().ToHandleChecked();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_StringIsWellFormed) {
|
||||
HandleScope handle_scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
Handle<String> string = args.at<String>(0);
|
||||
return isolate->heap()->ToBoolean(
|
||||
String::IsWellFormedUnicode(isolate, string));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_StringToWellFormed) {
|
||||
HandleScope handle_scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
Handle<String> source = args.at<String>(0);
|
||||
if (String::IsWellFormedUnicode(isolate, source)) return *source;
|
||||
source = String::Flatten(isolate, source);
|
||||
const int length = source->length();
|
||||
Handle<SeqTwoByteString> dest =
|
||||
isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
|
||||
DisallowGarbageCollection no_gc;
|
||||
const uint16_t* source_data =
|
||||
source->template GetChars<uint16_t>(isolate, no_gc);
|
||||
uint16_t* dest_data = dest->GetChars(no_gc);
|
||||
unibrow::Utf16::ReplaceUnpairedSurrogates(source_data, dest_data, length);
|
||||
return *dest;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -462,13 +462,15 @@ namespace internal {
|
||||
F(StringEscapeQuotes, 1, 1) \
|
||||
F(StringGreaterThan, 2, 1) \
|
||||
F(StringGreaterThanOrEqual, 2, 1) \
|
||||
F(StringIsWellFormed, 1, 1) \
|
||||
F(StringLastIndexOf, 2, 1) \
|
||||
F(StringLessThan, 2, 1) \
|
||||
F(StringLessThanOrEqual, 2, 1) \
|
||||
F(StringMaxLength, 0, 1) \
|
||||
F(StringReplaceOneCharWithString, 3, 1) \
|
||||
F(StringSubstring, 3, 1) \
|
||||
F(StringToArray, 2, 1)
|
||||
F(StringToArray, 2, 1) \
|
||||
F(StringToWellFormed, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_SYMBOL(F, I) \
|
||||
F(CreatePrivateNameSymbol, 1, 1) \
|
||||
|
@ -239,6 +239,37 @@ bool Utf8::ValidateEncoding(const byte* bytes, size_t length) {
|
||||
return state == State::kAccept;
|
||||
}
|
||||
|
||||
// static
|
||||
void Utf16::ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
|
||||
uint16_t* dest_code_units,
|
||||
size_t length) {
|
||||
// U+FFFD (REPLACEMENT CHARACTER)
|
||||
constexpr uint16_t kReplacement = 0xFFFD;
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
const uint16_t source_code_unit = source_code_units[i];
|
||||
const size_t copy_index = i;
|
||||
uint16_t dest_code_unit = source_code_unit;
|
||||
if (IsLeadSurrogate(source_code_unit)) {
|
||||
// The current code unit is a leading surrogate. If it's not followed by a
|
||||
// trailing surrogate, replace it with the replacement character.
|
||||
if (i == length - 1 || !IsTrailSurrogate(source_code_units[i + 1])) {
|
||||
dest_code_unit = kReplacement;
|
||||
} else {
|
||||
// Copy the paired trailing surrogate. The paired leading surrogate will
|
||||
// be copied below.
|
||||
++i;
|
||||
dest_code_units[i] = source_code_units[i];
|
||||
}
|
||||
} else if (IsTrailSurrogate(source_code_unit)) {
|
||||
// All paired trailing surrogates are skipped above, so this branch is
|
||||
// only for those that are unpaired.
|
||||
dest_code_unit = kReplacement;
|
||||
}
|
||||
dest_code_units[copy_index] = dest_code_unit;
|
||||
}
|
||||
}
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
bool Wtf8::ValidateEncoding(const byte* bytes, size_t length) {
|
||||
using State = GeneralizedUtf8DfaDecoder::State;
|
||||
|
@ -121,7 +121,7 @@ class Utf16 {
|
||||
// 4 bytes and the 3 bytes that were used to encode the lead surrogate
|
||||
// can be reclaimed.
|
||||
static const int kMaxExtraUtf8BytesForOneUtf16CodeUnit = 3;
|
||||
// One UTF-16 surrogate is endoded (illegally) as 3 UTF-8 bytes.
|
||||
// One UTF-16 surrogate is encoded (illegally) as 3 UTF-8 bytes.
|
||||
// The illegality stems from the surrogate not being part of a pair.
|
||||
static const int kUtf8BytesToCodeASurrogate = 3;
|
||||
static inline uint16_t LeadSurrogate(uint32_t char_code) {
|
||||
@ -132,6 +132,10 @@ class Utf16 {
|
||||
}
|
||||
static inline bool HasUnpairedSurrogate(const uint16_t* code_units,
|
||||
size_t length);
|
||||
|
||||
static void ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
|
||||
uint16_t* dest_code_units,
|
||||
size_t length);
|
||||
};
|
||||
|
||||
class Latin1 {
|
||||
|
@ -0,0 +1,42 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --expose-externalize-string --harmony-string-is-well-formed
|
||||
|
||||
(function TestIsWellFormed() {
|
||||
const short2ByteWellFormed = '\u1234';
|
||||
const short2ByteIllFormed = '\uD83D';
|
||||
|
||||
assertTrue(short2ByteWellFormed.isWellFormed());
|
||||
assertFalse(short2ByteIllFormed.isWellFormed());
|
||||
|
||||
try {
|
||||
// Turn the strings into uncached external strings to hit the slow runtime
|
||||
// path.
|
||||
externalizeString(short2ByteWellFormed, true);
|
||||
externalizeString(short2ByteIllFormed, true);
|
||||
} catch (e) {}
|
||||
|
||||
assertTrue(short2ByteWellFormed.isWellFormed());
|
||||
assertFalse(short2ByteIllFormed.isWellFormed());
|
||||
})();
|
||||
|
||||
(function TestToWellFormed() {
|
||||
const short2ByteWellFormed = '\u1234';
|
||||
const short2ByteIllFormed = '\uD83D';
|
||||
|
||||
assertTrue(short2ByteWellFormed.isWellFormed());
|
||||
assertFalse(short2ByteIllFormed.isWellFormed());
|
||||
|
||||
try {
|
||||
// Turn the strings into uncached external strings to hit the slow runtime
|
||||
// path.
|
||||
externalizeString(short2ByteWellFormed, true);
|
||||
externalizeString(short2ByteIllFormed, true);
|
||||
} catch (e) {}
|
||||
|
||||
assertEquals('\u1234', short2ByteWellFormed.toWellFormed());
|
||||
// U+FFFD (REPLACEMENT CHARACTER)
|
||||
assertEquals('\uFFFD', short2ByteIllFormed.toWellFormed());
|
||||
})();
|
@ -994,20 +994,6 @@
|
||||
'language/statements/class/decorator/syntax/valid/class-element-decorator-member-expr-identifier-reference': [FAIL],
|
||||
'language/statements/class/decorator/syntax/valid/class-element-decorator-parenthesized-expr-identifier-reference': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=13557
|
||||
'built-ins/String/prototype/isWellFormed/length': [FAIL],
|
||||
'built-ins/String/prototype/isWellFormed/name': [FAIL],
|
||||
'built-ins/String/prototype/isWellFormed/prop-desc': [FAIL],
|
||||
'built-ins/String/prototype/isWellFormed/return-abrupt-from-this': [FAIL],
|
||||
'built-ins/String/prototype/isWellFormed/returns-boolean': [FAIL],
|
||||
'built-ins/String/prototype/isWellFormed/to-string': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/length': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/name': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/prop-desc': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/return-abrupt-from-this': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/returns-well-formed-string': [FAIL],
|
||||
'built-ins/String/prototype/toWellFormed/to-string': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=11660
|
||||
# https://github.com/tc39/proposal-intl-duration-format/issues/114
|
||||
'intl402/DurationFormat/prototype/format/style-options-en': [FAIL],
|
||||
|
@ -56,6 +56,8 @@ FEATURE_FLAGS = {
|
||||
'array-grouping': '--harmony-array-grouping',
|
||||
'change-array-by-copy': '--harmony-change-array-by-copy',
|
||||
'symbols-as-weakmap-keys': '--harmony-symbol-as-weakmap-key',
|
||||
'String.prototype.isWellFormed': '--harmony-string-is-well-formed',
|
||||
'String.prototype.toWellFormed': '--harmony-string-is-well-formed',
|
||||
}
|
||||
|
||||
SKIPPED_FEATURES = set([])
|
||||
|
@ -577,30 +577,30 @@ KNOWN_OBJECTS = {
|
||||
("old_space", 0x04581): "StringSplitCache",
|
||||
("old_space", 0x04989): "RegExpMultipleCache",
|
||||
("old_space", 0x04d91): "BuiltinsConstantsTable",
|
||||
("old_space", 0x05359): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x0537d): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x053a1): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x053c5): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x053e9): "AsyncGeneratorYieldWithAwaitResolveSharedFun",
|
||||
("old_space", 0x0540d): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05431): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x05455): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x05479): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x0549d): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x054c1): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x054e5): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x05509): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x0552d): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05551): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x05575): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x05599): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x055bd): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x055e1): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x05605): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x05629): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x0564d): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x05671): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x05695): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
("old_space", 0x05361): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x05385): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x053a9): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x053cd): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x053f1): "AsyncGeneratorYieldWithAwaitResolveSharedFun",
|
||||
("old_space", 0x05415): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05439): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x0545d): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x05481): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x054a5): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x054c9): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x054ed): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x05511): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x05535): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05559): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x0557d): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x055a1): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x055c5): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x055e9): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x0560d): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x05631): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x05655): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x05679): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x0569d): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user