v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
json-parser.h
Go to the documentation of this file.
1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_JSON_JSON_PARSER_H_
6#define V8_JSON_JSON_PARSER_H_
7
8#include <optional>
9
12#include "src/base/strings.h"
15#include "src/heap/factory.h"
16#include "src/objects/objects.h"
17#include "src/objects/string.h"
18#include "src/roots/roots.h"
19
20namespace v8 {
21namespace internal {
22
24
25class JsonString final {
26 public:
28 : start_(0),
29 length_(0),
30 needs_conversion_(false),
31 internalize_(false),
32 has_escape_(false),
33 is_index_(false) {}
34
35 explicit JsonString(uint32_t index)
36 : index_(index),
37 length_(0),
38 needs_conversion_(false),
39 internalize_(false),
40 has_escape_(false),
41 is_index_(true) {}
42
43 JsonString(uint32_t start, uint32_t length, bool needs_conversion,
44 bool internalize, bool has_escape)
45 : start_(start),
46 length_(length),
48 internalize_(internalize),
50 is_index_(false) {}
51
52 bool internalize() const {
54 return internalize_;
55 }
56
57 bool needs_conversion() const {
59 return needs_conversion_;
60 }
61
62 bool has_escape() const {
64 return has_escape_;
65 }
66
67 uint32_t start() const {
69 return start_;
70 }
71
72 uint32_t length() const {
74 return length_;
75 }
76
77 uint32_t index() const {
79 return index_;
80 }
81
82 bool is_index() const { return is_index_; }
83
84 private:
85 union {
86 const uint32_t start_;
87 const uint32_t index_;
88 };
89 const uint32_t length_;
90 const bool needs_conversion_ : 1;
91 const bool internalize_ : 1;
92 const bool has_escape_ : 1;
93 const bool is_index_ : 1;
94};
95
98 explicit JsonProperty(const JsonString& string) : string(string) {}
100 : string(string), value(value) {}
101
104};
105
107 public:
110 Handle<Object> reviver,
111 Handle<String> source,
112 MaybeHandle<Object> val_node);
113
114 private:
116 Handle<String> source)
117 : isolate_(isolate), reviver_(reviver), source_(source) {}
118
120
121 template <WithOrWithoutSource with_source>
124 Handle<Object> val_node,
125 DirectHandle<Object> snapshot);
126
127 template <WithOrWithoutSource with_source>
129 Handle<Object> val_node, Handle<Object> snapshot);
130
134};
135
136enum class JsonToken : uint8_t {
137 NUMBER,
138 STRING,
139 LBRACE,
140 RBRACE,
141 LBRACK,
142 RBRACK,
147 COLON,
148 COMMA,
149 ILLEGAL,
150 EOS
151};
152
153// A simple json parser.
154template <typename Char>
155class JsonParser final {
156 public:
159
161 Handle<String> source) {
162 return JsonParser(isolate, source).ParseRawJson();
163 }
164
166 Isolate* isolate, Handle<String> source, Handle<Object> reviver) {
167 HighAllocationThroughputScope high_throughput_scope(
170 MaybeHandle<Object> val_node;
171 {
172 JsonParser parser(isolate, source);
173 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, parser.ParseJson(reviver));
174 val_node = parser.parsed_val_node_;
175 }
176 if (IsCallable(*reviver)) {
177 return JsonParseInternalizer::Internalize(isolate, result, reviver,
178 source, val_node);
179 }
180 return result;
181 }
182
183 static constexpr base::uc32 kEndOfString = static_cast<base::uc32>(-1);
185 static_cast<base::uc32>(-1);
186
187 private:
189
190 template <typename T>
194 JsonContinuation(Isolate* isolate, Type type, size_t index)
195 : scope(isolate),
196 type_(type),
197 index(static_cast<uint32_t>(index)),
198 max_index(0),
199 elements(0) {}
200
201 Type type() const { return static_cast<Type>(type_); }
202 void set_type(Type type) { type_ = static_cast<uint8_t>(type); }
203
205 // Unfortunately GCC doesn't like packing Type in two bits.
206 uint32_t type_ : 2;
207 uint32_t index : 30;
208 uint32_t max_index;
209 uint32_t elements;
210 };
211
212 JsonParser(Isolate* isolate, Handle<String> source);
213 ~JsonParser();
214
215 // Parse a string containing a single JSON value.
217
218 bool ParseRawJson();
219
220 void advance() { ++cursor_; }
221
223 if (V8_UNLIKELY(is_at_end())) return kEndOfString;
224 return *cursor_;
225 }
226
228 advance();
229 return CurrentCharacter();
230 }
231
232 void AdvanceToNonDecimal();
233
234 V8_INLINE JsonToken peek() const { return next_; }
235
236 void Consume(JsonToken token) {
237 DCHECK_EQ(peek(), token);
238 advance();
239 }
240
241 void Expect(JsonToken token,
242 std::optional<MessageTemplate> errorMessage = std::nullopt) {
243 if (V8_LIKELY(peek() == token)) {
244 advance();
245 } else {
246 errorMessage ? ReportUnexpectedToken(peek(), errorMessage.value())
248 }
249 }
250
252 std::optional<MessageTemplate> errorMessage = std::nullopt) {
254 errorMessage ? Expect(token, errorMessage.value()) : Expect(token);
255 }
256
257 bool Check(JsonToken token) {
259 if (next_ != token) return false;
260 advance();
261 return true;
262 }
263
264 template <size_t N>
265 void ScanLiteral(const char (&s)[N]) {
266 DCHECK(!is_at_end());
267 // There's at least 1 character, we always consume a character and compare
268 // the next character. The first character was compared before we jumped
269 // to ScanLiteral.
270 static_assert(N > 2);
271 size_t remaining = static_cast<size_t>(end_ - cursor_);
272 if (V8_LIKELY(remaining >= N - 1 &&
273 CompareCharsEqual(s + 1, cursor_ + 1, N - 2))) {
274 cursor_ += N - 1;
275 return;
276 }
277
278 cursor_++;
279 for (size_t i = 0; i < std::min(N - 2, remaining - 1); i++) {
280 if (*(s + 1 + i) != *cursor_) {
282 return;
283 }
284 cursor_++;
285 }
286
287 DCHECK(is_at_end());
289 }
290
291 // The JSON lexical grammar is specified in the ECMAScript 5 standard,
292 // section 15.12.1.1. The only allowed whitespace characters between tokens
293 // are tab, carriage-return, newline and space.
294 void SkipWhitespace();
295
296 // A JSON string (production JSONString) is subset of valid JavaScript string
297 // literals. The string must only be double-quoted (not single-quoted), and
298 // the only allowed backslash-escapes are ", /, \, b, f, n, r, t and
299 // four-digit hex escapes (uXXXX). Any other use of backslashes is invalid.
300 JsonString ScanJsonString(bool needs_internalization);
301 JsonString ScanJsonPropertyKey(JsonContinuation* cont);
308
309 template <typename SinkChar>
310 void DecodeString(SinkChar* sink, uint32_t start, uint32_t length);
311
312 template <typename SinkSeqString>
314 Handle<SinkSeqString> intermediate,
315 Handle<String> hint);
316
317 // A JSON number (production JSONNumber) is a subset of the valid JavaScript
318 // decimal number literals.
319 // It includes an optional minus sign, must have at least one
320 // digit before and after a decimal point, may not have prefixed zeros (unless
321 // the integer part is zero), and may include an exponent part (e.g., "e-10").
322 // Hexadecimal and octal numbers are not allowed.
324
325 // Parses a number either as a double or a Smi. Returns true if it was a
326 // double, false if it was a Smi.
327 bool ParseJsonNumberAsDoubleOrSmi(double* result_double, int* result_smi);
328
329 // Parse a single JSON value from input (grammar production JSONValue).
330 // A JSON value is either a (double-quoted) string literal, a number literal,
331 // one of "true", "false", or "null", or an object or array literal.
332 template <bool should_track_json_source>
334
336 Handle<Map> feedback = {});
337 MaybeHandle<Object> ParseJsonArray();
338 MaybeHandle<Object> ParseJsonObject(Handle<Map> feedback);
339
340 template <bool should_track_json_source>
341 Handle<JSObject> BuildJsonObject(const JsonContinuation& cont,
342 DirectHandle<Map> feedback);
344
345 static const int kMaxContextCharacters = 10;
347 (kMaxContextCharacters * 2) + 1;
348
349 // Mark that a parsing error has happened at the current character.
351 bool IsSpecialString();
354 int pos);
358 int pos);
359
360 // Calculate line and column based on the current cursor position.
361 // Both values start at 1.
363 DirectHandle<Object>& column);
364 // Mark that a parsing error has happened at the current token.
366 JsonToken token,
367 std::optional<MessageTemplate> errorMessage = std::nullopt);
368
369 inline Isolate* isolate() { return isolate_; }
370 inline Factory* factory() { return isolate_->factory(); }
375
376 static const int kInitialSpecialStringLength = 32;
377
378 static void UpdatePointersCallback(void* parser) {
379 reinterpret_cast<JsonParser<Char>*>(parser)->UpdatePointers();
380 }
381
384 const Char* chars = Cast<SeqString>(source_)->GetChars(no_gc);
385 if (chars_ != chars) {
386 size_t position = cursor_ - chars_;
387 size_t length = end_ - chars_;
388 chars_ = chars;
390 end_ = chars_ + length;
391 }
392 }
393
394 private:
395 static const bool kIsOneByte = sizeof(Char) == 1;
396
397 bool is_at_end() const {
399 return cursor_ == end_;
400 }
401
402 uint32_t position() const { return static_cast<uint32_t>(cursor_ - chars_); }
403
405 const uint64_t hash_seed_;
407 // Indicates whether the bytes underneath source_ can relocate during GC.
412 // The parsed value's source to be passed to the reviver, if the reviver is
413 // callable.
415
420
421 // Cached pointer to the raw chars in source. In case source is on-heap, we
422 // register an UpdatePointers callback. For this reason, chars_, cursor_ and
423 // end_ should never be locally cached across a possible allocation. The scope
424 // in which we cache chars has to be guarded by a DisallowGarbageCollection
425 // scope.
426 const Char* cursor_;
427 const Char* end_;
428 const Char* chars_;
429};
430
431// Explicit instantiation declarations.
432extern template class JsonParser<uint8_t>;
433extern template class JsonParser<uint16_t>;
434
435} // namespace internal
436} // namespace v8
437
438#endif // V8_JSON_JSON_PARSER_H_
SourcePosition pos
v8::internal::Factory * factory()
Definition isolate.h:1527
JsonParseInternalizer(Isolate *isolate, Handle< JSReceiver > reviver, Handle< String > source)
MaybeHandle< Object > InternalizeJsonProperty(DirectHandle< JSReceiver > holder, DirectHandle< String > key, Handle< Object > val_node, DirectHandle< Object > snapshot)
static MaybeHandle< Object > Internalize(Isolate *isolate, DirectHandle< Object > result, Handle< Object > reviver, Handle< String > source, MaybeHandle< Object > val_node)
bool RecurseAndApply(Handle< JSReceiver > holder, Handle< String > name, Handle< Object > val_node, Handle< Object > snapshot)
static const int kMaxContextCharacters
JsonString ScanJsonString(bool needs_internalization)
bool Check(JsonToken token)
MaybeHandle< Object > ParseJsonArray()
DirectHandle< JSFunction > object_constructor()
V8_INLINE JsonToken peek() const
Handle< String > MakeString(const JsonString &string, Handle< String > hint=Handle< String >())
void ExpectNext(JsonToken token, std::optional< MessageTemplate > errorMessage=std::nullopt)
SmallVector< Handle< Object > > element_stack_
static constexpr base::uc32 kEndOfString
MaybeHandle< Object > ParseJsonValue()
void Expect(JsonToken token, std::optional< MessageTemplate > errorMessage=std::nullopt)
MessageTemplate GetErrorMessageWithEllipses(DirectHandle< Object > &arg, DirectHandle< Object > &arg2, int pos)
static const int kInitialSpecialStringLength
void ReportUnexpectedToken(JsonToken token, std::optional< MessageTemplate > errorMessage=std::nullopt)
SmallVector< double > double_elements_
SmallVector< int > smi_elements_
MaybeHandle< Object > ParseJsonObject(Handle< Map > feedback)
JsonParser(Isolate *isolate, Handle< String > source)
void DecodeString(SinkChar *sink, uint32_t start, uint32_t length)
JsonString ScanJsonPropertyKey(JsonContinuation *cont)
static void UpdatePointersCallback(void *parser)
const Handle< String > original_source_
base::uc32 CurrentCharacter()
void ScanLiteral(const char(&s)[N])
Handle< JSObject > BuildJsonObject(const JsonContinuation &cont, DirectHandle< Map > feedback)
uint32_t position() const
Handle< String > source_
V8_INLINE MaybeHandle< Object > ParseJsonValueRecursive(Handle< Map > feedback={})
void CalculateFileLocation(DirectHandle< Object > &line, DirectHandle< Object > &column)
static V8_WARN_UNUSED_RESULT bool CheckRawJson(Isolate *isolate, Handle< String > source)
Handle< Object > ParseJsonNumber()
void Consume(JsonToken token)
ReadOnlyRoots roots()
base::uc32 ScanUnicodeCharacter()
static constexpr base::uc32 kInvalidUnicodeCharacter
MaybeHandle< Object > ParseJson(DirectHandle< Object > reviver)
void ReportUnexpectedCharacter(base::uc32 c)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Parse(Isolate *isolate, Handle< String > source, Handle< Object > reviver)
Handle< JSFunction > object_constructor_
bool ParseJsonNumberAsDoubleOrSmi(double *result_double, int *result_smi)
static const bool kIsOneByte
Handle< Object > BuildJsonArray(size_t start)
SmallVector< JsonProperty > property_stack_
base::Vector< const Char > GetKeyChars(JsonString key)
typename CharTraits< Char >::ExternalString SeqExternalString
static const int kMinOriginalSourceLengthForContext
MaybeHandle< Object > parsed_val_node_
const uint64_t hash_seed_
MessageTemplate LookUpErrorMessageForJsonToken(JsonToken token, DirectHandle< Object > &arg, DirectHandle< Object > &arg2, int pos)
typename CharTraits< Char >::String SeqString
uint32_t start() const
Definition json-parser.h:67
const uint32_t start_
Definition json-parser.h:86
const uint32_t index_
Definition json-parser.h:87
const uint32_t length_
Definition json-parser.h:89
uint32_t length() const
Definition json-parser.h:72
uint32_t index() const
Definition json-parser.h:77
bool needs_conversion() const
Definition json-parser.h:57
JsonString(uint32_t start, uint32_t length, bool needs_conversion, bool internalize, bool has_escape)
Definition json-parser.h:43
JsonString(uint32_t index)
Definition json-parser.h:35
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
int start
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
ZoneVector< RpoNumber > & result
uint32_t uc32
Definition strings.h:19
constexpr int N
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:509
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
JsonContinuation(Isolate *isolate, Type type, size_t index)
JsonProperty(const JsonString &string, Handle< Object > value)
Definition json-parser.h:99
JsonProperty(const JsonString &string)
Definition json-parser.h:98
#define V8_INLINE
Definition v8config.h:500
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_UNLIKELY(condition)
Definition v8config.h:660