Commit fd42f40b authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[json] Specialize json parser on chartype rather than bool seq_one_byte

Change-Id: I34dc911d205ab507f668bfd422eb1838f660a6bf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1571624
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60964}
parent 30028461
...@@ -3033,9 +3033,9 @@ MaybeLocal<Value> JSON::Parse(Local<Context> context, ...@@ -3033,9 +3033,9 @@ MaybeLocal<Value> JSON::Parse(Local<Context> context,
i::Handle<i::String> string = Utils::OpenHandle(*json_string); i::Handle<i::String> string = Utils::OpenHandle(*json_string);
i::Handle<i::String> source = i::String::Flatten(isolate, string); i::Handle<i::String> source = i::String::Flatten(isolate, string);
i::Handle<i::Object> undefined = isolate->factory()->undefined_value(); i::Handle<i::Object> undefined = isolate->factory()->undefined_value();
auto maybe = source->IsSeqOneByteString() auto maybe = source->IsOneByteRepresentation()
? i::JsonParser<true>::Parse(isolate, source, undefined) ? i::JsonParser<uint8_t>::Parse(isolate, source, undefined)
: i::JsonParser<false>::Parse(isolate, source, undefined); : i::JsonParser<uint16_t>::Parse(isolate, source, undefined);
Local<Value> result; Local<Value> result;
has_pending_exception = !ToLocal<Value>(maybe, &result); has_pending_exception = !ToLocal<Value>(maybe, &result);
RETURN_ON_FAILED_EXECUTION(Value); RETURN_ON_FAILED_EXECUTION(Value);
......
...@@ -22,9 +22,9 @@ BUILTIN(JsonParse) { ...@@ -22,9 +22,9 @@ BUILTIN(JsonParse) {
Object::ToString(isolate, source)); Object::ToString(isolate, source));
string = String::Flatten(isolate, string); string = String::Flatten(isolate, string);
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(
isolate, string->IsSeqOneByteString() isolate, string->IsOneByteRepresentation()
? JsonParser<true>::Parse(isolate, string, reviver) ? JsonParser<uint8_t>::Parse(isolate, string, reviver)
: JsonParser<false>::Parse(isolate, string, reviver)); : JsonParser<uint16_t>::Parse(isolate, string, reviver));
} }
// ES6 section 24.3.2 JSON.stringify. // ES6 section 24.3.2 JSON.stringify.
......
...@@ -134,28 +134,57 @@ bool JsonParseInternalizer::RecurseAndApply(Handle<JSReceiver> holder, ...@@ -134,28 +134,57 @@ bool JsonParseInternalizer::RecurseAndApply(Handle<JSReceiver> holder,
return true; return true;
} }
template <bool seq_one_byte> template <typename Char>
JsonParser<seq_one_byte>::JsonParser(Isolate* isolate, Handle<String> source) JsonParser<Char>::JsonParser(Isolate* isolate, Handle<String> source)
: source_(source), : isolate_(isolate),
source_length_(source->length()),
isolate_(isolate),
zone_(isolate_->allocator(), ZONE_NAME), zone_(isolate_->allocator(), ZONE_NAME),
object_constructor_(isolate_->native_context()->object_function(), object_constructor_(isolate_->object_function()),
isolate_), offset_(0),
length_(source->length()),
position_(-1), position_(-1),
properties_(&zone_) { properties_(&zone_) {
source_ = String::Flatten(isolate, source_); if (source->IsSlicedString()) {
allocation_ = (source_length_ >= kPretenureTreshold) ? AllocationType::kOld SlicedString string = SlicedString::cast(*source);
: AllocationType::kYoung; offset_ = string.offset();
length_ += offset_;
position_ += offset_;
String parent = string.parent();
if (parent.IsThinString()) parent = ThinString::cast(parent).actual();
source_ = handle(parent, isolate);
} else {
source_ = String::Flatten(isolate, source);
}
// Optimized fast case where we only have Latin1 characters. if (StringShape(*source_).IsExternal()) {
if (seq_one_byte) { chars_ =
seq_source_ = Handle<SeqOneByteString>::cast(source_); static_cast<const Char*>(SeqExternalString::cast(*source_)->GetChars());
} else {
DisallowHeapAllocation no_gc;
isolate->heap()->AddGCEpilogueCallback(UpdatePointersCallback,
v8::kGCTypeAll, this);
chars_ = SeqString::cast(*source_)->GetChars(no_gc);
} }
allocation_ = (source->length() >= kPretenureTreshold)
? AllocationType::kOld
: AllocationType::kYoung;
} }
template <bool seq_one_byte> template <typename Char>
MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() { JsonParser<Char>::~JsonParser() {
if (StringShape(*source_).IsExternal()) {
// Check that the string shape hasn't changed. Otherwise our GC hooks are
// broken.
SeqExternalString::cast(*source_);
} else {
// Check that the string shape hasn't changed. Otherwise our GC hooks are
// broken.
SeqString::cast(*source_);
isolate()->heap()->RemoveGCEpilogueCallback(UpdatePointersCallback, this);
}
}
template <typename Char>
MaybeHandle<Object> JsonParser<Char>::ParseJson() {
// Advance to the first character (possibly EOS) // Advance to the first character (possibly EOS)
AdvanceSkipWhitespace(); AdvanceSkipWhitespace();
Handle<Object> result = ParseJsonValue(); Handle<Object> result = ParseJsonValue();
...@@ -213,40 +242,38 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() { ...@@ -213,40 +242,38 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
MaybeHandle<Object> InternalizeJsonProperty(Handle<JSObject> holder, MaybeHandle<Object> InternalizeJsonProperty(Handle<JSObject> holder,
Handle<String> key); Handle<String> key);
template <bool seq_one_byte> template <typename Char>
void JsonParser<seq_one_byte>::Advance() { void JsonParser<Char>::Advance() {
position_++; position_++;
if (position_ >= source_length_) { if (position_ >= length_) {
c0_ = kEndOfString; c0_ = kEndOfString;
} else if (seq_one_byte) {
c0_ = seq_source_->SeqOneByteStringGet(position_);
} else { } else {
c0_ = source_->Get(position_); c0_ = chars_[position_];
} }
} }
template <bool seq_one_byte> template <typename Char>
void JsonParser<seq_one_byte>::AdvanceSkipWhitespace() { void JsonParser<Char>::AdvanceSkipWhitespace() {
do { do {
Advance(); Advance();
} while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r'); } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
} }
template <bool seq_one_byte> template <typename Char>
void JsonParser<seq_one_byte>::SkipWhitespace() { void JsonParser<Char>::SkipWhitespace() {
while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') { while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
Advance(); Advance();
} }
} }
template <bool seq_one_byte> template <typename Char>
uc32 JsonParser<seq_one_byte>::AdvanceGetChar() { uc32 JsonParser<Char>::AdvanceGetChar() {
Advance(); Advance();
return c0_; return c0_;
} }
template <bool seq_one_byte> template <typename Char>
bool JsonParser<seq_one_byte>::MatchSkipWhiteSpace(uc32 c) { bool JsonParser<Char>::MatchSkipWhiteSpace(uc32 c) {
if (c0_ == c) { if (c0_ == c) {
AdvanceSkipWhitespace(); AdvanceSkipWhitespace();
return true; return true;
...@@ -254,18 +281,32 @@ bool JsonParser<seq_one_byte>::MatchSkipWhiteSpace(uc32 c) { ...@@ -254,18 +281,32 @@ bool JsonParser<seq_one_byte>::MatchSkipWhiteSpace(uc32 c) {
return false; return false;
} }
template <bool seq_one_byte> template <typename Char>
bool JsonParser<seq_one_byte>::ParseJsonString(Handle<String> expected) { bool JsonParser<Char>::ParseJsonString(Handle<String> expected) {
int length = expected->length(); int length = expected->length();
if (source_->length() - position_ - 1 > length) { if (source_->length() - position_ - 1 > length) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
String::FlatContent content = expected->GetFlatContent(no_gc); String::FlatContent content = expected->GetFlatContent(no_gc);
DCHECK_EQ('"', c0_);
if (content.IsOneByte()) { if (content.IsOneByte()) {
DCHECK_EQ('"', c0_); const Char* input_chars = chars_ + position_ + 1;
const uint8_t* input_chars = seq_source_->GetChars(no_gc) + position_ + 1;
const uint8_t* expected_chars = content.ToOneByteVector().start(); const uint8_t* expected_chars = content.ToOneByteVector().start();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
uint8_t c0 = input_chars[i]; Char c0 = input_chars[i];
if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') {
return false;
}
}
if (input_chars[length] == '"') {
position_ = position_ + length + 1;
AdvanceSkipWhitespace();
return true;
}
} else {
const Char* input_chars = chars_ + position_ + 1;
const uint16_t* expected_chars = content.ToUC16Vector().start();
for (int i = 0; i < length; i++) {
Char c0 = input_chars[i];
if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') { if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') {
return false; return false;
} }
...@@ -281,8 +322,8 @@ bool JsonParser<seq_one_byte>::ParseJsonString(Handle<String> expected) { ...@@ -281,8 +322,8 @@ bool JsonParser<seq_one_byte>::ParseJsonString(Handle<String> expected) {
} }
// Parse any JSON value. // Parse any JSON value.
template <bool seq_one_byte> template <typename Char>
Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() { Handle<Object> JsonParser<Char>::ParseJsonValue() {
StackLimitCheck stack_check(isolate_); StackLimitCheck stack_check(isolate_);
if (stack_check.HasOverflowed()) { if (stack_check.HasOverflowed()) {
isolate_->StackOverflow(); isolate_->StackOverflow();
...@@ -325,8 +366,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() { ...@@ -325,8 +366,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
return ReportUnexpectedCharacter(); return ReportUnexpectedCharacter();
} }
template <bool seq_one_byte> template <typename Char>
ParseElementResult JsonParser<seq_one_byte>::ParseElement( ParseElementResult JsonParser<Char>::ParseElement(
Handle<JSObject> json_object) { Handle<JSObject> json_object) {
uint32_t index = 0; uint32_t index = 0;
// Maybe an array index, try to parse it. // Maybe an array index, try to parse it.
...@@ -362,8 +403,8 @@ ParseElementResult JsonParser<seq_one_byte>::ParseElement( ...@@ -362,8 +403,8 @@ ParseElementResult JsonParser<seq_one_byte>::ParseElement(
} }
// Parse a JSON object. Position must be right at '{'. // Parse a JSON object. Position must be right at '{'.
template <bool seq_one_byte> template <typename Char>
Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { Handle<Object> JsonParser<Char>::ParseJsonObject() {
HandleScope scope(isolate()); HandleScope scope(isolate());
Handle<JSObject> json_object = Handle<JSObject> json_object =
factory()->NewJSObject(object_constructor(), allocation_); factory()->NewJSObject(object_constructor(), allocation_);
...@@ -404,7 +445,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { ...@@ -404,7 +445,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
// to parse it first. // to parse it first.
bool follow_expected = false; bool follow_expected = false;
Handle<Map> target; Handle<Map> target;
if (seq_one_byte) { if (kIsOneByte) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
TransitionsAccessor transitions(isolate(), *map, &no_gc); TransitionsAccessor transitions(isolate(), *map, &no_gc);
key = transitions.ExpectedTransitionKey(); key = transitions.ExpectedTransitionKey();
...@@ -515,8 +556,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { ...@@ -515,8 +556,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
return scope.CloseAndEscape(json_object); return scope.CloseAndEscape(json_object);
} }
template <bool seq_one_byte> template <typename Char>
void JsonParser<seq_one_byte>::CommitStateToJsonObject( void JsonParser<Char>::CommitStateToJsonObject(
Handle<JSObject> json_object, Handle<Map> map, Handle<JSObject> json_object, Handle<Map> map,
Vector<const Handle<Object>> properties) { Vector<const Handle<Object>> properties) {
JSObject::AllocateStorageForMap(json_object, map); JSObject::AllocateStorageForMap(json_object, map);
...@@ -572,8 +613,8 @@ class ElementKindLattice { ...@@ -572,8 +613,8 @@ class ElementKindLattice {
}; };
// Parse a JSON array. Position must be right at '['. // Parse a JSON array. Position must be right at '['.
template <bool seq_one_byte> template <typename Char>
Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() { Handle<Object> JsonParser<Char>::ParseJsonArray() {
HandleScope scope(isolate()); HandleScope scope(isolate());
ZoneVector<Handle<Object>> elements(zone()); ZoneVector<Handle<Object>> elements(zone());
DCHECK_EQ(c0_, '['); DCHECK_EQ(c0_, '[');
...@@ -625,8 +666,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() { ...@@ -625,8 +666,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() {
return scope.CloseAndEscape(json_array); return scope.CloseAndEscape(json_array);
} }
template <bool seq_one_byte> template <typename Char>
Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() { Handle<Object> JsonParser<Char>::ParseJsonNumber() {
bool negative = false; bool negative = false;
int beg_pos = position_; int beg_pos = position_;
if (c0_ == '-') { if (c0_ == '-') {
...@@ -672,10 +713,10 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() { ...@@ -672,10 +713,10 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
} }
int length = position_ - beg_pos; int length = position_ - beg_pos;
double number; double number;
if (seq_one_byte) { if (kIsOneByte) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Vector<const uint8_t> chars(seq_source_->GetChars(no_gc) + beg_pos, length); Vector<const Char> chars(chars_ + beg_pos, length);
number = StringToDouble(chars, number = StringToDouble(Vector<const uint8_t>::cast(chars),
NO_FLAGS, // Hex, octal or trailing junk. NO_FLAGS, // Hex, octal or trailing junk.
std::numeric_limits<double>::quiet_NaN()); std::numeric_limits<double>::quiet_NaN());
} else { } else {
...@@ -724,12 +765,12 @@ inline Handle<SeqOneByteString> NewRawString(Factory* factory, int length, ...@@ -724,12 +765,12 @@ inline Handle<SeqOneByteString> NewRawString(Factory* factory, int length,
// Scans the rest of a JSON string starting from position_ and writes // Scans the rest of a JSON string starting from position_ and writes
// prefix[start..end] along with the scanned characters into a // prefix[start..end] along with the scanned characters into a
// sequential string of type StringType. // sequential string of type StringType.
template <bool seq_one_byte> template <typename Char>
template <typename StringType, typename SinkChar> template <typename StringType, typename SinkChar>
Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString( Handle<String> JsonParser<Char>::SlowScanJsonString(Handle<String> prefix,
Handle<String> prefix, int start, int end) { int start, int end) {
int count = end - start; int count = end - start;
int max_length = count + source_length_ - position_; int max_length = count + length_ - position_;
int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
Handle<StringType> seq_string = Handle<StringType> seq_string =
NewRawString<StringType>(factory(), length, allocation_); NewRawString<StringType>(factory(), length, allocation_);
...@@ -753,7 +794,7 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString( ...@@ -753,7 +794,7 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
// Latin1 characters, there's no need to test whether we can store the // Latin1 characters, there's no need to test whether we can store the
// character. Otherwise check whether the UC16 source character can fit // character. Otherwise check whether the UC16 source character can fit
// in the Latin1 sink. // in the Latin1 sink.
if (sizeof(SinkChar) == kUC16Size || seq_one_byte || if (sizeof(SinkChar) == kUC16Size || kIsOneByte ||
c0_ <= String::kMaxOneByteCharCode) { c0_ <= String::kMaxOneByteCharCode) {
SeqStringSet(seq_string, count++, c0_); SeqStringSet(seq_string, count++, c0_);
Advance(); Advance();
...@@ -822,8 +863,8 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString( ...@@ -822,8 +863,8 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
return SeqString::Truncate(seq_string, count); return SeqString::Truncate(seq_string, count);
} }
template <bool seq_one_byte> template <typename Char>
Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { Handle<String> JsonParser<Char>::ScanJsonString() {
DCHECK_EQ('"', c0_); DCHECK_EQ('"', c0_);
Advance(); Advance();
if (c0_ == '"') { if (c0_ == '"') {
...@@ -831,7 +872,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -831,7 +872,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
return factory()->empty_string(); return factory()->empty_string();
} }
if (seq_one_byte) { if (kIsOneByte) {
// Fast path for existing internalized strings. If the the string being // Fast path for existing internalized strings. If the the string being
// parsed is not a known internalized string, contains backslashes or // parsed is not a known internalized string, contains backslashes or
// unexpectedly reaches the end of string, return with an empty handle. // unexpectedly reaches the end of string, return with an empty handle.
...@@ -872,12 +913,12 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -872,12 +913,12 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
running_hash = StringHasher::AddCharacterCore(running_hash, running_hash = StringHasher::AddCharacterCore(running_hash,
static_cast<uint16_t>(c0)); static_cast<uint16_t>(c0));
position++; position++;
if (position >= source_length_) { if (position >= length_) {
c0_ = kEndOfString; c0_ = kEndOfString;
position_ = position; position_ = position;
return Handle<String>::null(); return Handle<String>::null();
} }
c0 = seq_source_->SeqOneByteStringGet(position); c0 = chars_[position];
} while (c0 != '"'); } while (c0 != '"');
int length = position - position_; int length = position - position_;
uint32_t hash; uint32_t hash;
...@@ -898,15 +939,14 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -898,15 +939,14 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
Object element = string_table->KeyAt(entry); Object element = string_table->KeyAt(entry);
if (element->IsUndefined(isolate())) { if (element->IsUndefined(isolate())) {
// Lookup failure. // Lookup failure.
result = result = Internalize(position_, length);
factory()->InternalizeOneByteString(seq_source_, position_, length);
break; break;
} }
if (!element->IsTheHole(isolate())) { if (!element->IsTheHole(isolate())) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Vector<const uint8_t> string_vector( Vector<const Char> string_vector(chars_ + position_, length);
seq_source_->GetChars(no_gc) + position_, length); if (String::cast(element)->IsOneByteEqualTo(
if (String::cast(element)->IsOneByteEqualTo(string_vector)) { Vector<const uint8_t>::cast(string_vector))) {
result = Handle<String>(String::cast(element), isolate()); result = Handle<String>(String::cast(element), isolate());
DCHECK_EQ(result->Hash(), DCHECK_EQ(result->Hash(),
(hash << String::kHashShift) >> String::kHashShift); (hash << String::kHashShift) >> String::kHashShift);
...@@ -927,7 +967,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -927,7 +967,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
// Check for control character (0x00-0x1F) or unterminated string (<0). // Check for control character (0x00-0x1F) or unterminated string (<0).
if (c0_ < 0x20) return Handle<String>::null(); if (c0_ < 0x20) return Handle<String>::null();
if (c0_ != '\\') { if (c0_ != '\\') {
if (seq_one_byte || c0_ <= String::kMaxOneByteCharCode) { if (kIsOneByte || c0_ <= String::kMaxOneByteCharCode) {
Advance(); Advance();
} else { } else {
return SlowScanJsonString<SeqTwoByteString, uc16>(source_, beg_pos, return SlowScanJsonString<SeqTwoByteString, uc16>(source_, beg_pos,
...@@ -951,9 +991,24 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -951,9 +991,24 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
return result; return result;
} }
template <>
Handle<String> JsonParser<uint8_t>::Internalize(int start, int length) {
if (StringShape(*source_).IsExternal()) {
return factory()->InternalizeOneByteString(
Vector<const uint8_t>(chars_ + start, length));
}
Handle<SeqString> seq = Handle<SeqString>::cast(source_);
return factory()->InternalizeOneByteString(seq, start, length);
}
template <>
Handle<String> JsonParser<uint16_t>::Internalize(int start, int length) {
UNREACHABLE();
}
// Explicit instantiation. // Explicit instantiation.
template class JsonParser<true>; template class JsonParser<uint8_t>;
template class JsonParser<false>; template class JsonParser<uint16_t>;
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -35,9 +35,12 @@ class JsonParseInternalizer { ...@@ -35,9 +35,12 @@ class JsonParseInternalizer {
}; };
// A simple json parser. // A simple json parser.
template <bool seq_one_byte> template <typename Char>
class JsonParser { class JsonParser final {
public: public:
using SeqString = typename CharTraits<Char>::String;
using SeqExternalString = typename CharTraits<Char>::ExternalString;
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Parse( V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Parse(
Isolate* isolate, Handle<String> source, Handle<Object> reviver) { Isolate* isolate, Handle<String> source, Handle<Object> reviver) {
Handle<Object> result; Handle<Object> result;
...@@ -52,7 +55,10 @@ class JsonParser { ...@@ -52,7 +55,10 @@ class JsonParser {
static const int kEndOfString = -1; static const int kEndOfString = -1;
private: private:
Handle<String> Internalize(int start, int length);
JsonParser(Isolate* isolate, Handle<String> source); JsonParser(Isolate* isolate, Handle<String> source);
~JsonParser();
// Parse a string containing a single JSON value. // Parse a string containing a single JSON value.
MaybeHandle<Object> ParseJson(); MaybeHandle<Object> ParseJson();
...@@ -136,20 +142,44 @@ class JsonParser { ...@@ -136,20 +142,44 @@ class JsonParser {
static const int kInitialSpecialStringLength = 32; static const int kInitialSpecialStringLength = 32;
static const int kPretenureTreshold = 100 * 1024; static const int kPretenureTreshold = 100 * 1024;
static void UpdatePointersCallback(v8::Isolate* v8_isolate, v8::GCType type,
v8::GCCallbackFlags flags, void* parser) {
reinterpret_cast<JsonParser<Char>*>(parser)->UpdatePointers();
}
void UpdatePointers() {
DisallowHeapAllocation no_gc;
const Char* chars = Handle<SeqString>::cast(source_)->GetChars(no_gc);
if (chars_ != chars) {
chars_ = chars;
}
}
private: private:
static const bool kIsOneByte = sizeof(Char) == 1;
Zone* zone() { return &zone_; } Zone* zone() { return &zone_; }
void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map, void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map,
Vector<const Handle<Object>> properties); Vector<const Handle<Object>> properties);
Handle<String> source_;
int source_length_;
Handle<SeqOneByteString> seq_source_;
AllocationType allocation_;
Isolate* isolate_; Isolate* isolate_;
Zone zone_; Zone zone_;
AllocationType allocation_;
Handle<JSFunction> object_constructor_; Handle<JSFunction> object_constructor_;
Handle<String> source_;
int offset_;
int length_;
// Cached pointer to the raw chars in source. In case source is on-heap, we
// register an UpdatePointers callback. For this reason, chars_ should never
// be locally cached across a possible allocation. The scope in which we
// cache chars has to be guarded by a DisallowHeapAllocation scope.
// TODO(verwaest): Move chars_ and functions that operate over chars to a
// separate helper class that makes it clear that all functions need to be
// guarded.
const Char* chars_;
uc32 c0_; uc32 c0_;
int position_; int position_;
...@@ -157,9 +187,15 @@ class JsonParser { ...@@ -157,9 +187,15 @@ class JsonParser {
ZoneVector<Handle<Object>> properties_; ZoneVector<Handle<Object>> properties_;
}; };
template <>
Handle<String> JsonParser<uint8_t>::Internalize(int start, int length);
template <>
Handle<String> JsonParser<uint16_t>::Internalize(int start, int length);
// Explicit instantiation declarations. // Explicit instantiation declarations.
extern template class JsonParser<true>; extern template class JsonParser<uint8_t>;
extern template class JsonParser<false>; extern template class JsonParser<uint16_t>;
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -6292,7 +6292,7 @@ JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags, ...@@ -6292,7 +6292,7 @@ JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags,
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
SeqOneByteString seq_flags = SeqOneByteString::cast(*flags); SeqOneByteString seq_flags = SeqOneByteString::cast(*flags);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
JSRegExp::Flag flag = CharToFlag(seq_flags.SeqOneByteStringGet(i)); JSRegExp::Flag flag = CharToFlag(seq_flags.Get(i));
// Duplicate or invalid flag. // Duplicate or invalid flag.
if (value & flag) return JSRegExp::Flags(0); if (value & flag) return JSRegExp::Flags(0);
value |= flag; value |= flag;
......
...@@ -323,24 +323,22 @@ uint16_t String::Get(int index) { ...@@ -323,24 +323,22 @@ uint16_t String::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
switch (StringShape(*this).full_representation_tag()) { switch (StringShape(*this).full_representation_tag()) {
case kSeqStringTag | kOneByteStringTag: case kSeqStringTag | kOneByteStringTag:
return SeqOneByteString::cast(*this)->SeqOneByteStringGet(index); return SeqOneByteString::cast(*this)->Get(index);
case kSeqStringTag | kTwoByteStringTag: case kSeqStringTag | kTwoByteStringTag:
return SeqTwoByteString::cast(*this)->SeqTwoByteStringGet(index); return SeqTwoByteString::cast(*this)->Get(index);
case kConsStringTag | kOneByteStringTag: case kConsStringTag | kOneByteStringTag:
case kConsStringTag | kTwoByteStringTag: case kConsStringTag | kTwoByteStringTag:
return ConsString::cast(*this)->ConsStringGet(index); return ConsString::cast(*this)->Get(index);
case kExternalStringTag | kOneByteStringTag: case kExternalStringTag | kOneByteStringTag:
return ExternalOneByteString::cast(*this)->ExternalOneByteStringGet( return ExternalOneByteString::cast(*this)->Get(index);
index);
case kExternalStringTag | kTwoByteStringTag: case kExternalStringTag | kTwoByteStringTag:
return ExternalTwoByteString::cast(*this)->ExternalTwoByteStringGet( return ExternalTwoByteString::cast(*this)->Get(index);
index);
case kSlicedStringTag | kOneByteStringTag: case kSlicedStringTag | kOneByteStringTag:
case kSlicedStringTag | kTwoByteStringTag: case kSlicedStringTag | kTwoByteStringTag:
return SlicedString::cast(*this)->SlicedStringGet(index); return SlicedString::cast(*this)->Get(index);
case kThinStringTag | kOneByteStringTag: case kThinStringTag | kOneByteStringTag:
case kThinStringTag | kTwoByteStringTag: case kThinStringTag | kTwoByteStringTag:
return ThinString::cast(*this)->ThinStringGet(index); return ThinString::cast(*this)->Get(index);
default: default:
break; break;
} }
...@@ -455,7 +453,7 @@ uint32_t String::ToValidIndex(Object number) { ...@@ -455,7 +453,7 @@ uint32_t String::ToValidIndex(Object number) {
return index; return index;
} }
uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { uint8_t SeqOneByteString::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
return READ_BYTE_FIELD(*this, kHeaderSize + index * kCharSize); return READ_BYTE_FIELD(*this, kHeaderSize + index * kCharSize);
} }
...@@ -484,7 +482,7 @@ uc16* SeqTwoByteString::GetChars(const DisallowHeapAllocation& no_gc) { ...@@ -484,7 +482,7 @@ uc16* SeqTwoByteString::GetChars(const DisallowHeapAllocation& no_gc) {
return reinterpret_cast<uc16*>(FIELD_ADDR(*this, kHeaderSize)); return reinterpret_cast<uc16*>(FIELD_ADDR(*this, kHeaderSize));
} }
uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) { uint16_t SeqTwoByteString::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
return READ_UINT16_FIELD(*this, kHeaderSize + index * kShortSize); return READ_UINT16_FIELD(*this, kHeaderSize + index * kShortSize);
} }
...@@ -618,7 +616,7 @@ const uint8_t* ExternalOneByteString::GetChars() { ...@@ -618,7 +616,7 @@ const uint8_t* ExternalOneByteString::GetChars() {
return reinterpret_cast<const uint8_t*>(resource()->data()); return reinterpret_cast<const uint8_t*>(resource()->data());
} }
uint16_t ExternalOneByteString::ExternalOneByteStringGet(int index) { uint8_t ExternalOneByteString::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
return GetChars()[index]; return GetChars()[index];
} }
...@@ -652,7 +650,7 @@ void ExternalTwoByteString::set_resource( ...@@ -652,7 +650,7 @@ void ExternalTwoByteString::set_resource(
const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); } const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); }
uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) { uint16_t ExternalTwoByteString::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
return GetChars()[index]; return GetChars()[index];
} }
......
...@@ -90,7 +90,7 @@ class StringTable : public HashTable<StringTable, StringTableShape> { ...@@ -90,7 +90,7 @@ class StringTable : public HashTable<StringTable, StringTableShape> {
static const int kMinShrinkCapacity = kMinCapacity; static const int kMinShrinkCapacity = kMinCapacity;
private: private:
template <bool seq_one_byte> template <typename char_type>
friend class JsonParser; friend class JsonParser;
OBJECT_CONSTRUCTORS(StringTable, HashTable<StringTable, StringTableShape>); OBJECT_CONSTRUCTORS(StringTable, HashTable<StringTable, StringTableShape>);
......
...@@ -1325,7 +1325,7 @@ void SeqTwoByteString::clear_padding() { ...@@ -1325,7 +1325,7 @@ void SeqTwoByteString::clear_padding() {
SizeFor(length()) - data_size); SizeFor(length()) - data_size);
} }
uint16_t ConsString::ConsStringGet(int index) { uint16_t ConsString::Get(int index) {
DCHECK(index >= 0 && index < this->length()); DCHECK(index >= 0 && index < this->length());
// Check for a flattened cons string // Check for a flattened cons string
...@@ -1354,9 +1354,9 @@ uint16_t ConsString::ConsStringGet(int index) { ...@@ -1354,9 +1354,9 @@ uint16_t ConsString::ConsStringGet(int index) {
UNREACHABLE(); UNREACHABLE();
} }
uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } uint16_t ThinString::Get(int index) { return actual()->Get(index); }
uint16_t SlicedString::SlicedStringGet(int index) { uint16_t SlicedString::Get(int index) {
return parent()->Get(offset() + index); return parent()->Get(offset() + index);
} }
......
...@@ -507,7 +507,7 @@ class SeqOneByteString : public SeqString { ...@@ -507,7 +507,7 @@ class SeqOneByteString : public SeqString {
static const bool kHasOneByteEncoding = true; static const bool kHasOneByteEncoding = true;
// Dispatched behavior. // Dispatched behavior.
inline uint16_t SeqOneByteStringGet(int index); inline uint8_t Get(int index);
inline void SeqOneByteStringSet(int index, uint16_t value); inline void SeqOneByteStringSet(int index, uint16_t value);
// Get the address of the characters in this string. // Get the address of the characters in this string.
...@@ -548,7 +548,7 @@ class SeqTwoByteString : public SeqString { ...@@ -548,7 +548,7 @@ class SeqTwoByteString : public SeqString {
static const bool kHasOneByteEncoding = false; static const bool kHasOneByteEncoding = false;
// Dispatched behavior. // Dispatched behavior.
inline uint16_t SeqTwoByteStringGet(int index); inline uint16_t Get(int index);
inline void SeqTwoByteStringSet(int index, uint16_t value); inline void SeqTwoByteStringSet(int index, uint16_t value);
// Get the address of the characters in this string. // Get the address of the characters in this string.
...@@ -610,7 +610,7 @@ class ConsString : public String { ...@@ -610,7 +610,7 @@ class ConsString : public String {
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Dispatched behavior. // Dispatched behavior.
V8_EXPORT_PRIVATE uint16_t ConsStringGet(int index); V8_EXPORT_PRIVATE uint16_t Get(int index);
DECL_CAST(ConsString) DECL_CAST(ConsString)
...@@ -642,7 +642,7 @@ class ThinString : public String { ...@@ -642,7 +642,7 @@ class ThinString : public String {
inline void set_actual(String s, inline void set_actual(String s,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
V8_EXPORT_PRIVATE uint16_t ThinStringGet(int index); V8_EXPORT_PRIVATE uint16_t Get(int index);
DECL_CAST(ThinString) DECL_CAST(ThinString)
DECL_VERIFIER(ThinString) DECL_VERIFIER(ThinString)
...@@ -676,7 +676,7 @@ class SlicedString : public String { ...@@ -676,7 +676,7 @@ class SlicedString : public String {
inline void set_offset(int offset); inline void set_offset(int offset);
// Dispatched behavior. // Dispatched behavior.
V8_EXPORT_PRIVATE uint16_t SlicedStringGet(int index); V8_EXPORT_PRIVATE uint16_t Get(int index);
DECL_CAST(SlicedString) DECL_CAST(SlicedString)
...@@ -758,7 +758,7 @@ class ExternalOneByteString : public ExternalString { ...@@ -758,7 +758,7 @@ class ExternalOneByteString : public ExternalString {
inline const uint8_t* GetChars(); inline const uint8_t* GetChars();
// Dispatched behavior. // Dispatched behavior.
inline uint16_t ExternalOneByteStringGet(int index); inline uint8_t Get(int index);
DECL_CAST(ExternalOneByteString) DECL_CAST(ExternalOneByteString)
...@@ -793,7 +793,7 @@ class ExternalTwoByteString : public ExternalString { ...@@ -793,7 +793,7 @@ class ExternalTwoByteString : public ExternalString {
inline const uint16_t* GetChars(); inline const uint16_t* GetChars();
// Dispatched behavior. // Dispatched behavior.
inline uint16_t ExternalTwoByteStringGet(int index); inline uint16_t Get(int index);
// For regexp code. // For regexp code.
inline const uint16_t* ExternalTwoByteStringGetData(unsigned start); inline const uint16_t* ExternalTwoByteStringGetData(unsigned start);
...@@ -895,6 +895,21 @@ class StringCharacterStream { ...@@ -895,6 +895,21 @@ class StringCharacterStream {
DISALLOW_COPY_AND_ASSIGN(StringCharacterStream); DISALLOW_COPY_AND_ASSIGN(StringCharacterStream);
}; };
template <typename Char>
struct CharTraits;
template <>
struct CharTraits<uint8_t> {
using String = SeqOneByteString;
using ExternalString = ExternalOneByteString;
};
template <>
struct CharTraits<uint16_t> {
using String = SeqTwoByteString;
using ExternalString = ExternalTwoByteString;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -49,21 +49,6 @@ namespace { ...@@ -49,21 +49,6 @@ namespace {
const unibrow::uchar kUtf8Bom = 0xFEFF; const unibrow::uchar kUtf8Bom = 0xFEFF;
} // namespace } // namespace
template <typename Char>
struct CharTraits;
template <>
struct CharTraits<uint8_t> {
using String = SeqOneByteString;
using ExternalString = ExternalOneByteString;
};
template <>
struct CharTraits<uint16_t> {
using String = SeqTwoByteString;
using ExternalString = ExternalTwoByteString;
};
template <typename Char> template <typename Char>
struct Range { struct Range {
const Char* start; const Char* start;
......
// Copyright 2019 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.
var s = 'abcabcabcabcabc["possibly a sliced string"]'.slice(15)
assertEquals(["possibly a sliced string"], JSON.parse(s));
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