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

Side by Side Diff: src/json-stringifier.h

Issue 2002933002: [json] move json parser and stringifier into own compilation units. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 4 years, 7 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 unified diff | Download patch
« no previous file with comments | « src/json-parser.cc ('k') | src/json-stringifier.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_JSON_STRINGIFIER_H_ 5 #ifndef V8_JSON_STRINGIFIER_H_
6 #define V8_JSON_STRINGIFIER_H_ 6 #define V8_JSON_STRINGIFIER_H_
7 7
8 #include "src/conversions.h" 8 #include "src/objects.h"
9 #include "src/lookup.h"
10 #include "src/messages.h"
11 #include "src/string-builder.h" 9 #include "src/string-builder.h"
12 #include "src/utils.h"
13 10
14 namespace v8 { 11 namespace v8 {
15 namespace internal { 12 namespace internal {
16 13
17 class BasicJsonStringifier BASE_EMBEDDED { 14 class BasicJsonStringifier BASE_EMBEDDED {
18 public: 15 public:
19 BasicJsonStringifier(Isolate* isolate, Handle<String> gap); 16 BasicJsonStringifier(Isolate* isolate, Handle<String> gap);
20 17
21 ~BasicJsonStringifier() { DeleteArray(gap_); } 18 ~BasicJsonStringifier() { DeleteArray(gap_); }
22 19
23 MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object); 20 MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object);
24 21
25 MUST_USE_RESULT INLINE(static MaybeHandle<Object> StringifyString( 22 MUST_USE_RESULT static MaybeHandle<Object> StringifyString(
26 Isolate* isolate, 23 Isolate* isolate, Handle<String> object);
27 Handle<String> object));
28 24
29 private: 25 private:
30 enum Result { UNCHANGED, SUCCESS, EXCEPTION }; 26 enum Result { UNCHANGED, SUCCESS, EXCEPTION };
31 27
32 MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction( 28 MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
33 Handle<Object> object, 29 Handle<Object> object,
34 Handle<Object> key); 30 Handle<Object> key);
35 31
36 // Entry point to serialize the object. 32 // Entry point to serialize the object.
37 INLINE(Result SerializeObject(Handle<Object> obj)) { 33 INLINE(Result SerializeObject(Handle<Object> obj)) {
(...skipping 16 matching lines...) Expand all
54 INLINE(Result SerializeProperty(Handle<Object> object, 50 INLINE(Result SerializeProperty(Handle<Object> object,
55 bool deferred_comma, 51 bool deferred_comma,
56 Handle<String> deferred_key)) { 52 Handle<String> deferred_key)) {
57 DCHECK(!deferred_key.is_null()); 53 DCHECK(!deferred_key.is_null());
58 return Serialize_<true>(object, deferred_comma, deferred_key); 54 return Serialize_<true>(object, deferred_comma, deferred_key);
59 } 55 }
60 56
61 template <bool deferred_string_key> 57 template <bool deferred_string_key>
62 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); 58 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
63 59
64 void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) { 60 INLINE(void SerializeDeferredKey(bool deferred_comma,
65 Separator(!deferred_comma); 61 Handle<Object> deferred_key));
66 SerializeString(Handle<String>::cast(deferred_key));
67 builder_.AppendCharacter(':');
68 if (gap_ != nullptr) builder_.AppendCharacter(' ');
69 }
70 62
71 Result SerializeSmi(Smi* object); 63 Result SerializeSmi(Smi* object);
72 64
73 Result SerializeDouble(double number); 65 Result SerializeDouble(double number);
74 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { 66 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
75 return SerializeDouble(object->value()); 67 return SerializeDouble(object->value());
76 } 68 }
77 69
78 Result SerializeJSValue(Handle<JSValue> object); 70 Result SerializeJSValue(Handle<JSValue> object);
79 71
(...skipping 14 matching lines...) Expand all
94 86
95 template <typename SrcChar, typename DestChar> 87 template <typename SrcChar, typename DestChar>
96 INLINE(void SerializeString_(Handle<String> string)); 88 INLINE(void SerializeString_(Handle<String> string));
97 89
98 template <typename Char> 90 template <typename Char>
99 INLINE(static bool DoNotEscape(Char c)); 91 INLINE(static bool DoNotEscape(Char c));
100 92
101 INLINE(void NewLine()); 93 INLINE(void NewLine());
102 INLINE(void Indent() { indent_++; }); 94 INLINE(void Indent() { indent_++; });
103 INLINE(void Unindent() { indent_--; }); 95 INLINE(void Unindent() { indent_--; });
104 INLINE(void Separator(bool first) { 96 INLINE(void Separator(bool first));
105 if (!first) builder_.AppendCharacter(',');
106 NewLine();
107 })
108 97
109 Result StackPush(Handle<Object> object); 98 Result StackPush(Handle<Object> object);
110 void StackPop(); 99 void StackPop();
111 100
112 Factory* factory() { return isolate_->factory(); } 101 Factory* factory() { return isolate_->factory(); }
113 102
114 Isolate* isolate_; 103 Isolate* isolate_;
115 IncrementalStringBuilder builder_; 104 IncrementalStringBuilder builder_;
116 Handle<String> tojson_string_; 105 Handle<String> tojson_string_;
117 Handle<JSArray> stack_; 106 Handle<JSArray> stack_;
118 Handle<String> gap_string_; 107 Handle<String> gap_string_;
119 uc16* gap_; 108 uc16* gap_;
120 int indent_; 109 int indent_;
121 110
122 static const int kJsonEscapeTableEntrySize = 8; 111 static const int kJsonEscapeTableEntrySize = 8;
123 static const char* const JsonEscapeTable; 112 static const char* const JsonEscapeTable;
124 }; 113 };
125 114
126
127 // Translation table to escape Latin1 characters.
128 // Table entries start at a multiple of 8 and are null-terminated.
129 const char* const BasicJsonStringifier::JsonEscapeTable =
130 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
131 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
132 "\\b\0 \\t\0 \\n\0 \\u000b\0 "
133 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
134 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
135 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
136 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
137 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
138 " \0 !\0 \\\"\0 #\0 "
139 "$\0 %\0 &\0 '\0 "
140 "(\0 )\0 *\0 +\0 "
141 ",\0 -\0 .\0 /\0 "
142 "0\0 1\0 2\0 3\0 "
143 "4\0 5\0 6\0 7\0 "
144 "8\0 9\0 :\0 ;\0 "
145 "<\0 =\0 >\0 ?\0 "
146 "@\0 A\0 B\0 C\0 "
147 "D\0 E\0 F\0 G\0 "
148 "H\0 I\0 J\0 K\0 "
149 "L\0 M\0 N\0 O\0 "
150 "P\0 Q\0 R\0 S\0 "
151 "T\0 U\0 V\0 W\0 "
152 "X\0 Y\0 Z\0 [\0 "
153 "\\\\\0 ]\0 ^\0 _\0 "
154 "`\0 a\0 b\0 c\0 "
155 "d\0 e\0 f\0 g\0 "
156 "h\0 i\0 j\0 k\0 "
157 "l\0 m\0 n\0 o\0 "
158 "p\0 q\0 r\0 s\0 "
159 "t\0 u\0 v\0 w\0 "
160 "x\0 y\0 z\0 {\0 "
161 "|\0 }\0 ~\0 \177\0 "
162 "\200\0 \201\0 \202\0 \203\0 "
163 "\204\0 \205\0 \206\0 \207\0 "
164 "\210\0 \211\0 \212\0 \213\0 "
165 "\214\0 \215\0 \216\0 \217\0 "
166 "\220\0 \221\0 \222\0 \223\0 "
167 "\224\0 \225\0 \226\0 \227\0 "
168 "\230\0 \231\0 \232\0 \233\0 "
169 "\234\0 \235\0 \236\0 \237\0 "
170 "\240\0 \241\0 \242\0 \243\0 "
171 "\244\0 \245\0 \246\0 \247\0 "
172 "\250\0 \251\0 \252\0 \253\0 "
173 "\254\0 \255\0 \256\0 \257\0 "
174 "\260\0 \261\0 \262\0 \263\0 "
175 "\264\0 \265\0 \266\0 \267\0 "
176 "\270\0 \271\0 \272\0 \273\0 "
177 "\274\0 \275\0 \276\0 \277\0 "
178 "\300\0 \301\0 \302\0 \303\0 "
179 "\304\0 \305\0 \306\0 \307\0 "
180 "\310\0 \311\0 \312\0 \313\0 "
181 "\314\0 \315\0 \316\0 \317\0 "
182 "\320\0 \321\0 \322\0 \323\0 "
183 "\324\0 \325\0 \326\0 \327\0 "
184 "\330\0 \331\0 \332\0 \333\0 "
185 "\334\0 \335\0 \336\0 \337\0 "
186 "\340\0 \341\0 \342\0 \343\0 "
187 "\344\0 \345\0 \346\0 \347\0 "
188 "\350\0 \351\0 \352\0 \353\0 "
189 "\354\0 \355\0 \356\0 \357\0 "
190 "\360\0 \361\0 \362\0 \363\0 "
191 "\364\0 \365\0 \366\0 \367\0 "
192 "\370\0 \371\0 \372\0 \373\0 "
193 "\374\0 \375\0 \376\0 \377\0 ";
194
195 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate, Handle<String> gap)
196 : isolate_(isolate), builder_(isolate), gap_string_(gap), indent_(0) {
197 tojson_string_ = factory()->toJSON_string();
198 stack_ = factory()->NewJSArray(8);
199 int gap_length = gap->length();
200 if (gap_length != 0) {
201 gap = String::Flatten(gap);
202 if (gap->IsTwoByteRepresentation()) builder_.ChangeEncoding();
203 DisallowHeapAllocation no_gc;
204 String::FlatContent flat = gap->GetFlatContent();
205 gap_ = NewArray<uc16>(gap_length + 1);
206 if (flat.IsOneByte()) {
207 CopyChars(gap_, flat.ToOneByteVector().start(), gap_length);
208 } else {
209 CopyChars(gap_, flat.ToUC16Vector().start(), gap_length);
210 }
211 gap_[gap_length] = '\0';
212 } else {
213 gap_ = nullptr;
214 }
215 }
216
217
218 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
219 Result result = SerializeObject(object);
220 if (result == UNCHANGED) return factory()->undefined_value();
221 if (result == SUCCESS) return builder_.Finish();
222 DCHECK(result == EXCEPTION);
223 return MaybeHandle<Object>();
224 }
225
226
227 MaybeHandle<Object> BasicJsonStringifier::StringifyString(
228 Isolate* isolate, Handle<String> object) {
229 static const int kJsonQuoteWorstCaseBlowup = 6;
230 static const int kSpaceForQuotes = 2;
231 int worst_case_length =
232 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
233
234 if (worst_case_length > 32 * KB) { // Slow path if too large.
235 BasicJsonStringifier stringifier(isolate,
236 isolate->factory()->empty_string());
237 return stringifier.Stringify(object);
238 }
239
240 object = String::Flatten(object);
241 DCHECK(object->IsFlat());
242 Handle<SeqString> result;
243 if (object->IsOneByteRepresentationUnderneath()) {
244 result = isolate->factory()
245 ->NewRawOneByteString(worst_case_length)
246 .ToHandleChecked();
247 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
248 result, worst_case_length);
249 no_extend.Append('\"');
250 SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
251 &no_extend);
252 no_extend.Append('\"');
253 return no_extend.Finalize();
254 } else {
255 result = isolate->factory()
256 ->NewRawTwoByteString(worst_case_length)
257 .ToHandleChecked();
258 IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
259 worst_case_length);
260 no_extend.Append('\"');
261 SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
262 &no_extend);
263 no_extend.Append('\"');
264 return no_extend.Finalize();
265 }
266 }
267
268
269 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
270 Handle<Object> object, Handle<Object> key) {
271 LookupIterator it(object, tojson_string_,
272 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
273 Handle<Object> fun;
274 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
275 if (!fun->IsCallable()) return object;
276
277 // Call toJSON function.
278 if (key->IsSmi()) key = factory()->NumberToString(key);
279 Handle<Object> argv[] = { key };
280 HandleScope scope(isolate_);
281 ASSIGN_RETURN_ON_EXCEPTION(
282 isolate_, object,
283 Execution::Call(isolate_, fun, object, 1, argv),
284 Object);
285 return scope.CloseAndEscape(object);
286 }
287
288
289 BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
290 Handle<Object> object) {
291 StackLimitCheck check(isolate_);
292 if (check.HasOverflowed()) {
293 isolate_->StackOverflow();
294 return EXCEPTION;
295 }
296
297 int length = Smi::cast(stack_->length())->value();
298 {
299 DisallowHeapAllocation no_allocation;
300 FixedArray* elements = FixedArray::cast(stack_->elements());
301 for (int i = 0; i < length; i++) {
302 if (elements->get(i) == *object) {
303 AllowHeapAllocation allow_to_return_error;
304 Handle<Object> error =
305 factory()->NewTypeError(MessageTemplate::kCircularStructure);
306 isolate_->Throw(*error);
307 return EXCEPTION;
308 }
309 }
310 }
311 JSArray::SetLength(stack_, length + 1);
312 FixedArray::cast(stack_->elements())->set(length, *object);
313 return SUCCESS;
314 }
315
316
317 void BasicJsonStringifier::StackPop() {
318 int length = Smi::cast(stack_->length())->value();
319 stack_->set_length(Smi::FromInt(length - 1));
320 }
321
322
323 template <bool deferred_string_key>
324 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
325 Handle<Object> object, bool comma, Handle<Object> key) {
326 if (object->IsJSReceiver()) {
327 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
328 isolate_, object,
329 ApplyToJsonFunction(object, key),
330 EXCEPTION);
331 }
332
333 if (object->IsSmi()) {
334 if (deferred_string_key) SerializeDeferredKey(comma, key);
335 return SerializeSmi(Smi::cast(*object));
336 }
337
338 switch (HeapObject::cast(*object)->map()->instance_type()) {
339 case HEAP_NUMBER_TYPE:
340 case MUTABLE_HEAP_NUMBER_TYPE:
341 if (deferred_string_key) SerializeDeferredKey(comma, key);
342 return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
343 case ODDBALL_TYPE:
344 switch (Oddball::cast(*object)->kind()) {
345 case Oddball::kFalse:
346 if (deferred_string_key) SerializeDeferredKey(comma, key);
347 builder_.AppendCString("false");
348 return SUCCESS;
349 case Oddball::kTrue:
350 if (deferred_string_key) SerializeDeferredKey(comma, key);
351 builder_.AppendCString("true");
352 return SUCCESS;
353 case Oddball::kNull:
354 if (deferred_string_key) SerializeDeferredKey(comma, key);
355 builder_.AppendCString("null");
356 return SUCCESS;
357 default:
358 return UNCHANGED;
359 }
360 case JS_ARRAY_TYPE:
361 if (deferred_string_key) SerializeDeferredKey(comma, key);
362 return SerializeJSArray(Handle<JSArray>::cast(object));
363 case JS_VALUE_TYPE:
364 if (deferred_string_key) SerializeDeferredKey(comma, key);
365 return SerializeJSValue(Handle<JSValue>::cast(object));
366 case SIMD128_VALUE_TYPE:
367 case SYMBOL_TYPE:
368 return UNCHANGED;
369 default:
370 if (object->IsString()) {
371 if (deferred_string_key) SerializeDeferredKey(comma, key);
372 SerializeString(Handle<String>::cast(object));
373 return SUCCESS;
374 } else {
375 DCHECK(object->IsJSReceiver());
376 if (object->IsCallable()) return UNCHANGED;
377 // Go to slow path for global proxy and objects requiring access checks.
378 if (deferred_string_key) SerializeDeferredKey(comma, key);
379 if (object->IsJSProxy()) {
380 return SerializeJSProxy(Handle<JSProxy>::cast(object));
381 }
382 return SerializeJSObject(Handle<JSObject>::cast(object));
383 }
384 }
385
386 UNREACHABLE();
387 return UNCHANGED;
388 }
389
390
391 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
392 Handle<JSValue> object) {
393 String* class_name = object->class_name();
394 if (class_name == isolate_->heap()->String_string()) {
395 Handle<Object> value;
396 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
397 isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
398 SerializeString(Handle<String>::cast(value));
399 } else if (class_name == isolate_->heap()->Number_string()) {
400 Handle<Object> value;
401 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
402 EXCEPTION);
403 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
404 SerializeHeapNumber(Handle<HeapNumber>::cast(value));
405 } else if (class_name == isolate_->heap()->Boolean_string()) {
406 Object* value = JSValue::cast(*object)->value();
407 DCHECK(value->IsBoolean());
408 builder_.AppendCString(value->IsTrue() ? "true" : "false");
409 } else {
410 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
411 return SerializeJSObject(object);
412 }
413 return SUCCESS;
414 }
415
416
417 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
418 static const int kBufferSize = 100;
419 char chars[kBufferSize];
420 Vector<char> buffer(chars, kBufferSize);
421 builder_.AppendCString(IntToCString(object->value(), buffer));
422 return SUCCESS;
423 }
424
425
426 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
427 double number) {
428 if (std::isinf(number) || std::isnan(number)) {
429 builder_.AppendCString("null");
430 return SUCCESS;
431 }
432 static const int kBufferSize = 100;
433 char chars[kBufferSize];
434 Vector<char> buffer(chars, kBufferSize);
435 builder_.AppendCString(DoubleToCString(number, buffer));
436 return SUCCESS;
437 }
438
439
440 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
441 Handle<JSArray> object) {
442 HandleScope handle_scope(isolate_);
443 Result stack_push = StackPush(object);
444 if (stack_push != SUCCESS) return stack_push;
445 uint32_t length = 0;
446 CHECK(object->length()->ToArrayLength(&length));
447 DCHECK(!object->IsAccessCheckNeeded());
448 builder_.AppendCharacter('[');
449 Indent();
450 switch (object->GetElementsKind()) {
451 case FAST_SMI_ELEMENTS: {
452 Handle<FixedArray> elements(FixedArray::cast(object->elements()),
453 isolate_);
454 for (uint32_t i = 0; i < length; i++) {
455 Separator(i == 0);
456 SerializeSmi(Smi::cast(elements->get(i)));
457 }
458 break;
459 }
460 case FAST_DOUBLE_ELEMENTS: {
461 // Empty array is FixedArray but not FixedDoubleArray.
462 if (length == 0) break;
463 Handle<FixedDoubleArray> elements(
464 FixedDoubleArray::cast(object->elements()), isolate_);
465 for (uint32_t i = 0; i < length; i++) {
466 Separator(i == 0);
467 SerializeDouble(elements->get_scalar(i));
468 }
469 break;
470 }
471 case FAST_ELEMENTS: {
472 Handle<Object> old_length(object->length(), isolate_);
473 for (uint32_t i = 0; i < length; i++) {
474 if (object->length() != *old_length ||
475 object->GetElementsKind() != FAST_ELEMENTS) {
476 Result result = SerializeArrayLikeSlow(object, i, length);
477 if (result != SUCCESS) return result;
478 break;
479 }
480 Separator(i == 0);
481 Result result = SerializeElement(
482 isolate_,
483 Handle<Object>(FixedArray::cast(object->elements())->get(i),
484 isolate_),
485 i);
486 if (result == SUCCESS) continue;
487 if (result == UNCHANGED) {
488 builder_.AppendCString("null");
489 } else {
490 return result;
491 }
492 }
493 break;
494 }
495 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
496 // the non-holey cases except that a lookup is necessary for holes.
497 default: {
498 Result result = SerializeArrayLikeSlow(object, 0, length);
499 if (result != SUCCESS) return result;
500 break;
501 }
502 }
503 Unindent();
504 if (length > 0) NewLine();
505 builder_.AppendCharacter(']');
506 StackPop();
507 return SUCCESS;
508 }
509
510 BasicJsonStringifier::Result BasicJsonStringifier::SerializeArrayLikeSlow(
511 Handle<JSReceiver> object, uint32_t start, uint32_t length) {
512 for (uint32_t i = start; i < length; i++) {
513 Separator(i == 0);
514 Handle<Object> element;
515 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
516 isolate_, element, JSReceiver::GetElement(isolate_, object, i),
517 EXCEPTION);
518 if (element->IsUndefined()) {
519 builder_.AppendCString("null");
520 } else {
521 Result result = SerializeElement(isolate_, element, i);
522 if (result == SUCCESS) continue;
523 if (result == UNCHANGED) {
524 builder_.AppendCString("null");
525 } else {
526 return result;
527 }
528 }
529 }
530 return SUCCESS;
531 }
532
533 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
534 Handle<JSObject> object) {
535 HandleScope handle_scope(isolate_);
536 Result stack_push = StackPush(object);
537 if (stack_push != SUCCESS) return stack_push;
538
539 if (object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
540 object->HasFastProperties() &&
541 Handle<JSObject>::cast(object)->elements()->length() == 0) {
542 DCHECK(object->IsJSObject());
543 DCHECK(!object->IsJSGlobalProxy());
544 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
545 DCHECK(!js_obj->HasIndexedInterceptor());
546 DCHECK(!js_obj->HasNamedInterceptor());
547 Handle<Map> map(js_obj->map());
548 builder_.AppendCharacter('{');
549 Indent();
550 bool comma = false;
551 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
552 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
553 // TODO(rossberg): Should this throw?
554 if (!name->IsString()) continue;
555 Handle<String> key = Handle<String>::cast(name);
556 PropertyDetails details = map->instance_descriptors()->GetDetails(i);
557 if (details.IsDontEnum()) continue;
558 Handle<Object> property;
559 if (details.type() == DATA && *map == js_obj->map()) {
560 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
561 if (js_obj->IsUnboxedDoubleField(field_index)) {
562 double value = js_obj->RawFastDoublePropertyAt(field_index);
563 property = isolate_->factory()->NewHeapNumber(value);
564 } else {
565 property = handle(js_obj->RawFastPropertyAt(field_index), isolate_);
566 }
567 } else {
568 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
569 isolate_, property, Object::GetPropertyOrElement(js_obj, key),
570 EXCEPTION);
571 }
572 Result result = SerializeProperty(property, comma, key);
573 if (!comma && result == SUCCESS) comma = true;
574 if (result == EXCEPTION) return result;
575 }
576 Unindent();
577 if (comma) NewLine();
578 builder_.AppendCharacter('}');
579 } else {
580 Result result = SerializeJSReceiverSlow(object);
581 if (result != SUCCESS) return result;
582 }
583 StackPop();
584 return SUCCESS;
585 }
586
587 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow(
588 Handle<JSReceiver> object) {
589 Handle<FixedArray> contents;
590 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
591 isolate_, contents,
592 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION);
593
594 builder_.AppendCharacter('{');
595 Indent();
596 bool comma = false;
597 for (int i = 0; i < contents->length(); i++) {
598 Object* key = contents->get(i);
599 Handle<String> key_handle;
600 MaybeHandle<Object> maybe_property;
601 if (key->IsString()) {
602 key_handle = Handle<String>(String::cast(key), isolate_);
603 maybe_property = Object::GetPropertyOrElement(object, key_handle);
604 } else {
605 DCHECK(key->IsNumber());
606 key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
607 if (key->IsSmi()) {
608 maybe_property =
609 JSReceiver::GetElement(isolate_, object, Smi::cast(key)->value());
610 } else {
611 maybe_property = Object::GetPropertyOrElement(object, key_handle);
612 }
613 }
614 Handle<Object> property;
615 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property, maybe_property,
616 EXCEPTION);
617 Result result = SerializeProperty(property, comma, key_handle);
618 if (!comma && result == SUCCESS) comma = true;
619 if (result == EXCEPTION) return result;
620 }
621 Unindent();
622 if (comma) NewLine();
623 builder_.AppendCharacter('}');
624 return SUCCESS;
625 }
626
627 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSProxy(
628 Handle<JSProxy> object) {
629 Result stack_push = StackPush(object);
630 if (stack_push != SUCCESS) return stack_push;
631 Maybe<bool> is_array = Object::IsArray(object);
632 if (is_array.IsNothing()) return EXCEPTION;
633 if (is_array.FromJust()) {
634 Handle<Object> length_object;
635 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
636 isolate_, length_object,
637 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION);
638 uint32_t length;
639 if (!length_object->ToUint32(&length)) {
640 // Technically, we need to be able to handle lengths outside the
641 // uint32_t range. However, we would run into string size overflow
642 // if we tried to stringify such an array.
643 isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
644 return EXCEPTION;
645 }
646 builder_.AppendCharacter('[');
647 Indent();
648 Result result = SerializeArrayLikeSlow(object, 0, length);
649 if (result != SUCCESS) return result;
650 Unindent();
651 if (length > 0) NewLine();
652 builder_.AppendCharacter(']');
653 } else {
654 Result result = SerializeJSReceiverSlow(object);
655 if (result != SUCCESS) return result;
656 }
657 StackPop();
658 return SUCCESS;
659 }
660
661
662 template <typename SrcChar, typename DestChar>
663 void BasicJsonStringifier::SerializeStringUnchecked_(
664 Vector<const SrcChar> src,
665 IncrementalStringBuilder::NoExtend<DestChar>* dest) {
666 // Assert that uc16 character is not truncated down to 8 bit.
667 // The <uc16, char> version of this method must not be called.
668 DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
669
670 for (int i = 0; i < src.length(); i++) {
671 SrcChar c = src[i];
672 if (DoNotEscape(c)) {
673 dest->Append(c);
674 } else {
675 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
676 }
677 }
678 }
679
680
681 template <typename SrcChar, typename DestChar>
682 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
683 int length = string->length();
684 builder_.Append<uint8_t, DestChar>('"');
685 // We make a rough estimate to find out if the current string can be
686 // serialized without allocating a new string part. The worst case length of
687 // an escaped character is 6. Shifting the remainin string length right by 3
688 // is a more pessimistic estimate, but faster to calculate.
689 int worst_case_length = length << 3;
690 if (builder_.CurrentPartCanFit(worst_case_length)) {
691 DisallowHeapAllocation no_gc;
692 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
693 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
694 &builder_, worst_case_length);
695 SerializeStringUnchecked_(vector, &no_extend);
696 } else {
697 FlatStringReader reader(isolate_, string);
698 for (int i = 0; i < reader.length(); i++) {
699 SrcChar c = reader.Get<SrcChar>(i);
700 if (DoNotEscape(c)) {
701 builder_.Append<SrcChar, DestChar>(c);
702 } else {
703 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
704 }
705 }
706 }
707
708 builder_.Append<uint8_t, DestChar>('"');
709 }
710
711
712 template <>
713 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
714 return c >= '#' && c <= '~' && c != '\\';
715 }
716
717
718 template <>
719 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
720 return c >= '#' && c != '\\' && c != 0x7f;
721 }
722
723 void BasicJsonStringifier::NewLine() {
724 if (gap_ == nullptr) return;
725 builder_.AppendCharacter('\n');
726 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
727 }
728
729 void BasicJsonStringifier::SerializeString(Handle<String> object) {
730 object = String::Flatten(object);
731 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
732 if (object->IsOneByteRepresentationUnderneath()) {
733 SerializeString_<uint8_t, uint8_t>(object);
734 } else {
735 builder_.ChangeEncoding();
736 SerializeString(object);
737 }
738 } else {
739 if (object->IsOneByteRepresentationUnderneath()) {
740 SerializeString_<uint8_t, uc16>(object);
741 } else {
742 SerializeString_<uc16, uc16>(object);
743 }
744 }
745 }
746
747 } // namespace internal 115 } // namespace internal
748 } // namespace v8 116 } // namespace v8
749 117
750 #endif // V8_JSON_STRINGIFIER_H_ 118 #endif // V8_JSON_STRINGIFIER_H_
OLDNEW
« no previous file with comments | « src/json-parser.cc ('k') | src/json-stringifier.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698