diff options
Diffstat (limited to 'src/3rdparty/v8/src/json-parser.h')
-rw-r--r-- | src/3rdparty/v8/src/json-parser.h | 266 |
1 files changed, 185 insertions, 81 deletions
diff --git a/src/3rdparty/v8/src/json-parser.h b/src/3rdparty/v8/src/json-parser.h index d22cd0d..6f8c715 100644 --- a/src/3rdparty/v8/src/json-parser.h +++ b/src/3rdparty/v8/src/json-parser.h @@ -43,15 +43,15 @@ namespace internal { template <bool seq_ascii> class JsonParser BASE_EMBEDDED { public: - static Handle<Object> Parse(Handle<String> source) { - return JsonParser().ParseJson(source); + static Handle<Object> Parse(Handle<String> source, Zone* zone) { + return JsonParser().ParseJson(source, zone); } static const int kEndOfString = -1; private: // Parse a string containing a single JSON value. - Handle<Object> ParseJson(Handle<String> source); + Handle<Object> ParseJson(Handle<String> source, Zone* zone); inline void Advance() { position_++; @@ -71,11 +71,11 @@ class JsonParser BASE_EMBEDDED { inline void AdvanceSkipWhitespace() { do { Advance(); - } while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' '); + } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r'); } inline void SkipWhitespace() { - while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ') { + while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') { Advance(); } } @@ -149,8 +149,12 @@ class JsonParser BASE_EMBEDDED { } inline Isolate* isolate() { return isolate_; } + inline Factory* factory() { return factory_; } + inline Handle<JSFunction> object_constructor() { return object_constructor_; } + inline Zone* zone() const { return zone_; } static const int kInitialSpecialStringLength = 1024; + static const int kPretenureTreshold = 100 * 1024; private: @@ -158,17 +162,27 @@ class JsonParser BASE_EMBEDDED { int source_length_; Handle<SeqAsciiString> seq_source_; + PretenureFlag pretenure_; Isolate* isolate_; + Factory* factory_; + Handle<JSFunction> object_constructor_; uc32 c0_; int position_; + Zone* zone_; }; template <bool seq_ascii> -Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source) { +Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source, + Zone* zone) { isolate_ = source->map()->GetHeap()->isolate(); + factory_ = isolate_->factory(); + object_constructor_ = Handle<JSFunction>( + isolate()->native_context()->object_function(), isolate()); + zone_ = zone; FlattenString(source); source_ = source; source_length_ = source_->length(); + pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED; // Optimized fast case where we only have ASCII characters. if (seq_ascii) { @@ -181,10 +195,12 @@ Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source) { AdvanceSkipWhitespace(); Handle<Object> result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { - // Parse failed. Current character is the unexpected token. + // Some exception (for example stack overflow) is already pending. + if (isolate_->has_pending_exception()) return Handle<Object>::null(); + // Parse failed. Current character is the unexpected token. const char* message; - Factory* factory = isolate()->factory(); + Factory* factory = this->factory(); Handle<JSArray> array; switch (c0_) { @@ -233,87 +249,118 @@ Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source) { // 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(); + StackLimitCheck stack_check(isolate_); + if (stack_check.HasOverflowed()) { + isolate_->StackOverflow(); + return Handle<Object>::null(); + } + + if (c0_ == '"') return ParseJsonString(); + if ((c0_ >= '0' && c0_ <= '9') || c0_ == '-') return ParseJsonNumber(); + if (c0_ == '{') return ParseJsonObject(); + if (c0_ == '[') return ParseJsonArray(); + if (c0_ == 'f') { + if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' && + AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') { + AdvanceSkipWhitespace(); + return factory()->false_value(); + } + return ReportUnexpectedCharacter(); + } + if (c0_ == 't') { + if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' && + AdvanceGetChar() == 'e') { + AdvanceSkipWhitespace(); + return factory()->true_value(); + } + return ReportUnexpectedCharacter(); + } + if (c0_ == 'n') { + if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' && + AdvanceGetChar() == 'l') { + AdvanceSkipWhitespace(); + return factory()->null_value(); + } + return ReportUnexpectedCharacter(); } + 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<Object> prototype; Handle<JSObject> json_object = - isolate()->factory()->NewJSObject(object_constructor); + factory()->NewJSObject(object_constructor(), pretenure_); ASSERT_EQ(c0_, '{'); AdvanceSkipWhitespace(); if (c0_ != '}') { do { if (c0_ != '"') return ReportUnexpectedCharacter(); + + int start_position = position_; + Advance(); + + uint32_t index = 0; + if (c0_ >= '0' && c0_ <= '9') { + // Maybe an array index, try to parse it. + if (c0_ == '0') { + // With a leading zero, the string has to be "0" only to be an index. + Advance(); + } else { + do { + int d = c0_ - '0'; + if (index > 429496729U - ((d > 5) ? 1 : 0)) break; + index = (index * 10) + d; + Advance(); + } while (c0_ >= '0' && c0_ <= '9'); + } + + if (c0_ == '"') { + // Successfully parsed index, parse and store element. + AdvanceSkipWhitespace(); + + if (c0_ != ':') return ReportUnexpectedCharacter(); + AdvanceSkipWhitespace(); + Handle<Object> value = ParseJsonValue(); + if (value.is_null()) return ReportUnexpectedCharacter(); + + JSObject::SetOwnElement(json_object, index, value, kNonStrictMode); + continue; + } + // Not an index, fallback to the slow path. + } + + position_ = start_position; +#ifdef DEBUG + c0_ = '"'; +#endif + 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)) { - JSObject::SetOwnElement(json_object, index, value, kNonStrictMode); - } else if (key->Equals(isolate()->heap()->Proto_symbol())) { - SetPrototype(json_object, value); + if (key->Equals(isolate()->heap()->Proto_symbol())) { + prototype = value; } else { - JSObject::SetLocalPropertyIgnoreAttributes( - json_object, key, value, NONE); + if (JSObject::TryTransitionToField(json_object, key)) { + int index = json_object->LastAddedFieldIndex(); + json_object->FastPropertyAtPut(index, *value); + } else { + JSObject::SetLocalPropertyIgnoreAttributes( + json_object, key, value, NONE); + } } } while (MatchSkipWhiteSpace(',')); if (c0_ != '}') { return ReportUnexpectedCharacter(); } + if (!prototype.is_null()) SetPrototype(json_object, prototype); } AdvanceSkipWhitespace(); return json_object; @@ -322,8 +369,8 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { // 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); + ZoneScope zone_scope(zone(), DELETE_ON_EXIT); + ZoneList<Handle<Object> > elements(4, zone()); ASSERT_EQ(c0_, '['); AdvanceSkipWhitespace(); @@ -331,7 +378,7 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() { do { Handle<Object> element = ParseJsonValue(); if (element.is_null()) return ReportUnexpectedCharacter(); - elements.Add(element); + elements.Add(element, zone()); } while (MatchSkipWhiteSpace(',')); if (c0_ != ']') { return ReportUnexpectedCharacter(); @@ -340,11 +387,12 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() { AdvanceSkipWhitespace(); // Allocate a fixed array with all the elements. Handle<FixedArray> fast_elements = - isolate()->factory()->NewFixedArray(elements.length()); + factory()->NewFixedArray(elements.length(), pretenure_); for (int i = 0, n = elements.length(); i < n; i++) { fast_elements->set(i, *elements[i]); } - return isolate()->factory()->NewJSArrayWithElements(fast_elements); + return factory()->NewJSArrayWithElements( + fast_elements, FAST_ELEMENTS, pretenure_); } @@ -411,7 +459,7 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonNumber() { buffer.Dispose(); } SkipWhitespace(); - return isolate()->factory()->NewNumber(number); + return factory()->NewNumber(number, pretenure_); } @@ -429,16 +477,22 @@ inline void SeqStringSet(Handle<SeqAsciiString> seq_str, int i, uc32 c) { } template <typename StringType> -inline Handle<StringType> NewRawString(Factory* factory, int length); +inline Handle<StringType> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure); template <> -inline Handle<SeqTwoByteString> NewRawString(Factory* factory, int length) { - return factory->NewRawTwoByteString(length, NOT_TENURED); +inline Handle<SeqTwoByteString> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure) { + return factory->NewRawTwoByteString(length, pretenure); } template <> -inline Handle<SeqAsciiString> NewRawString(Factory* factory, int length) { - return factory->NewRawAsciiString(length, NOT_TENURED); +inline Handle<SeqAsciiString> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure) { + return factory->NewRawAsciiString(length, pretenure); } @@ -452,8 +506,8 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( 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); + Handle<StringType> seq_str = + NewRawString<StringType>(factory(), length, pretenure_); // Copy prefix into seq_str. SinkChar* dest = seq_str->GetChars(); String::WriteToFlat(*prefix, dest, start, end); @@ -557,8 +611,58 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { Advance(); if (c0_ == '"') { AdvanceSkipWhitespace(); - return Handle<String>(isolate()->heap()->empty_string()); + return factory()->empty_string(); + } + + if (seq_ascii && is_symbol) { + // Fast path for existing symbols. If the the string being parsed is not + // a known symbol, contains backslashes or unexpectedly reaches the end of + // string, return with an empty handle. + uint32_t running_hash = isolate()->heap()->HashSeed(); + int position = position_; + uc32 c0 = c0_; + do { + if (c0 == '\\') { + c0_ = c0; + int beg_pos = position_; + position_ = position; + return SlowScanJsonString<SeqAsciiString, char>(source_, + beg_pos, + position_); + } + if (c0 < 0x20) return Handle<String>::null(); + running_hash = StringHasher::AddCharacterCore(running_hash, c0); + position++; + if (position >= source_length_) return Handle<String>::null(); + c0 = seq_source_->SeqAsciiStringGet(position); + } while (c0 != '"'); + int length = position - position_; + uint32_t hash = (length <= String::kMaxHashCalcLength) + ? StringHasher::GetHashCore(running_hash) : length; + Vector<const char> string_vector( + seq_source_->GetChars() + position_, length); + SymbolTable* symbol_table = isolate()->heap()->symbol_table(); + uint32_t capacity = symbol_table->Capacity(); + uint32_t entry = SymbolTable::FirstProbe(hash, capacity); + uint32_t count = 1; + while (true) { + Object* element = symbol_table->KeyAt(entry); + if (element == isolate()->heap()->undefined_value()) { + // Lookup failure. + break; + } + if (element != isolate()->heap()->the_hole_value() && + String::cast(element)->IsAsciiEqualTo(string_vector)) { + // Lookup success, update the current position. + position_ = position; + // Advance past the last '"'. + AdvanceSkipWhitespace(); + return Handle<String>(String::cast(element), isolate()); + } + entry = SymbolTable::NextProbe(entry, count++, capacity); + } } + int beg_pos = position_; // Fast case for ASCII only without escape characters. do { @@ -581,11 +685,11 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { int length = position_ - beg_pos; Handle<String> result; if (seq_ascii && is_symbol) { - result = isolate()->factory()->LookupAsciiSymbol(seq_source_, - beg_pos, - length); + result = factory()->LookupAsciiSymbol(seq_source_, + beg_pos, + length); } else { - result = isolate()->factory()->NewRawAsciiString(length); + result = factory()->NewRawAsciiString(length, pretenure_); char* dest = SeqAsciiString::cast(*result)->GetChars(); String::WriteToFlat(*source_, dest, beg_pos, position_); } |