| Index: src/json-parser.cc
|
| diff --git a/src/json-parser.h b/src/json-parser.cc
|
| similarity index 73%
|
| copy from src/json-parser.h
|
| copy to src/json-parser.cc
|
| index 1b9829fa40ba39774656836ad1c8941b36ab3be3..fc8b17943b8aa03f458b5ee82dc335552c8a96fb 100644
|
| --- a/src/json-parser.h
|
| +++ b/src/json-parser.cc
|
| @@ -1,16 +1,16 @@
|
| -// Copyright 2011 the V8 project authors. All rights reserved.
|
| +// Copyright 2016 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.
|
|
|
| -#ifndef V8_JSON_PARSER_H_
|
| -#define V8_JSON_PARSER_H_
|
| +#include "src/json-parser.h"
|
|
|
| -#include "src/char-predicates.h"
|
| +#include "src/char-predicates-inl.h"
|
| #include "src/conversions.h"
|
| #include "src/debug/debug.h"
|
| #include "src/factory.h"
|
| #include "src/field-type.h"
|
| #include "src/messages.h"
|
| +#include "src/objects-inl.h"
|
| #include "src/parsing/scanner.h"
|
| #include "src/parsing/token.h"
|
| #include "src/transitions.h"
|
| @@ -18,195 +18,24 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
|
| -
|
| -
|
| -// A simple json parser.
|
| template <bool seq_one_byte>
|
| -class JsonParser BASE_EMBEDDED {
|
| - public:
|
| - MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
|
| - return JsonParser(source).ParseJson();
|
| - }
|
| -
|
| - static const int kEndOfString = -1;
|
| -
|
| - private:
|
| - explicit JsonParser(Handle<String> source)
|
| - : source_(source),
|
| - source_length_(source->length()),
|
| - isolate_(source->map()->GetHeap()->isolate()),
|
| - factory_(isolate_->factory()),
|
| - zone_(isolate_->allocator()),
|
| - object_constructor_(isolate_->native_context()->object_function(),
|
| - isolate_),
|
| - position_(-1) {
|
| - source_ = String::Flatten(source_);
|
| - pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED;
|
| -
|
| - // Optimized fast case where we only have Latin1 characters.
|
| - if (seq_one_byte) {
|
| - seq_source_ = Handle<SeqOneByteString>::cast(source_);
|
| - }
|
| - }
|
| -
|
| - // Parse a string containing a single JSON value.
|
| - MaybeHandle<Object> ParseJson();
|
| -
|
| - inline void Advance() {
|
| - position_++;
|
| - if (position_ >= source_length_) {
|
| - c0_ = kEndOfString;
|
| - } else if (seq_one_byte) {
|
| - c0_ = seq_source_->SeqOneByteStringGet(position_);
|
| - } else {
|
| - c0_ = source_->Get(position_);
|
| - }
|
| - }
|
| -
|
| - // The JSON lexical grammar is specified in the ECMAScript 5 standard,
|
| - // section 15.12.1.1. The only allowed whitespace characters between tokens
|
| - // are tab, carriage-return, newline and space.
|
| -
|
| - inline void AdvanceSkipWhitespace() {
|
| - do {
|
| - Advance();
|
| - } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
|
| - }
|
| -
|
| - inline void SkipWhitespace() {
|
| - while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
|
| - Advance();
|
| - }
|
| - }
|
| -
|
| - inline uc32 AdvanceGetChar() {
|
| - Advance();
|
| - return c0_;
|
| - }
|
| -
|
| - // Checks that current charater is c.
|
| - // If so, then consume c and skip whitespace.
|
| - inline bool MatchSkipWhiteSpace(uc32 c) {
|
| - if (c0_ == c) {
|
| - AdvanceSkipWhitespace();
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - // A JSON string (production JSONString) is subset of valid JavaScript string
|
| - // literals. The string must only be double-quoted (not single-quoted), and
|
| - // the only allowed backslash-escapes are ", /, \, b, f, n, r, t and
|
| - // four-digit hex escapes (uXXXX). Any other use of backslashes is invalid.
|
| - Handle<String> ParseJsonString() {
|
| - return ScanJsonString<false>();
|
| - }
|
| -
|
| - bool ParseJsonString(Handle<String> expected) {
|
| - int length = expected->length();
|
| - if (source_->length() - position_ - 1 > length) {
|
| - DisallowHeapAllocation no_gc;
|
| - String::FlatContent content = expected->GetFlatContent();
|
| - if (content.IsOneByte()) {
|
| - DCHECK_EQ('"', c0_);
|
| - const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
|
| - const uint8_t* expected_chars = content.ToOneByteVector().start();
|
| - for (int i = 0; i < length; i++) {
|
| - uint8_t 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;
|
| - }
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - Handle<String> ParseJsonInternalizedString() {
|
| - Handle<String> result = ScanJsonString<true>();
|
| - if (result.is_null()) return result;
|
| - return factory()->InternalizeString(result);
|
| - }
|
| -
|
| - template <bool is_internalized>
|
| - Handle<String> ScanJsonString();
|
| - // 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-Latin1 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.
|
| - // It includes an optional minus sign, must have at least one
|
| - // digit before and after a decimal point, may not have prefixed zeros (unless
|
| - // the integer part is zero), and may include an exponent part (e.g., "e-10").
|
| - // Hexadecimal and octal numbers are not allowed.
|
| - Handle<Object> ParseJsonNumber();
|
| -
|
| - // Parse a single JSON value from input (grammar production JSONValue).
|
| - // A JSON value is either a (double-quoted) string literal, a number literal,
|
| - // one of "true", "false", or "null", or an object or array literal.
|
| - Handle<Object> ParseJsonValue();
|
| -
|
| - // Parse a JSON object literal (grammar production JSONObject).
|
| - // An object literal is a squiggly-braced and comma separated sequence
|
| - // (possibly empty) of key/value pairs, where the key is a JSON string
|
| - // literal, the value is a JSON value, and the two are separated by a colon.
|
| - // A JSON array doesn't allow numbers and identifiers as keys, like a
|
| - // JavaScript array.
|
| - Handle<Object> ParseJsonObject();
|
| -
|
| - // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded
|
| - // as an element, not a property.
|
| - ParseElementResult ParseElement(Handle<JSObject> json_object);
|
| -
|
| - // Parses a JSON array literal (grammar production JSONArray). An array
|
| - // literal is a square-bracketed and comma separated sequence (possibly empty)
|
| - // of JSON values.
|
| - // A JSON array doesn't allow leaving out values from the sequence, nor does
|
| - // it allow a terminal comma, like a JavaScript array does.
|
| - Handle<Object> ParseJsonArray();
|
| -
|
| -
|
| - // Mark that a parsing error has happened at the current token, and
|
| - // return a null handle. Primarily for readability.
|
| - inline Handle<Object> ReportUnexpectedCharacter() {
|
| - return Handle<Object>::null();
|
| +JsonParser<seq_one_byte>::JsonParser(Handle<String> source)
|
| + : source_(source),
|
| + source_length_(source->length()),
|
| + isolate_(source->map()->GetHeap()->isolate()),
|
| + factory_(isolate_->factory()),
|
| + zone_(isolate_->allocator()),
|
| + object_constructor_(isolate_->native_context()->object_function(),
|
| + isolate_),
|
| + position_(-1) {
|
| + source_ = String::Flatten(source_);
|
| + pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED;
|
| +
|
| + // Optimized fast case where we only have Latin1 characters.
|
| + if (seq_one_byte) {
|
| + seq_source_ = Handle<SeqOneByteString>::cast(source_);
|
| }
|
| -
|
| - inline Isolate* isolate() { return isolate_; }
|
| - inline Factory* factory() { return factory_; }
|
| - inline Handle<JSFunction> object_constructor() { return object_constructor_; }
|
| -
|
| - static const int kInitialSpecialStringLength = 32;
|
| - static const int kPretenureTreshold = 100 * 1024;
|
| -
|
| -
|
| - private:
|
| - Zone* zone() { return &zone_; }
|
| -
|
| - void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map,
|
| - ZoneList<Handle<Object> >* properties);
|
| -
|
| - Handle<String> source_;
|
| - int source_length_;
|
| - Handle<SeqOneByteString> seq_source_;
|
| -
|
| - PretenureFlag pretenure_;
|
| - Isolate* isolate_;
|
| - Factory* factory_;
|
| - Zone zone_;
|
| - Handle<JSFunction> object_constructor_;
|
| - uc32 c0_;
|
| - int position_;
|
| -};
|
| +}
|
|
|
| template <bool seq_one_byte>
|
| MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
|
| @@ -261,6 +90,72 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
|
| return result;
|
| }
|
|
|
| +template <bool seq_one_byte>
|
| +void JsonParser<seq_one_byte>::Advance() {
|
| + position_++;
|
| + if (position_ >= source_length_) {
|
| + c0_ = kEndOfString;
|
| + } else if (seq_one_byte) {
|
| + c0_ = seq_source_->SeqOneByteStringGet(position_);
|
| + } else {
|
| + c0_ = source_->Get(position_);
|
| + }
|
| +}
|
| +
|
| +template <bool seq_one_byte>
|
| +void JsonParser<seq_one_byte>::AdvanceSkipWhitespace() {
|
| + do {
|
| + Advance();
|
| + } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
|
| +}
|
| +
|
| +template <bool seq_one_byte>
|
| +void JsonParser<seq_one_byte>::SkipWhitespace() {
|
| + while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
|
| + Advance();
|
| + }
|
| +}
|
| +
|
| +template <bool seq_one_byte>
|
| +uc32 JsonParser<seq_one_byte>::AdvanceGetChar() {
|
| + Advance();
|
| + return c0_;
|
| +}
|
| +
|
| +template <bool seq_one_byte>
|
| +bool JsonParser<seq_one_byte>::MatchSkipWhiteSpace(uc32 c) {
|
| + if (c0_ == c) {
|
| + AdvanceSkipWhitespace();
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +template <bool seq_one_byte>
|
| +bool JsonParser<seq_one_byte>::ParseJsonString(Handle<String> expected) {
|
| + int length = expected->length();
|
| + if (source_->length() - position_ - 1 > length) {
|
| + DisallowHeapAllocation no_gc;
|
| + String::FlatContent content = expected->GetFlatContent();
|
| + if (content.IsOneByte()) {
|
| + DCHECK_EQ('"', c0_);
|
| + const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
|
| + const uint8_t* expected_chars = content.ToOneByteVector().start();
|
| + for (int i = 0; i < length; i++) {
|
| + uint8_t 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;
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| +}
|
|
|
| // Parse any JSON value.
|
| template <bool seq_one_byte>
|
| @@ -308,7 +203,6 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
|
| return ReportUnexpectedCharacter();
|
| }
|
|
|
| -
|
| template <bool seq_one_byte>
|
| ParseElementResult JsonParser<seq_one_byte>::ParseElement(
|
| Handle<JSObject> json_object) {
|
| @@ -481,7 +375,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
|
| if (value.is_null()) return ReportUnexpectedCharacter();
|
|
|
| JSObject::DefinePropertyOrElementIgnoreAttributes(json_object, key,
|
| - value).Check();
|
| + value)
|
| + .Check();
|
| }
|
| }
|
|
|
| @@ -493,7 +388,6 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
|
| return scope.CloseAndEscape(json_object);
|
| }
|
|
|
| -
|
| template <bool seq_one_byte>
|
| void JsonParser<seq_one_byte>::CommitStateToJsonObject(
|
| Handle<JSObject> json_object, Handle<Map> map,
|
| @@ -510,7 +404,6 @@ void JsonParser<seq_one_byte>::CommitStateToJsonObject(
|
| }
|
| }
|
|
|
| -
|
| // Parse a JSON array. Position must be right at '['.
|
| template <bool seq_one_byte>
|
| Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() {
|
| @@ -541,7 +434,6 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() {
|
| return scope.CloseAndEscape(json_array);
|
| }
|
|
|
| -
|
| template <bool seq_one_byte>
|
| Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
|
| bool negative = false;
|
| @@ -587,7 +479,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
|
| int length = position_ - beg_pos;
|
| double number;
|
| if (seq_one_byte) {
|
| - Vector<const uint8_t> chars(seq_source_->GetChars() + beg_pos, length);
|
| + Vector<const uint8_t> chars(seq_source_->GetChars() + beg_pos, length);
|
| number = StringToDouble(isolate()->unicode_cache(), chars,
|
| NO_FLAGS, // Hex, octal or trailing junk.
|
| std::numeric_limits<double>::quiet_NaN());
|
| @@ -596,8 +488,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
|
| String::WriteToFlat(*source_, buffer.start(), beg_pos, position_);
|
| Vector<const uint8_t> result =
|
| Vector<const uint8_t>(buffer.start(), length);
|
| - number = StringToDouble(isolate()->unicode_cache(),
|
| - result,
|
| + number = StringToDouble(isolate()->unicode_cache(), result,
|
| NO_FLAGS, // Hex, octal or trailing junk.
|
| 0.0);
|
| buffer.Dispose();
|
| @@ -606,7 +497,6 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
|
| return factory()->NewNumber(number, pretenure_);
|
| }
|
|
|
| -
|
| template <typename StringType>
|
| inline void SeqStringSet(Handle<StringType> seq_str, int i, uc32 c);
|
|
|
| @@ -621,25 +511,21 @@ inline void SeqStringSet(Handle<SeqOneByteString> 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,
|
| +inline Handle<SeqTwoByteString> NewRawString(Factory* factory, int length,
|
| PretenureFlag pretenure) {
|
| return factory->NewRawTwoByteString(length, pretenure).ToHandleChecked();
|
| }
|
|
|
| template <>
|
| -inline Handle<SeqOneByteString> NewRawString(Factory* factory,
|
| - int length,
|
| - PretenureFlag pretenure) {
|
| +inline Handle<SeqOneByteString> NewRawString(Factory* factory, int length,
|
| + PretenureFlag pretenure) {
|
| return factory->NewRawOneByteString(length, pretenure).ToHandleChecked();
|
| }
|
|
|
| -
|
| // 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.
|
| @@ -718,8 +604,7 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
|
| // char.
|
| position_ -= 6; // Rewind position_ to \ in \uxxxx.
|
| Advance();
|
| - return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string,
|
| - 0,
|
| + return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0,
|
| count);
|
| }
|
| }
|
| @@ -738,7 +623,6 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
|
| return SeqString::Truncate(seq_string, count);
|
| }
|
|
|
| -
|
| template <bool seq_one_byte>
|
| template <bool is_internalized>
|
| Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| @@ -761,8 +645,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| c0_ = c0;
|
| int beg_pos = position_;
|
| position_ = position;
|
| - return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
|
| - beg_pos,
|
| + return SlowScanJsonString<SeqOneByteString, uint8_t>(source_, beg_pos,
|
| position_);
|
| }
|
| if (c0 < 0x20) return Handle<String>::null();
|
| @@ -776,8 +659,8 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| uint32_t hash = (length <= String::kMaxHashCalcLength)
|
| ? StringHasher::GetHashCore(running_hash)
|
| : static_cast<uint32_t>(length);
|
| - Vector<const uint8_t> string_vector(
|
| - seq_source_->GetChars() + position_, length);
|
| + Vector<const uint8_t> string_vector(seq_source_->GetChars() + position_,
|
| + length);
|
| StringTable* string_table = isolate()->heap()->string_table();
|
| uint32_t capacity = string_table->Capacity();
|
| uint32_t entry = StringTable::FirstProbe(hash, capacity);
|
| @@ -787,8 +670,8 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| Object* element = string_table->KeyAt(entry);
|
| if (element == isolate()->heap()->undefined_value()) {
|
| // Lookup failure.
|
| - result = factory()->InternalizeOneByteString(
|
| - seq_source_, position_, length);
|
| + result =
|
| + factory()->InternalizeOneByteString(seq_source_, position_, length);
|
| break;
|
| }
|
| if (element != isolate()->heap()->the_hole_value() &&
|
| @@ -819,13 +702,11 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| if (seq_one_byte || c0_ <= String::kMaxOneByteCharCode) {
|
| Advance();
|
| } else {
|
| - return SlowScanJsonString<SeqTwoByteString, uc16>(source_,
|
| - beg_pos,
|
| + return SlowScanJsonString<SeqTwoByteString, uc16>(source_, beg_pos,
|
| position_);
|
| }
|
| } else {
|
| - return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
|
| - beg_pos,
|
| + return SlowScanJsonString<SeqOneByteString, uint8_t>(source_, beg_pos,
|
| position_);
|
| }
|
| } while (c0_ != '"');
|
| @@ -841,7 +722,9 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
|
| return result;
|
| }
|
|
|
| +// Explicit instantiation.
|
| +template class JsonParser<true>;
|
| +template class JsonParser<false>;
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
| -
|
| -#endif // V8_JSON_PARSER_H_
|
|
|