blob: 5c0459eb1b0aa11bfc6c6125bac53db27aa2cdae [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
3// found in the LICENSE file.
4
5#ifndef V8_JSON_STRINGIFIER_H_
6#define V8_JSON_STRINGIFIER_H_
7
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/conversions.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/lookup.h"
10#include "src/messages.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/string-builder.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/utils.h"
13
14namespace v8 {
15namespace internal {
16
17class BasicJsonStringifier BASE_EMBEDDED {
18 public:
19 explicit BasicJsonStringifier(Isolate* isolate);
20
21 MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object);
22
23 MUST_USE_RESULT INLINE(static MaybeHandle<Object> StringifyString(
24 Isolate* isolate,
25 Handle<String> object));
26
27 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 enum Result { UNCHANGED, SUCCESS, EXCEPTION };
29
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
31 Handle<Object> object,
32 Handle<Object> key);
33
34 Result SerializeGeneric(Handle<Object> object,
35 Handle<Object> key,
36 bool deferred_comma,
37 bool deferred_key);
38
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 // Entry point to serialize the object.
40 INLINE(Result SerializeObject(Handle<Object> obj)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040041 return Serialize_<false>(obj, false, factory()->empty_string());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 }
43
44 // Serialize an array element.
45 // The index may serve as argument for the toJSON function.
46 INLINE(Result SerializeElement(Isolate* isolate,
47 Handle<Object> object,
48 int i)) {
49 return Serialize_<false>(object,
50 false,
51 Handle<Object>(Smi::FromInt(i), isolate));
52 }
53
54 // Serialize a object property.
55 // The key may or may not be serialized depending on the property.
56 // The key may also serve as argument for the toJSON function.
57 INLINE(Result SerializeProperty(Handle<Object> object,
58 bool deferred_comma,
59 Handle<String> deferred_key)) {
60 DCHECK(!deferred_key.is_null());
61 return Serialize_<true>(object, deferred_comma, deferred_key);
62 }
63
64 template <bool deferred_string_key>
65 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
66
67 void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040068 if (deferred_comma) builder_.AppendCharacter(',');
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 SerializeString(Handle<String>::cast(deferred_key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040070 builder_.AppendCharacter(':');
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 }
72
73 Result SerializeSmi(Smi* object);
74
75 Result SerializeDouble(double number);
76 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
77 return SerializeDouble(object->value());
78 }
79
80 Result SerializeJSValue(Handle<JSValue> object);
81
82 INLINE(Result SerializeJSArray(Handle<JSArray> object));
83 INLINE(Result SerializeJSObject(Handle<JSObject> object));
84
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 Result SerializeJSArraySlow(Handle<JSArray> object, uint32_t start,
86 uint32_t length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087
88 void SerializeString(Handle<String> object);
89
90 template <typename SrcChar, typename DestChar>
Emily Bernierd0a1eb72015-03-24 16:35:39 -040091 INLINE(static void SerializeStringUnchecked_(
92 Vector<const SrcChar> src,
93 IncrementalStringBuilder::NoExtend<DestChar>* dest));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094
Emily Bernierd0a1eb72015-03-24 16:35:39 -040095 template <typename SrcChar, typename DestChar>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096 INLINE(void SerializeString_(Handle<String> string));
97
98 template <typename Char>
99 INLINE(static bool DoNotEscape(Char c));
100
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 Result StackPush(Handle<Object> object);
102 void StackPop();
103
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400104 Factory* factory() { return isolate_->factory(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105
106 Isolate* isolate_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400107 IncrementalStringBuilder builder_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 Handle<String> tojson_string_;
109 Handle<JSArray> stack_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110
111 static const int kJsonEscapeTableEntrySize = 8;
112 static const char* const JsonEscapeTable;
113};
114
115
116// Translation table to escape Latin1 characters.
117// Table entries start at a multiple of 8 and are null-terminated.
118const char* const BasicJsonStringifier::JsonEscapeTable =
119 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
120 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
121 "\\b\0 \\t\0 \\n\0 \\u000b\0 "
122 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
123 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
124 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
125 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
126 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
127 " \0 !\0 \\\"\0 #\0 "
128 "$\0 %\0 &\0 '\0 "
129 "(\0 )\0 *\0 +\0 "
130 ",\0 -\0 .\0 /\0 "
131 "0\0 1\0 2\0 3\0 "
132 "4\0 5\0 6\0 7\0 "
133 "8\0 9\0 :\0 ;\0 "
134 "<\0 =\0 >\0 ?\0 "
135 "@\0 A\0 B\0 C\0 "
136 "D\0 E\0 F\0 G\0 "
137 "H\0 I\0 J\0 K\0 "
138 "L\0 M\0 N\0 O\0 "
139 "P\0 Q\0 R\0 S\0 "
140 "T\0 U\0 V\0 W\0 "
141 "X\0 Y\0 Z\0 [\0 "
142 "\\\\\0 ]\0 ^\0 _\0 "
143 "`\0 a\0 b\0 c\0 "
144 "d\0 e\0 f\0 g\0 "
145 "h\0 i\0 j\0 k\0 "
146 "l\0 m\0 n\0 o\0 "
147 "p\0 q\0 r\0 s\0 "
148 "t\0 u\0 v\0 w\0 "
149 "x\0 y\0 z\0 {\0 "
150 "|\0 }\0 ~\0 \177\0 "
151 "\200\0 \201\0 \202\0 \203\0 "
152 "\204\0 \205\0 \206\0 \207\0 "
153 "\210\0 \211\0 \212\0 \213\0 "
154 "\214\0 \215\0 \216\0 \217\0 "
155 "\220\0 \221\0 \222\0 \223\0 "
156 "\224\0 \225\0 \226\0 \227\0 "
157 "\230\0 \231\0 \232\0 \233\0 "
158 "\234\0 \235\0 \236\0 \237\0 "
159 "\240\0 \241\0 \242\0 \243\0 "
160 "\244\0 \245\0 \246\0 \247\0 "
161 "\250\0 \251\0 \252\0 \253\0 "
162 "\254\0 \255\0 \256\0 \257\0 "
163 "\260\0 \261\0 \262\0 \263\0 "
164 "\264\0 \265\0 \266\0 \267\0 "
165 "\270\0 \271\0 \272\0 \273\0 "
166 "\274\0 \275\0 \276\0 \277\0 "
167 "\300\0 \301\0 \302\0 \303\0 "
168 "\304\0 \305\0 \306\0 \307\0 "
169 "\310\0 \311\0 \312\0 \313\0 "
170 "\314\0 \315\0 \316\0 \317\0 "
171 "\320\0 \321\0 \322\0 \323\0 "
172 "\324\0 \325\0 \326\0 \327\0 "
173 "\330\0 \331\0 \332\0 \333\0 "
174 "\334\0 \335\0 \336\0 \337\0 "
175 "\340\0 \341\0 \342\0 \343\0 "
176 "\344\0 \345\0 \346\0 \347\0 "
177 "\350\0 \351\0 \352\0 \353\0 "
178 "\354\0 \355\0 \356\0 \357\0 "
179 "\360\0 \361\0 \362\0 \363\0 "
180 "\364\0 \365\0 \366\0 \367\0 "
181 "\370\0 \371\0 \372\0 \373\0 "
182 "\374\0 \375\0 \376\0 \377\0 ";
183
184
185BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186 : isolate_(isolate), builder_(isolate) {
187 tojson_string_ = factory()->toJSON_string();
188 stack_ = factory()->NewJSArray(8);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189}
190
191
192MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
193 Result result = SerializeObject(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194 if (result == UNCHANGED) return factory()->undefined_value();
195 if (result == SUCCESS) return builder_.Finish();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 DCHECK(result == EXCEPTION);
197 return MaybeHandle<Object>();
198}
199
200
201MaybeHandle<Object> BasicJsonStringifier::StringifyString(
202 Isolate* isolate, Handle<String> object) {
203 static const int kJsonQuoteWorstCaseBlowup = 6;
204 static const int kSpaceForQuotes = 2;
205 int worst_case_length =
206 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
207
208 if (worst_case_length > 32 * KB) { // Slow path if too large.
209 BasicJsonStringifier stringifier(isolate);
210 return stringifier.Stringify(object);
211 }
212
213 object = String::Flatten(object);
214 DCHECK(object->IsFlat());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400215 Handle<SeqString> result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 if (object->IsOneByteRepresentationUnderneath()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 result = isolate->factory()
218 ->NewRawOneByteString(worst_case_length)
219 .ToHandleChecked();
220 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
221 result, worst_case_length);
222 no_extend.Append('\"');
223 SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
224 &no_extend);
225 no_extend.Append('\"');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226 return no_extend.Finalize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400228 result = isolate->factory()
229 ->NewRawTwoByteString(worst_case_length)
230 .ToHandleChecked();
231 IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
232 worst_case_length);
233 no_extend.Append('\"');
234 SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
235 &no_extend);
236 no_extend.Append('\"');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 return no_extend.Finalize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239}
240
241
242MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
243 Handle<Object> object, Handle<Object> key) {
244 LookupIterator it(object, tojson_string_,
245 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
246 Handle<Object> fun;
247 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
248 if (!fun->IsJSFunction()) return object;
249
250 // Call toJSON function.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400251 if (key->IsSmi()) key = factory()->NumberToString(key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 Handle<Object> argv[] = { key };
253 HandleScope scope(isolate_);
254 ASSIGN_RETURN_ON_EXCEPTION(
255 isolate_, object,
256 Execution::Call(isolate_, fun, object, 1, argv),
257 Object);
258 return scope.CloseAndEscape(object);
259}
260
261
262BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
263 Handle<Object> object) {
264 StackLimitCheck check(isolate_);
265 if (check.HasOverflowed()) {
266 isolate_->StackOverflow();
267 return EXCEPTION;
268 }
269
270 int length = Smi::cast(stack_->length())->value();
271 {
272 DisallowHeapAllocation no_allocation;
273 FixedArray* elements = FixedArray::cast(stack_->elements());
274 for (int i = 0; i < length; i++) {
275 if (elements->get(i) == *object) {
276 AllowHeapAllocation allow_to_return_error;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 Handle<Object> error =
278 factory()->NewTypeError(MessageTemplate::kCircularStructure);
279 isolate_->Throw(*error);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280 return EXCEPTION;
281 }
282 }
283 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 JSArray::SetLength(stack_, length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 FixedArray::cast(stack_->elements())->set(length, *object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 return SUCCESS;
287}
288
289
290void BasicJsonStringifier::StackPop() {
291 int length = Smi::cast(stack_->length())->value();
292 stack_->set_length(Smi::FromInt(length - 1));
293}
294
295
296template <bool deferred_string_key>
297BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
298 Handle<Object> object, bool comma, Handle<Object> key) {
299 if (object->IsJSObject()) {
300 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
301 isolate_, object,
302 ApplyToJsonFunction(object, key),
303 EXCEPTION);
304 }
305
306 if (object->IsSmi()) {
307 if (deferred_string_key) SerializeDeferredKey(comma, key);
308 return SerializeSmi(Smi::cast(*object));
309 }
310
311 switch (HeapObject::cast(*object)->map()->instance_type()) {
312 case HEAP_NUMBER_TYPE:
313 case MUTABLE_HEAP_NUMBER_TYPE:
314 if (deferred_string_key) SerializeDeferredKey(comma, key);
315 return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
316 case ODDBALL_TYPE:
317 switch (Oddball::cast(*object)->kind()) {
318 case Oddball::kFalse:
319 if (deferred_string_key) SerializeDeferredKey(comma, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400320 builder_.AppendCString("false");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 return SUCCESS;
322 case Oddball::kTrue:
323 if (deferred_string_key) SerializeDeferredKey(comma, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400324 builder_.AppendCString("true");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 return SUCCESS;
326 case Oddball::kNull:
327 if (deferred_string_key) SerializeDeferredKey(comma, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400328 builder_.AppendCString("null");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 return SUCCESS;
330 default:
331 return UNCHANGED;
332 }
333 case JS_ARRAY_TYPE:
334 if (object->IsAccessCheckNeeded()) break;
335 if (deferred_string_key) SerializeDeferredKey(comma, key);
336 return SerializeJSArray(Handle<JSArray>::cast(object));
337 case JS_VALUE_TYPE:
338 if (deferred_string_key) SerializeDeferredKey(comma, key);
339 return SerializeJSValue(Handle<JSValue>::cast(object));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 default:
341 if (object->IsString()) {
342 if (deferred_string_key) SerializeDeferredKey(comma, key);
343 SerializeString(Handle<String>::cast(object));
344 return SUCCESS;
345 } else if (object->IsJSObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 if (object->IsCallable()) return UNCHANGED;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347 // Go to slow path for global proxy and objects requiring access checks.
348 if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break;
349 if (deferred_string_key) SerializeDeferredKey(comma, key);
350 return SerializeJSObject(Handle<JSObject>::cast(object));
351 }
352 }
353
354 return SerializeGeneric(object, key, comma, deferred_string_key);
355}
356
357
358BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
359 Handle<Object> object,
360 Handle<Object> key,
361 bool deferred_comma,
362 bool deferred_key) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363 Handle<JSFunction> fun = isolate_->json_serialize_adapter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364 Handle<Object> argv[] = { key, object };
365 Handle<Object> result;
366 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 isolate_, result, Execution::Call(isolate_, fun, object, 2, argv),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368 EXCEPTION);
369 if (result->IsUndefined()) return UNCHANGED;
370 if (deferred_key) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 if (key->IsSmi()) key = factory()->NumberToString(key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 SerializeDeferredKey(deferred_comma, key);
373 }
374
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375 builder_.AppendString(Handle<String>::cast(result));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 return SUCCESS;
377}
378
379
380BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
381 Handle<JSValue> object) {
382 String* class_name = object->class_name();
383 if (class_name == isolate_->heap()->String_string()) {
384 Handle<Object> value;
385 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 SerializeString(Handle<String>::cast(value));
388 } else if (class_name == isolate_->heap()->Number_string()) {
389 Handle<Object> value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
391 EXCEPTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
393 SerializeHeapNumber(Handle<HeapNumber>::cast(value));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 } else if (class_name == isolate_->heap()->Boolean_string()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000395 Object* value = JSValue::cast(*object)->value();
396 DCHECK(value->IsBoolean());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400397 builder_.AppendCString(value->IsTrue() ? "true" : "false");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000398 } else {
399 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
400 CHECK(!object->IsAccessCheckNeeded());
401 CHECK(!object->IsJSGlobalProxy());
402 return SerializeJSObject(object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000403 }
404 return SUCCESS;
405}
406
407
408BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
409 static const int kBufferSize = 100;
410 char chars[kBufferSize];
411 Vector<char> buffer(chars, kBufferSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412 builder_.AppendCString(IntToCString(object->value(), buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 return SUCCESS;
414}
415
416
417BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
418 double number) {
419 if (std::isinf(number) || std::isnan(number)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400420 builder_.AppendCString("null");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 return SUCCESS;
422 }
423 static const int kBufferSize = 100;
424 char chars[kBufferSize];
425 Vector<char> buffer(chars, kBufferSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426 builder_.AppendCString(DoubleToCString(number, buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 return SUCCESS;
428}
429
430
431BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
432 Handle<JSArray> object) {
433 HandleScope handle_scope(isolate_);
434 Result stack_push = StackPush(object);
435 if (stack_push != SUCCESS) return stack_push;
436 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 CHECK(object->length()->ToArrayLength(&length));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400438 builder_.AppendCharacter('[');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 switch (object->GetElementsKind()) {
440 case FAST_SMI_ELEMENTS: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 Handle<FixedArray> elements(FixedArray::cast(object->elements()),
442 isolate_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443 for (uint32_t i = 0; i < length; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400444 if (i > 0) builder_.AppendCharacter(',');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445 SerializeSmi(Smi::cast(elements->get(i)));
446 }
447 break;
448 }
449 case FAST_DOUBLE_ELEMENTS: {
450 // Empty array is FixedArray but not FixedDoubleArray.
451 if (length == 0) break;
452 Handle<FixedDoubleArray> elements(
453 FixedDoubleArray::cast(object->elements()), isolate_);
454 for (uint32_t i = 0; i < length; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400455 if (i > 0) builder_.AppendCharacter(',');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000456 SerializeDouble(elements->get_scalar(i));
457 }
458 break;
459 }
460 case FAST_ELEMENTS: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 Handle<Object> old_length(object->length(), isolate_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 for (uint32_t i = 0; i < length; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463 if (object->length() != *old_length ||
464 object->GetElementsKind() != FAST_ELEMENTS) {
465 Result result = SerializeJSArraySlow(object, i, length);
466 if (result != SUCCESS) return result;
467 break;
468 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400469 if (i > 0) builder_.AppendCharacter(',');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 Result result = SerializeElement(
471 isolate_,
472 Handle<Object>(FixedArray::cast(object->elements())->get(i),
473 isolate_),
474 i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 if (result == SUCCESS) continue;
476 if (result == UNCHANGED) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400477 builder_.AppendCString("null");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 } else {
479 return result;
480 }
481 }
482 break;
483 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
485 // the non-holey cases except that a lookup is necessary for holes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 default: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 Result result = SerializeJSArraySlow(object, 0, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488 if (result != SUCCESS) return result;
489 break;
490 }
491 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400492 builder_.AppendCharacter(']');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000493 StackPop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 return SUCCESS;
495}
496
497
498BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 Handle<JSArray> object, uint32_t start, uint32_t length) {
500 for (uint32_t i = start; i < length; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400501 if (i > 0) builder_.AppendCharacter(',');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 Handle<Object> element;
503 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
504 isolate_, element,
505 Object::GetElement(isolate_, object, i),
506 EXCEPTION);
507 if (element->IsUndefined()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508 builder_.AppendCString("null");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509 } else {
510 Result result = SerializeElement(isolate_, element, i);
511 if (result == SUCCESS) continue;
512 if (result == UNCHANGED) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400513 builder_.AppendCString("null");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 } else {
515 return result;
516 }
517 }
518 }
519 return SUCCESS;
520}
521
522
523BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
524 Handle<JSObject> object) {
525 HandleScope handle_scope(isolate_);
526 Result stack_push = StackPush(object);
527 if (stack_push != SUCCESS) return stack_push;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 DCHECK(!object->IsJSGlobalProxy() && !object->IsJSGlobalObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400530 builder_.AppendCharacter('{');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 bool comma = false;
532
533 if (object->HasFastProperties() &&
534 !object->HasIndexedInterceptor() &&
535 !object->HasNamedInterceptor() &&
536 object->elements()->length() == 0) {
537 Handle<Map> map(object->map());
538 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
539 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
540 // TODO(rossberg): Should this throw?
541 if (!name->IsString()) continue;
542 Handle<String> key = Handle<String>::cast(name);
543 PropertyDetails details = map->instance_descriptors()->GetDetails(i);
544 if (details.IsDontEnum()) continue;
545 Handle<Object> property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 if (details.type() == DATA && *map == object->map()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400547 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
548 Isolate* isolate = object->GetIsolate();
549 if (object->IsUnboxedDoubleField(field_index)) {
550 double value = object->RawFastDoublePropertyAt(field_index);
551 property = isolate->factory()->NewHeapNumber(value);
552
553 } else {
554 property = handle(object->RawFastPropertyAt(field_index), isolate);
555 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 } else {
557 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
558 isolate_, property,
559 Object::GetPropertyOrElement(object, key),
560 EXCEPTION);
561 }
562 Result result = SerializeProperty(property, comma, key);
563 if (!comma && result == SUCCESS) comma = true;
564 if (result == EXCEPTION) return result;
565 }
566 } else {
567 Handle<FixedArray> contents;
568 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
569 isolate_, contents,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570 JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY, ENUMERABLE_STRINGS),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571 EXCEPTION);
572
573 for (int i = 0; i < contents->length(); i++) {
574 Object* key = contents->get(i);
575 Handle<String> key_handle;
576 MaybeHandle<Object> maybe_property;
577 if (key->IsString()) {
578 key_handle = Handle<String>(String::cast(key), isolate_);
579 maybe_property = Object::GetPropertyOrElement(object, key_handle);
580 } else {
581 DCHECK(key->IsNumber());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400582 key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 if (key->IsSmi()) {
584 maybe_property = Object::GetElement(
585 isolate_, object, Smi::cast(key)->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 } else {
587 maybe_property = Object::GetPropertyOrElement(object, key_handle);
588 }
589 }
590 Handle<Object> property;
591 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
592 isolate_, property, maybe_property, EXCEPTION);
593 Result result = SerializeProperty(property, comma, key_handle);
594 if (!comma && result == SUCCESS) comma = true;
595 if (result == EXCEPTION) return result;
596 }
597 }
598
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400599 builder_.AppendCharacter('}');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 StackPop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 return SUCCESS;
602}
603
604
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400605template <typename SrcChar, typename DestChar>
606void BasicJsonStringifier::SerializeStringUnchecked_(
607 Vector<const SrcChar> src,
608 IncrementalStringBuilder::NoExtend<DestChar>* dest) {
609 // Assert that uc16 character is not truncated down to 8 bit.
610 // The <uc16, char> version of this method must not be called.
611 DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400613 for (int i = 0; i < src.length(); i++) {
614 SrcChar c = src[i];
615 if (DoNotEscape(c)) {
616 dest->Append(c);
617 } else {
618 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
619 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 }
621}
622
623
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624template <typename SrcChar, typename DestChar>
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625void BasicJsonStringifier::SerializeString_(Handle<String> string) {
626 int length = string->length();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400627 builder_.Append<uint8_t, DestChar>('"');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628 // We make a rough estimate to find out if the current string can be
629 // serialized without allocating a new string part. The worst case length of
630 // an escaped character is 6. Shifting the remainin string length right by 3
631 // is a more pessimistic estimate, but faster to calculate.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400632 int worst_case_length = length << 3;
633 if (builder_.CurrentPartCanFit(worst_case_length)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 DisallowHeapAllocation no_gc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400635 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
636 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
637 &builder_, worst_case_length);
638 SerializeStringUnchecked_(vector, &no_extend);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400640 FlatStringReader reader(isolate_, string);
641 for (int i = 0; i < reader.length(); i++) {
642 SrcChar c = reader.Get<SrcChar>(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643 if (DoNotEscape(c)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400644 builder_.Append<SrcChar, DestChar>(c);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000645 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647 }
648 }
649 }
650
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400651 builder_.Append<uint8_t, DestChar>('"');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652}
653
654
655template <>
656bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
657 return c >= '#' && c <= '~' && c != '\\';
658}
659
660
661template <>
662bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
663 return c >= '#' && c != '\\' && c != 0x7f;
664}
665
666
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667void BasicJsonStringifier::SerializeString(Handle<String> object) {
668 object = String::Flatten(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400669 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000670 if (object->IsOneByteRepresentationUnderneath()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400671 SerializeString_<uint8_t, uint8_t>(object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400673 builder_.ChangeEncoding();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 SerializeString(object);
675 }
676 } else {
677 if (object->IsOneByteRepresentationUnderneath()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400678 SerializeString_<uint8_t, uc16>(object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400680 SerializeString_<uc16, uc16>(object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 }
682 }
683}
684
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685} // namespace internal
686} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000687
688#endif // V8_JSON_STRINGIFIER_H_