Index: src/json-parser.h |
=================================================================== |
--- src/json-parser.h (revision 8446) |
+++ src/json-parser.h (working copy) |
@@ -55,7 +55,7 @@ |
inline void Advance() { |
position_++; |
- if (position_ > source_length_) { |
+ if (position_ >= source_length_) { |
c0_ = kEndOfString; |
} else if (seq_ascii) { |
c0_ = seq_source_->SeqAsciiStringGet(position_); |
@@ -107,9 +107,11 @@ |
} |
template <bool is_symbol> |
Handle<String> ScanJsonString(); |
- // Slow version for unicode support, uses the first ascii_count characters, |
- // as first part of a ConsString |
- Handle<String> SlowScanJsonString(int beg_pos); |
+ // Creates a new string and copies prefix[start..end] into the beginning |
+ // of it. Then scans the rest of the string, adding characters after the |
+ // prefix. Called by ScanJsonString when reaching a '\' or non-ASCII char. |
+ template <typename StringType, typename SinkChar> |
+ Handle<String> SlowScanJsonString(Handle<String> prefix, int start, int end); |
// A JSON number (production JSONNumber) is a subset of the valid JavaScript |
// decimal number literals. |
@@ -148,7 +150,7 @@ |
inline Isolate* isolate() { return isolate_; } |
- static const int kInitialSpecialStringSize = 1024; |
+ static const int kInitialSpecialStringLength = 1024; |
private: |
@@ -165,9 +167,9 @@ |
Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source) { |
isolate_ = source->map()->isolate(); |
source_ = Handle<String>(source->TryFlattenGetString()); |
- source_length_ = source_->length() - 1; |
+ source_length_ = source_->length(); |
- // Optimized fast case where we only have ascii characters. |
+ // Optimized fast case where we only have ASCII characters. |
if (seq_ascii) { |
seq_source_ = Handle<SeqAsciiString>::cast(source_); |
} |
@@ -410,62 +412,93 @@ |
return isolate()->factory()->NewNumber(number); |
} |
+ |
+template <typename StringType> |
+inline void SeqStringSet(Handle<StringType> seq_str, int i, uc32 c); |
+ |
+template <> |
+inline void SeqStringSet(Handle<SeqTwoByteString> seq_str, int i, uc32 c) { |
+ seq_str->SeqTwoByteStringSet(i, c); |
+} |
+ |
+template <> |
+inline void SeqStringSet(Handle<SeqAsciiString> seq_str, int i, uc32 c) { |
+ seq_str->SeqAsciiStringSet(i, c); |
+} |
+ |
+template <typename StringType> |
+inline Handle<StringType> NewRawString(Factory* factory, int length); |
+ |
+template <> |
+inline Handle<SeqTwoByteString> NewRawString(Factory* factory, int length) { |
+ return factory->NewRawTwoByteString(length, NOT_TENURED); |
+} |
+ |
+template <> |
+inline Handle<SeqAsciiString> NewRawString(Factory* factory, int length) { |
+ return factory->NewRawAsciiString(length, NOT_TENURED); |
+} |
+ |
+ |
+// Scans the rest of a JSON string starting from position_ and writes |
+// prefix[start..end] along with the scanned characters into a |
+// sequential string of type StringType. |
template <bool seq_ascii> |
-Handle<String> JsonParser<seq_ascii>::SlowScanJsonString(int beg_pos) { |
- // The currently scanned ascii characters. |
- Handle<String> ascii(isolate()->factory()->NewProperSubString(source_, |
- beg_pos, |
- position_)); |
- Handle<String> two_byte = |
- isolate()->factory()->NewRawTwoByteString(kInitialSpecialStringSize, |
- NOT_TENURED); |
- Handle<SeqTwoByteString> seq_two_byte = |
- Handle<SeqTwoByteString>::cast(two_byte); |
+template <typename StringType, typename SinkChar> |
+Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( |
+ Handle<String> prefix, int start, int end) { |
+ int count = end - start; |
+ int max_length = count + source_length_ - position_; |
+ int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); |
+ Handle<StringType> seq_str = NewRawString<StringType>(isolate()->factory(), |
+ length); |
+ // Copy prefix into seq_str. |
+ SinkChar* dest = seq_str->GetChars(); |
+ String::WriteToFlat(*prefix, dest, start, end); |
- int allocation_count = 1; |
- int count = 0; |
- |
while (c0_ != '"') { |
- // Create new seq string |
- if (count >= kInitialSpecialStringSize * allocation_count) { |
- allocation_count = allocation_count * 2; |
- int new_size = allocation_count * kInitialSpecialStringSize; |
- Handle<String> new_two_byte = |
- isolate()->factory()->NewRawTwoByteString(new_size, |
- NOT_TENURED); |
- uc16* char_start = |
- Handle<SeqTwoByteString>::cast(new_two_byte)->GetChars(); |
- String::WriteToFlat(*seq_two_byte, char_start, 0, count); |
- seq_two_byte = Handle<SeqTwoByteString>::cast(new_two_byte); |
+ if (count >= length) { |
+ // We need to create a longer sequential string for the result. |
+ return SlowScanJsonString<StringType, SinkChar>(seq_str, 0, count); |
} |
- |
// Check for control character (0x00-0x1f) or unterminated string (<0). |
if (c0_ < 0x20) return Handle<String>::null(); |
if (c0_ != '\\') { |
- seq_two_byte->SeqTwoByteStringSet(count++, c0_); |
- Advance(); |
+ // If the sink can contain UC16 characters, or source_ contains only |
+ // ASCII characters, there's no need to test whether we can store the |
+ // character. Otherwise check whether the UC16 source character can fit |
+ // in the ASCII sink. |
+ if (sizeof(SinkChar) == kUC16Size || |
+ seq_ascii || |
+ c0_ <= kMaxAsciiCharCode) { |
+ SeqStringSet(seq_str, count++, c0_); |
+ Advance(); |
+ } else { |
+ // StringType is SeqAsciiString and we just read a non-ASCII char. |
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, 0, count); |
+ } |
} else { |
- Advance(); |
+ Advance(); // Advance past the \. |
switch (c0_) { |
case '"': |
case '\\': |
case '/': |
- seq_two_byte->SeqTwoByteStringSet(count++, c0_); |
+ SeqStringSet(seq_str, count++, c0_); |
break; |
case 'b': |
- seq_two_byte->SeqTwoByteStringSet(count++, '\x08'); |
+ SeqStringSet(seq_str, count++, '\x08'); |
break; |
case 'f': |
- seq_two_byte->SeqTwoByteStringSet(count++, '\x0c'); |
+ SeqStringSet(seq_str, count++, '\x0c'); |
break; |
case 'n': |
- seq_two_byte->SeqTwoByteStringSet(count++, '\x0a'); |
+ SeqStringSet(seq_str, count++, '\x0a'); |
break; |
case 'r': |
- seq_two_byte->SeqTwoByteStringSet(count++, '\x0d'); |
+ SeqStringSet(seq_str, count++, '\x0d'); |
break; |
case 't': |
- seq_two_byte->SeqTwoByteStringSet(count++, '\x09'); |
+ SeqStringSet(seq_str, count++, '\x09'); |
break; |
case 'u': { |
uc32 value = 0; |
@@ -477,8 +510,17 @@ |
} |
value = value * 16 + digit; |
} |
- seq_two_byte->SeqTwoByteStringSet(count++, value); |
- break; |
+ if (sizeof(SinkChar) == kUC16Size || value <= kMaxAsciiCharCode) { |
+ SeqStringSet(seq_str, count++, value); |
+ break; |
+ } else { |
+ // StringType is SeqAsciiString and we just read a non-ASCII char. |
+ position_ -= 6; // Rewind position_ to \ in \uxxxx. |
+ Advance(); |
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, |
+ 0, |
+ count); |
+ } |
} |
default: |
return Handle<String>::null(); |
@@ -486,56 +528,69 @@ |
Advance(); |
} |
} |
- // Advance past the last '"'. |
- ASSERT_EQ('"', c0_); |
- AdvanceSkipWhitespace(); |
- |
- // Shrink the the string to our length. |
- if (isolate()->heap()->InNewSpace(*seq_two_byte)) { |
+ // Shrink seq_string length to count. |
+ if (isolate()->heap()->InNewSpace(*seq_str)) { |
isolate()->heap()->new_space()-> |
- template ShrinkStringAtAllocationBoundary<SeqTwoByteString>( |
- *seq_two_byte, count); |
+ template ShrinkStringAtAllocationBoundary<StringType>( |
+ *seq_str, count); |
} else { |
- int string_size = SeqTwoByteString::SizeFor(count); |
- int allocated_string_size = |
- SeqTwoByteString::SizeFor(kInitialSpecialStringSize * allocation_count); |
+ int string_size = StringType::SizeFor(count); |
+ int allocated_string_size = StringType::SizeFor(length); |
int delta = allocated_string_size - string_size; |
- Address start_filler_object = seq_two_byte->address() + string_size; |
- seq_two_byte->set_length(count); |
+ Address start_filler_object = seq_str->address() + string_size; |
+ seq_str->set_length(count); |
isolate()->heap()->CreateFillerObjectAt(start_filler_object, delta); |
} |
- return isolate()->factory()->NewConsString(ascii, seq_two_byte); |
+ ASSERT_EQ('"', c0_); |
+ // Advance past the last '"'. |
+ AdvanceSkipWhitespace(); |
+ return seq_str; |
} |
+ |
template <bool seq_ascii> |
template <bool is_symbol> |
Handle<String> JsonParser<seq_ascii>::ScanJsonString() { |
ASSERT_EQ('"', c0_); |
Advance(); |
+ if (c0_ == '"') { |
+ AdvanceSkipWhitespace(); |
+ return Handle<String>(isolate()->heap()->empty_string()); |
+ } |
int beg_pos = position_; |
- // Fast case for ascii only without escape characters. |
- while (c0_ != '"') { |
+ // Fast case for ASCII only without escape characters. |
+ do { |
// Check for control character (0x00-0x1f) or unterminated string (<0). |
if (c0_ < 0x20) return Handle<String>::null(); |
- if (c0_ != '\\' && (seq_ascii || c0_ < kMaxAsciiCharCode)) { |
- Advance(); |
+ if (c0_ != '\\') { |
+ if (seq_ascii || c0_ <= kMaxAsciiCharCode) { |
+ Advance(); |
+ } else { |
+ return SlowScanJsonString<SeqTwoByteString, uc16>(source_, |
+ beg_pos, |
+ position_); |
+ } |
} else { |
- return this->SlowScanJsonString(beg_pos); |
+ return SlowScanJsonString<SeqAsciiString, char>(source_, |
+ beg_pos, |
+ position_); |
} |
+ } while (c0_ != '"'); |
+ int length = position_ - beg_pos; |
+ Handle<String> result; |
+ if (seq_ascii && is_symbol) { |
+ result = isolate()->factory()->LookupAsciiSymbol(seq_source_, |
+ beg_pos, |
+ length); |
+ } else { |
+ result = isolate()->factory()->NewRawAsciiString(length); |
+ char* dest = SeqAsciiString::cast(*result)->GetChars(); |
+ String::WriteToFlat(*source_, dest, beg_pos, position_); |
} |
ASSERT_EQ('"', c0_); |
- int end_pos = position_; |
// Advance past the last '"'. |
AdvanceSkipWhitespace(); |
- if (seq_ascii && is_symbol) { |
- return isolate()->factory()->LookupAsciiSymbol(seq_source_, |
- beg_pos, |
- end_pos - beg_pos); |
- } else { |
- return isolate()->factory()->NewProperSubString(source_, |
- beg_pos, |
- end_pos); |
- } |
+ return result; |
} |
} } // namespace v8::internal |