Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Unified Diff: src/json-parser.h

Issue 7134010: Specialize JSON parser to only check for SequentialAsciiString once. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/SConscript ('k') | src/json-parser.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/json-parser.h
===================================================================
--- src/json-parser.h (revision 8194)
+++ src/json-parser.h (working copy)
@@ -28,12 +28,19 @@
#ifndef V8_JSON_PARSER_H_
#define V8_JSON_PARSER_H_
+#include "v8.h"
+
+#include "char-predicates-inl.h"
+#include "conversions.h"
+#include "messages.h"
+#include "spaces-inl.h"
#include "token.h"
namespace v8 {
namespace internal {
// A simple json parser.
+template <bool seq_ascii>
class JsonParser BASE_EMBEDDED {
public:
static Handle<Object> Parse(Handle<String> source) {
@@ -50,7 +57,7 @@
position_++;
if (position_ > source_length_) {
c0_ = kEndOfString;
- } else if (is_sequential_ascii_) {
+ } else if (seq_ascii) {
c0_ = seq_source_->SeqAsciiStringGet(position_);
} else {
c0_ = source_->Get(position_);
@@ -149,7 +156,6 @@
int source_length_;
Handle<SeqAsciiString> seq_source_;
- bool is_sequential_ascii_;
// begin and end position of scanned string or number
int beg_pos_;
int end_pos_;
@@ -161,6 +167,381 @@
double number_;
};
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source) {
+ isolate_ = source->map()->isolate();
+ source_ = Handle<String>(source->TryFlattenGetString());
+ source_length_ = source_->length() - 1;
+
+ // Optimized fast case where we only have ascii characters.
+ if (seq_ascii) {
+ seq_source_ = Handle<SeqAsciiString>::cast(source_);
+ }
+
+ // Set initial position right before the string.
+ position_ = -1;
+ // Advance to the first character (posibly EOS)
+ AdvanceSkipWhitespace();
+ Handle<Object> result = ParseJsonValue();
+ if (result.is_null() || c0_ != kEndOfString) {
+ // Parse failed. Current character is the unexpected token.
+
+ const char* message;
+ Factory* factory = isolate()->factory();
+ Handle<JSArray> array;
+
+ switch (c0_) {
+ case kEndOfString:
+ message = "unexpected_eos";
+ array = factory->NewJSArray(0);
+ break;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ message = "unexpected_token_number";
+ array = factory->NewJSArray(0);
+ break;
+ case '"':
+ message = "unexpected_token_string";
+ array = factory->NewJSArray(0);
+ break;
+ default:
+ message = "unexpected_token";
+ Handle<Object> name = LookupSingleCharacterStringFromCode(c0_);
+ Handle<FixedArray> element = factory->NewFixedArray(1);
+ element->set(0, *name);
+ array = factory->NewJSArrayWithElements(element);
+ break;
+ }
+
+ MessageLocation location(factory->NewScript(source),
+ position_,
+ position_ + 1);
+ Handle<Object> result = factory->NewSyntaxError(message, array);
+ isolate()->Throw(*result, &location);
+ return Handle<Object>::null();
+ }
+ return result;
+}
+
+
+// Parse any JSON value.
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonValue() {
+ switch (c0_) {
+ case '"':
+ return ParseJsonString();
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return ParseJsonNumber();
+ case 'f':
+ if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' &&
+ AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') {
+ AdvanceSkipWhitespace();
+ return isolate()->factory()->false_value();
+ } else {
+ return ReportUnexpectedCharacter();
+ }
+ case 't':
+ if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' &&
+ AdvanceGetChar() == 'e') {
+ AdvanceSkipWhitespace();
+ return isolate()->factory()->true_value();
+ } else {
+ return ReportUnexpectedCharacter();
+ }
+ case 'n':
+ if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' &&
+ AdvanceGetChar() == 'l') {
+ AdvanceSkipWhitespace();
+ return isolate()->factory()->null_value();
+ } else {
+ return ReportUnexpectedCharacter();
+ }
+ case '{':
+ return ParseJsonObject();
+ case '[':
+ return ParseJsonArray();
+ default:
+ return ReportUnexpectedCharacter();
+ }
+}
+
+
+// Parse a JSON object. Position must be right at '{'.
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
+ Handle<JSFunction> object_constructor(
+ isolate()->global_context()->object_function());
+ Handle<JSObject> json_object =
+ isolate()->factory()->NewJSObject(object_constructor);
+ ASSERT_EQ(c0_, '{');
+
+ AdvanceSkipWhitespace();
+ if (c0_ != '}') {
+ do {
+ if (c0_ != '"') return ReportUnexpectedCharacter();
+ Handle<String> key = ParseJsonSymbol();
+ if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+ AdvanceSkipWhitespace();
+ Handle<Object> value = ParseJsonValue();
+ if (value.is_null()) return ReportUnexpectedCharacter();
+
+ uint32_t index;
+ if (key->AsArrayIndex(&index)) {
+ SetOwnElement(json_object, index, value, kNonStrictMode);
+ } else if (key->Equals(isolate()->heap()->Proto_symbol())) {
+ SetPrototype(json_object, value);
+ } else {
+ SetLocalPropertyIgnoreAttributes(json_object, key, value, NONE);
+ }
+ } while (MatchSkipWhiteSpace(','));
+ if (c0_ != '}') {
+ return ReportUnexpectedCharacter();
+ }
+ }
+ AdvanceSkipWhitespace();
+ return json_object;
+}
+
+// Parse a JSON array. Position must be right at '['.
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() {
+ ZoneScope zone_scope(isolate(), DELETE_ON_EXIT);
+ ZoneList<Handle<Object> > elements(4);
+ ASSERT_EQ(c0_, '[');
+
+ AdvanceSkipWhitespace();
+ if (c0_ != ']') {
+ do {
+ Handle<Object> element = ParseJsonValue();
+ if (element.is_null()) return ReportUnexpectedCharacter();
+ elements.Add(element);
+ } while (MatchSkipWhiteSpace(','));
+ if (c0_ != ']') {
+ return ReportUnexpectedCharacter();
+ }
+ }
+ AdvanceSkipWhitespace();
+ // Allocate a fixed array with all the elements.
+ Handle<FixedArray> fast_elements =
+ isolate()->factory()->NewFixedArray(elements.length());
+ for (int i = 0, n = elements.length(); i < n; i++) {
+ fast_elements->set(i, *elements[i]);
+ }
+ return isolate()->factory()->NewJSArrayWithElements(fast_elements);
+}
+
+
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonNumber() {
+ bool negative = false;
+ beg_pos_ = position_;
+ if (c0_ == '-') {
+ Advance();
+ negative = true;
+ }
+ if (c0_ == '0') {
+ Advance();
+ // Prefix zero is only allowed if it's the only digit before
+ // a decimal point or exponent.
+ if ('0' <= c0_ && c0_ <= '9') return ReportUnexpectedCharacter();
+ } else {
+ int i = 0;
+ int digits = 0;
+ if (c0_ < '1' || c0_ > '9') return ReportUnexpectedCharacter();
+ do {
+ i = i * 10 + c0_ - '0';
+ digits++;
+ Advance();
+ } while (c0_ >= '0' && c0_ <= '9');
+ if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && digits < 10) {
+ number_ = (negative ? -i : i);
+ SkipWhitespace();
+ return isolate()->factory()->NewNumber(number_);
+ }
+ }
+ if (c0_ == '.') {
+ Advance();
+ if (c0_ < '0' || c0_ > '9') return ReportUnexpectedCharacter();
+ do {
+ Advance();
+ } while (c0_ >= '0' && c0_ <= '9');
+ }
+ if (AsciiAlphaToLower(c0_) == 'e') {
+ Advance();
+ if (c0_ == '-' || c0_ == '+') Advance();
+ if (c0_ < '0' || c0_ > '9') return ReportUnexpectedCharacter();
+ do {
+ Advance();
+ } while (c0_ >= '0' && c0_ <= '9');
+ }
+ int length = position_ - beg_pos_;
+ if (seq_ascii) {
+ Vector<const char> chars(seq_source_->GetChars() + beg_pos_, length);
+ number_ = StringToDouble(isolate()->unicode_cache(),
+ chars,
+ NO_FLAGS, // Hex, octal or trailing junk.
+ OS::nan_value());
+ } else {
+ Vector<char> buffer = Vector<char>::New(length);
+ String::WriteToFlat(*source_, buffer.start(), beg_pos_, position_);
+ Vector<const char> result =
+ Vector<const char>(reinterpret_cast<const char*>(buffer.start()),
+ length);
+ number_ = StringToDouble(isolate()->unicode_cache(),
+ result,
+ NO_FLAGS, // Hex, octal or trailing junk.
+ 0.0);
+ buffer.Dispose();
+ }
+ SkipWhitespace();
+ return isolate()->factory()->NewNumber(number_);
+}
+
+template <bool seq_ascii>
+Handle<String> JsonParser<seq_ascii>::SlowScanJsonString() {
+ // The currently scanned ascii characters.
+ Handle<String> ascii(isolate()->factory()->NewSubString(source_,
+ beg_pos_,
+ position_));
+ Handle<String> two_byte =
+ isolate()->factory()->NewRawTwoByteString(kInitialSpecialStringSize,
+ NOT_TENURED);
+ Handle<SeqTwoByteString> seq_two_byte =
+ Handle<SeqTwoByteString>::cast(two_byte);
+
+ 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);
+ }
+
+ // 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();
+ } else {
+ Advance();
+ switch (c0_) {
+ case '"':
+ case '\\':
+ case '/':
+ seq_two_byte->SeqTwoByteStringSet(count++, c0_);
+ break;
+ case 'b':
+ seq_two_byte->SeqTwoByteStringSet(count++, '\x08');
+ break;
+ case 'f':
+ seq_two_byte->SeqTwoByteStringSet(count++, '\x0c');
+ break;
+ case 'n':
+ seq_two_byte->SeqTwoByteStringSet(count++, '\x0a');
+ break;
+ case 'r':
+ seq_two_byte->SeqTwoByteStringSet(count++, '\x0d');
+ break;
+ case 't':
+ seq_two_byte->SeqTwoByteStringSet(count++, '\x09');
+ break;
+ case 'u': {
+ uc32 value = 0;
+ for (int i = 0; i < 4; i++) {
+ Advance();
+ int digit = HexValue(c0_);
+ if (digit < 0) {
+ return Handle<String>::null();
+ }
+ value = value * 16 + digit;
+ }
+ seq_two_byte->SeqTwoByteStringSet(count++, value);
+ break;
+ }
+ default:
+ return Handle<String>::null();
+ }
+ Advance();
+ }
+ }
+ // Advance past the last '"'.
+ ASSERT_EQ('"', c0_);
+ AdvanceSkipWhitespace();
+
+ // Shrink the the string to our length.
+ if (isolate()->heap()->InNewSpace(*seq_two_byte)) {
+ isolate()->heap()->new_space()->
+ template ShrinkStringAtAllocationBoundary<SeqTwoByteString>(
+ *seq_two_byte, count);
+ } else {
+ int string_size = SeqTwoByteString::SizeFor(count);
+ int allocated_string_size =
+ SeqTwoByteString::SizeFor(kInitialSpecialStringSize * allocation_count);
+ int delta = allocated_string_size - string_size;
+ Address start_filler_object = seq_two_byte->address() + string_size;
+ seq_two_byte->set_length(count);
+ isolate()->heap()->CreateFillerObjectAt(start_filler_object, delta);
+ }
+ return isolate()->factory()->NewConsString(ascii, seq_two_byte);
+}
+
+template <bool seq_ascii>
+template <bool is_symbol>
+Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
+ ASSERT_EQ('"', c0_);
+ Advance();
+ beg_pos_ = position_;
+ // Fast case for ascii only without escape characters.
+ while (c0_ != '"') {
+ // Check for control character (0x00-0x1f) or unterminated string (<0).
+ if (c0_ < 0x20) return Handle<String>::null();
+ if (c0_ != '\\' && (seq_ascii || c0_ < kMaxAsciiCharCode)) {
+ Advance();
+ } else {
+ return this->SlowScanJsonString();
+ }
+ }
+ ASSERT_EQ('"', c0_);
+ 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()->NewSubString(source_, beg_pos_, end_pos_);
+ }
+}
+
} } // namespace v8::internal
#endif // V8_JSON_PARSER_H_
« no previous file with comments | « src/SConscript ('k') | src/json-parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698