1 // Copyright 2016 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 #include "src/json-stringifier.h" 6 7 #include "src/conversions.h" 8 #include "src/heap/heap-inl.h" 9 #include "src/lookup.h" 10 #include "src/messages.h" 11 #include "src/objects-inl.h" 12 #include "src/objects/js-array-inl.h" 13 #include "src/string-builder-inl.h" 14 #include "src/utils.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class JsonStringifier BASE_EMBEDDED { 20 public: 21 explicit JsonStringifier(Isolate* isolate); 22 23 ~JsonStringifier() { DeleteArray(gap_); } 24 25 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Stringify(Handle<Object> object, 26 Handle<Object> replacer, 27 Handle<Object> gap); 28 29 private: 30 enum Result { UNCHANGED, SUCCESS, EXCEPTION }; 31 32 bool InitializeReplacer(Handle<Object> replacer); 33 bool InitializeGap(Handle<Object> gap); 34 35 V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyToJsonFunction( 36 Handle<Object> object, Handle<Object> key); 37 V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyReplacerFunction( 38 Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder); 39 40 // Entry point to serialize the object. 41 V8_INLINE Result SerializeObject(Handle<Object> obj) { 42 return Serialize_<false>(obj, false, factory()->empty_string()); 43 } 44 45 // Serialize an array element. 46 // The index may serve as argument for the toJSON function. 47 V8_INLINE Result SerializeElement(Isolate* isolate, Handle<Object> object, 48 int i) { 49 return Serialize_<false>(object, false, 50 Handle<Object>(Smi::FromInt(i), isolate)); 51 } 52 53 // Serialize a object property. 54 // The key may or may not be serialized depending on the property. 55 // The key may also serve as argument for the toJSON function. 56 V8_INLINE Result SerializeProperty(Handle<Object> object, bool deferred_comma, 57 Handle<String> deferred_key) { 58 DCHECK(!deferred_key.is_null()); 59 return Serialize_<true>(object, deferred_comma, deferred_key); 60 } 61 62 template <bool deferred_string_key> 63 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); 64 65 V8_INLINE void SerializeDeferredKey(bool deferred_comma, 66 Handle<Object> deferred_key); 67 68 Result SerializeSmi(Smi* object); 69 70 Result SerializeDouble(double number); 71 V8_INLINE Result SerializeHeapNumber(Handle<HeapNumber> object) { 72 return SerializeDouble(object->value()); 73 } 74 75 Result SerializeJSValue(Handle<JSValue> object); 76 77 V8_INLINE Result SerializeJSArray(Handle<JSArray> object); 78 V8_INLINE Result SerializeJSObject(Handle<JSObject> object); 79 80 Result SerializeJSProxy(Handle<JSProxy> object); 81 Result SerializeJSReceiverSlow(Handle<JSReceiver> object); 82 Result SerializeArrayLikeSlow(Handle<JSReceiver> object, uint32_t start, 83 uint32_t length); 84 85 void SerializeString(Handle<String> object); 86 87 template <typename SrcChar, typename DestChar> 88 V8_INLINE static void SerializeStringUnchecked_( 89 Vector<const SrcChar> src, 90 IncrementalStringBuilder::NoExtend<DestChar>* dest); 91 92 template <typename SrcChar, typename DestChar> 93 V8_INLINE void SerializeString_(Handle<String> string); 94 95 template <typename Char> 96 V8_INLINE static bool DoNotEscape(Char c); 97 98 V8_INLINE void NewLine(); 99 V8_INLINE void Indent() { indent_++; } 100 V8_INLINE void Unindent() { indent_--; } 101 V8_INLINE void Separator(bool first); 102 103 Handle<JSReceiver> CurrentHolder(Handle<Object> value, 104 Handle<Object> inital_holder); 105 106 Result StackPush(Handle<Object> object); 107 void StackPop(); 108 109 Factory* factory() { return isolate_->factory(); } 110 111 Isolate* isolate_; 112 IncrementalStringBuilder builder_; 113 Handle<String> tojson_string_; 114 Handle<JSArray> stack_; 115 Handle<FixedArray> property_list_; 116 Handle<JSReceiver> replacer_function_; 117 uc16* gap_; 118 int indent_; 119 120 static const int kJsonEscapeTableEntrySize = 8; 121 static const char* const JsonEscapeTable; 122 }; 123 124 MaybeHandle<Object> JsonStringify(Isolate* isolate, Handle<Object> object, 125 Handle<Object> replacer, Handle<Object> gap) { 126 JsonStringifier stringifier(isolate); 127 return stringifier.Stringify(object, replacer, gap); 128 } 129 130 // Translation table to escape Latin1 characters. 131 // Table entries start at a multiple of 8 and are null-terminated. 132 const char* const JsonStringifier::JsonEscapeTable = 133 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " 134 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " 135 "\\b\0 \\t\0 \\n\0 \\u000b\0 " 136 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " 137 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " 138 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " 139 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " 140 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " 141 " \0 !\0 \\\"\0 #\0 " 142 "$\0 %\0 &\0 '\0 " 143 "(\0 )\0 *\0 +\0 " 144 ",\0 -\0 .\0 /\0 " 145 "0\0 1\0 2\0 3\0 " 146 "4\0 5\0 6\0 7\0 " 147 "8\0 9\0 :\0 ;\0 " 148 "<\0 =\0 >\0 ?\0 " 149 "@\0 A\0 B\0 C\0 " 150 "D\0 E\0 F\0 G\0 " 151 "H\0 I\0 J\0 K\0 " 152 "L\0 M\0 N\0 O\0 " 153 "P\0 Q\0 R\0 S\0 " 154 "T\0 U\0 V\0 W\0 " 155 "X\0 Y\0 Z\0 [\0 " 156 "\\\\\0 ]\0 ^\0 _\0 " 157 "`\0 a\0 b\0 c\0 " 158 "d\0 e\0 f\0 g\0 " 159 "h\0 i\0 j\0 k\0 " 160 "l\0 m\0 n\0 o\0 " 161 "p\0 q\0 r\0 s\0 " 162 "t\0 u\0 v\0 w\0 " 163 "x\0 y\0 z\0 {\0 " 164 "|\0 }\0 ~\0 \x7F\0 " 165 "\x80\0 \x81\0 \x82\0 \x83\0 " 166 "\x84\0 \x85\0 \x86\0 \x87\0 " 167 "\x88\0 \x89\0 \x8A\0 \x8B\0 " 168 "\x8C\0 \x8D\0 \x8E\0 \x8F\0 " 169 "\x90\0 \x91\0 \x92\0 \x93\0 " 170 "\x94\0 \x95\0 \x96\0 \x97\0 " 171 "\x98\0 \x99\0 \x9A\0 \x9B\0 " 172 "\x9C\0 \x9D\0 \x9E\0 \x9F\0 " 173 "\xA0\0 \xA1\0 \xA2\0 \xA3\0 " 174 "\xA4\0 \xA5\0 \xA6\0 \xA7\0 " 175 "\xA8\0 \xA9\0 \xAA\0 \xAB\0 " 176 "\xAC\0 \xAD\0 \xAE\0 \xAF\0 " 177 "\xB0\0 \xB1\0 \xB2\0 \xB3\0 " 178 "\xB4\0 \xB5\0 \xB6\0 \xB7\0 " 179 "\xB8\0 \xB9\0 \xBA\0 \xBB\0 " 180 "\xBC\0 \xBD\0 \xBE\0 \xBF\0 " 181 "\xC0\0 \xC1\0 \xC2\0 \xC3\0 " 182 "\xC4\0 \xC5\0 \xC6\0 \xC7\0 " 183 "\xC8\0 \xC9\0 \xCA\0 \xCB\0 " 184 "\xCC\0 \xCD\0 \xCE\0 \xCF\0 " 185 "\xD0\0 \xD1\0 \xD2\0 \xD3\0 " 186 "\xD4\0 \xD5\0 \xD6\0 \xD7\0 " 187 "\xD8\0 \xD9\0 \xDA\0 \xDB\0 " 188 "\xDC\0 \xDD\0 \xDE\0 \xDF\0 " 189 "\xE0\0 \xE1\0 \xE2\0 \xE3\0 " 190 "\xE4\0 \xE5\0 \xE6\0 \xE7\0 " 191 "\xE8\0 \xE9\0 \xEA\0 \xEB\0 " 192 "\xEC\0 \xED\0 \xEE\0 \xEF\0 " 193 "\xF0\0 \xF1\0 \xF2\0 \xF3\0 " 194 "\xF4\0 \xF5\0 \xF6\0 \xF7\0 " 195 "\xF8\0 \xF9\0 \xFA\0 \xFB\0 " 196 "\xFC\0 \xFD\0 \xFE\0 \xFF\0 "; 197 198 JsonStringifier::JsonStringifier(Isolate* isolate) 199 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { 200 tojson_string_ = factory()->toJSON_string(); 201 stack_ = factory()->NewJSArray(8); 202 } 203 204 MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object, 205 Handle<Object> replacer, 206 Handle<Object> gap) { 207 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); 208 if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) { 209 return MaybeHandle<Object>(); 210 } 211 Result result = SerializeObject(object); 212 if (result == UNCHANGED) return factory()->undefined_value(); 213 if (result == SUCCESS) return builder_.Finish(); 214 DCHECK(result == EXCEPTION); 215 return MaybeHandle<Object>(); 216 } 217 218 bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) { 219 DCHECK(property_list_.is_null()); 220 DCHECK(replacer_function_.is_null()); 221 Maybe<bool> is_array = Object::IsArray(replacer); 222 if (is_array.IsNothing()) return false; 223 if (is_array.FromJust()) { 224 HandleScope handle_scope(isolate_); 225 Handle<OrderedHashSet> set = factory()->NewOrderedHashSet(); 226 Handle<Object> length_obj; 227 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 228 isolate_, length_obj, 229 Object::GetLengthFromArrayLike(isolate_, 230 Handle<JSReceiver>::cast(replacer)), 231 false); 232 uint32_t length; 233 if (!length_obj->ToUint32(&length)) length = kMaxUInt32; 234 for (uint32_t i = 0; i < length; i++) { 235 Handle<Object> element; 236 Handle<String> key; 237 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 238 isolate_, element, Object::GetElement(isolate_, replacer, i), false); 239 if (element->IsNumber() || element->IsString()) { 240 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 241 isolate_, key, Object::ToString(isolate_, element), false); 242 } else if (element->IsJSValue()) { 243 Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_); 244 if (value->IsNumber() || value->IsString()) { 245 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 246 isolate_, key, Object::ToString(isolate_, element), false); 247 } 248 } 249 if (key.is_null()) continue; 250 // Object keys are internalized, so do it here. 251 key = factory()->InternalizeString(key); 252 set = OrderedHashSet::Add(isolate_, set, key); 253 } 254 property_list_ = OrderedHashSet::ConvertToKeysArray( 255 isolate_, set, GetKeysConversion::kKeepNumbers); 256 property_list_ = handle_scope.CloseAndEscape(property_list_); 257 } else if (replacer->IsCallable()) { 258 replacer_function_ = Handle<JSReceiver>::cast(replacer); 259 } 260 return true; 261 } 262 263 bool JsonStringifier::InitializeGap(Handle<Object> gap) { 264 DCHECK_NULL(gap_); 265 HandleScope scope(isolate_); 266 if (gap->IsJSValue()) { 267 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); 268 if (value->IsString()) { 269 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, 270 Object::ToString(isolate_, gap), false); 271 } else if (value->IsNumber()) { 272 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, 273 Object::ToNumber(isolate_, gap), false); 274 } 275 } 276 277 if (gap->IsString()) { 278 Handle<String> gap_string = Handle<String>::cast(gap); 279 if (gap_string->length() > 0) { 280 int gap_length = std::min(gap_string->length(), 10); 281 gap_ = NewArray<uc16>(gap_length + 1); 282 String::WriteToFlat(*gap_string, gap_, 0, gap_length); 283 for (int i = 0; i < gap_length; i++) { 284 if (gap_[i] > String::kMaxOneByteCharCode) { 285 builder_.ChangeEncoding(); 286 break; 287 } 288 } 289 gap_[gap_length] = '\0'; 290 } 291 } else if (gap->IsNumber()) { 292 int num_value = DoubleToInt32(gap->Number()); 293 if (num_value > 0) { 294 int gap_length = std::min(num_value, 10); 295 gap_ = NewArray<uc16>(gap_length + 1); 296 for (int i = 0; i < gap_length; i++) gap_[i] = ' '; 297 gap_[gap_length] = '\0'; 298 } 299 } 300 return true; 301 } 302 303 MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object, 304 Handle<Object> key) { 305 HandleScope scope(isolate_); 306 307 Handle<Object> object_for_lookup = object; 308 if (object->IsBigInt()) { 309 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object_for_lookup, 310 Object::ToObject(isolate_, object), Object); 311 } 312 DCHECK(object_for_lookup->IsJSReceiver()); 313 314 // Retrieve toJSON function. 315 Handle<Object> fun; 316 { 317 LookupIterator it(isolate_, object_for_lookup, tojson_string_, 318 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 319 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); 320 if (!fun->IsCallable()) return object; 321 } 322 323 // Call toJSON function. 324 if (key->IsSmi()) key = factory()->NumberToString(key); 325 Handle<Object> argv[] = {key}; 326 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object, 327 Execution::Call(isolate_, fun, object, 1, argv), 328 Object); 329 return scope.CloseAndEscape(object); 330 } 331 332 MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction( 333 Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) { 334 HandleScope scope(isolate_); 335 if (key->IsSmi()) key = factory()->NumberToString(key); 336 Handle<Object> argv[] = {key, value}; 337 Handle<JSReceiver> holder = CurrentHolder(value, initial_holder); 338 ASSIGN_RETURN_ON_EXCEPTION( 339 isolate_, value, 340 Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object); 341 return scope.CloseAndEscape(value); 342 } 343 344 Handle<JSReceiver> JsonStringifier::CurrentHolder( 345 Handle<Object> value, Handle<Object> initial_holder) { 346 int length = Smi::ToInt(stack_->length()); 347 if (length == 0) { 348 Handle<JSObject> holder = 349 factory()->NewJSObject(isolate_->object_function()); 350 JSObject::AddProperty(isolate_, holder, factory()->empty_string(), 351 initial_holder, NONE); 352 return holder; 353 } else { 354 FixedArray* elements = FixedArray::cast(stack_->elements()); 355 return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)), 356 isolate_); 357 } 358 } 359 360 JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) { 361 StackLimitCheck check(isolate_); 362 if (check.HasOverflowed()) { 363 isolate_->StackOverflow(); 364 return EXCEPTION; 365 } 366 367 int length = Smi::ToInt(stack_->length()); 368 { 369 DisallowHeapAllocation no_allocation; 370 FixedArray* elements = FixedArray::cast(stack_->elements()); 371 for (int i = 0; i < length; i++) { 372 if (elements->get(i) == *object) { 373 AllowHeapAllocation allow_to_return_error; 374 Handle<Object> error = 375 factory()->NewTypeError(MessageTemplate::kCircularStructure); 376 isolate_->Throw(*error); 377 return EXCEPTION; 378 } 379 } 380 } 381 JSArray::SetLength(stack_, length + 1); 382 FixedArray::cast(stack_->elements())->set(length, *object); 383 return SUCCESS; 384 } 385 386 void JsonStringifier::StackPop() { 387 int length = Smi::ToInt(stack_->length()); 388 stack_->set_length(Smi::FromInt(length - 1)); 389 } 390 391 template <bool deferred_string_key> 392 JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object, 393 bool comma, 394 Handle<Object> key) { 395 StackLimitCheck interrupt_check(isolate_); 396 Handle<Object> initial_value = object; 397 if (interrupt_check.InterruptRequested() && 398 isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) { 399 return EXCEPTION; 400 } 401 if (object->IsJSReceiver() || object->IsBigInt()) { 402 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 403 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION); 404 } 405 if (!replacer_function_.is_null()) { 406 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 407 isolate_, object, ApplyReplacerFunction(object, key, initial_value), 408 EXCEPTION); 409 } 410 411 if (object->IsSmi()) { 412 if (deferred_string_key) SerializeDeferredKey(comma, key); 413 return SerializeSmi(Smi::cast(*object)); 414 } 415 416 switch (HeapObject::cast(*object)->map()->instance_type()) { 417 case HEAP_NUMBER_TYPE: 418 case MUTABLE_HEAP_NUMBER_TYPE: 419 if (deferred_string_key) SerializeDeferredKey(comma, key); 420 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); 421 case BIGINT_TYPE: 422 isolate_->Throw( 423 *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON)); 424 return EXCEPTION; 425 case ODDBALL_TYPE: 426 switch (Oddball::cast(*object)->kind()) { 427 case Oddball::kFalse: 428 if (deferred_string_key) SerializeDeferredKey(comma, key); 429 builder_.AppendCString("false"); 430 return SUCCESS; 431 case Oddball::kTrue: 432 if (deferred_string_key) SerializeDeferredKey(comma, key); 433 builder_.AppendCString("true"); 434 return SUCCESS; 435 case Oddball::kNull: 436 if (deferred_string_key) SerializeDeferredKey(comma, key); 437 builder_.AppendCString("null"); 438 return SUCCESS; 439 default: 440 return UNCHANGED; 441 } 442 case JS_ARRAY_TYPE: 443 if (deferred_string_key) SerializeDeferredKey(comma, key); 444 return SerializeJSArray(Handle<JSArray>::cast(object)); 445 case JS_VALUE_TYPE: 446 if (deferred_string_key) SerializeDeferredKey(comma, key); 447 return SerializeJSValue(Handle<JSValue>::cast(object)); 448 case SYMBOL_TYPE: 449 return UNCHANGED; 450 default: 451 if (object->IsString()) { 452 if (deferred_string_key) SerializeDeferredKey(comma, key); 453 SerializeString(Handle<String>::cast(object)); 454 return SUCCESS; 455 } else { 456 DCHECK(object->IsJSReceiver()); 457 if (object->IsCallable()) return UNCHANGED; 458 // Go to slow path for global proxy and objects requiring access checks. 459 if (deferred_string_key) SerializeDeferredKey(comma, key); 460 if (object->IsJSProxy()) { 461 return SerializeJSProxy(Handle<JSProxy>::cast(object)); 462 } 463 return SerializeJSObject(Handle<JSObject>::cast(object)); 464 } 465 } 466 467 UNREACHABLE(); 468 } 469 470 JsonStringifier::Result JsonStringifier::SerializeJSValue( 471 Handle<JSValue> object) { 472 Object* raw = object->value(); 473 if (raw->IsString()) { 474 Handle<Object> value; 475 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 476 isolate_, value, Object::ToString(isolate_, object), EXCEPTION); 477 SerializeString(Handle<String>::cast(value)); 478 } else if (raw->IsNumber()) { 479 Handle<Object> value; 480 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 481 isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION); 482 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); 483 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); 484 } else if (raw->IsBigInt()) { 485 isolate_->Throw( 486 *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON)); 487 return EXCEPTION; 488 } else if (raw->IsBoolean()) { 489 builder_.AppendCString(raw->IsTrue(isolate_) ? "true" : "false"); 490 } else { 491 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. 492 return SerializeJSObject(object); 493 } 494 return SUCCESS; 495 } 496 497 JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) { 498 static const int kBufferSize = 100; 499 char chars[kBufferSize]; 500 Vector<char> buffer(chars, kBufferSize); 501 builder_.AppendCString(IntToCString(object->value(), buffer)); 502 return SUCCESS; 503 } 504 505 JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { 506 if (std::isinf(number) || std::isnan(number)) { 507 builder_.AppendCString("null"); 508 return SUCCESS; 509 } 510 static const int kBufferSize = 100; 511 char chars[kBufferSize]; 512 Vector<char> buffer(chars, kBufferSize); 513 builder_.AppendCString(DoubleToCString(number, buffer)); 514 return SUCCESS; 515 } 516 517 JsonStringifier::Result JsonStringifier::SerializeJSArray( 518 Handle<JSArray> object) { 519 HandleScope handle_scope(isolate_); 520 Result stack_push = StackPush(object); 521 if (stack_push != SUCCESS) return stack_push; 522 uint32_t length = 0; 523 CHECK(object->length()->ToArrayLength(&length)); 524 DCHECK(!object->IsAccessCheckNeeded()); 525 builder_.AppendCharacter('['); 526 Indent(); 527 uint32_t i = 0; 528 if (replacer_function_.is_null()) { 529 switch (object->GetElementsKind()) { 530 case PACKED_SMI_ELEMENTS: { 531 Handle<FixedArray> elements(FixedArray::cast(object->elements()), 532 isolate_); 533 StackLimitCheck interrupt_check(isolate_); 534 while (i < length) { 535 if (interrupt_check.InterruptRequested() && 536 isolate_->stack_guard()->HandleInterrupts()->IsException( 537 isolate_)) { 538 return EXCEPTION; 539 } 540 Separator(i == 0); 541 SerializeSmi(Smi::cast(elements->get(i))); 542 i++; 543 } 544 break; 545 } 546 case PACKED_DOUBLE_ELEMENTS: { 547 // Empty array is FixedArray but not FixedDoubleArray. 548 if (length == 0) break; 549 Handle<FixedDoubleArray> elements( 550 FixedDoubleArray::cast(object->elements()), isolate_); 551 StackLimitCheck interrupt_check(isolate_); 552 while (i < length) { 553 if (interrupt_check.InterruptRequested() && 554 isolate_->stack_guard()->HandleInterrupts()->IsException( 555 isolate_)) { 556 return EXCEPTION; 557 } 558 Separator(i == 0); 559 SerializeDouble(elements->get_scalar(i)); 560 i++; 561 } 562 break; 563 } 564 case PACKED_ELEMENTS: { 565 Handle<Object> old_length(object->length(), isolate_); 566 while (i < length) { 567 if (object->length() != *old_length || 568 object->GetElementsKind() != PACKED_ELEMENTS) { 569 // Fall back to slow path. 570 break; 571 } 572 Separator(i == 0); 573 Result result = SerializeElement( 574 isolate_, 575 Handle<Object>(FixedArray::cast(object->elements())->get(i), 576 isolate_), 577 i); 578 if (result == UNCHANGED) { 579 builder_.AppendCString("null"); 580 } else if (result != SUCCESS) { 581 return result; 582 } 583 i++; 584 } 585 break; 586 } 587 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble 588 // the non-holey cases except that a lookup is necessary for holes. 589 default: 590 break; 591 } 592 } 593 if (i < length) { 594 // Slow path for non-fast elements and fall-back in edge case. 595 Result result = SerializeArrayLikeSlow(object, i, length); 596 if (result != SUCCESS) return result; 597 } 598 Unindent(); 599 if (length > 0) NewLine(); 600 builder_.AppendCharacter(']'); 601 StackPop(); 602 return SUCCESS; 603 } 604 605 JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow( 606 Handle<JSReceiver> object, uint32_t start, uint32_t length) { 607 // We need to write out at least two characters per array element. 608 static const int kMaxSerializableArrayLength = String::kMaxLength / 2; 609 if (length > kMaxSerializableArrayLength) { 610 isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError()); 611 return EXCEPTION; 612 } 613 for (uint32_t i = start; i < length; i++) { 614 Separator(i == 0); 615 Handle<Object> element; 616 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 617 isolate_, element, JSReceiver::GetElement(isolate_, object, i), 618 EXCEPTION); 619 Result result = SerializeElement(isolate_, element, i); 620 if (result == SUCCESS) continue; 621 if (result == UNCHANGED) { 622 // Detect overflow sooner for large sparse arrays. 623 if (builder_.HasOverflowed()) return EXCEPTION; 624 builder_.AppendCString("null"); 625 } else { 626 return result; 627 } 628 } 629 return SUCCESS; 630 } 631 632 JsonStringifier::Result JsonStringifier::SerializeJSObject( 633 Handle<JSObject> object) { 634 HandleScope handle_scope(isolate_); 635 Result stack_push = StackPush(object); 636 if (stack_push != SUCCESS) return stack_push; 637 638 if (property_list_.is_null() && 639 !object->map()->IsCustomElementsReceiverMap() && 640 object->HasFastProperties() && 641 Handle<JSObject>::cast(object)->elements()->length() == 0) { 642 DCHECK(object->IsJSObject()); 643 DCHECK(!object->IsJSGlobalProxy()); 644 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); 645 DCHECK(!js_obj->HasIndexedInterceptor()); 646 DCHECK(!js_obj->HasNamedInterceptor()); 647 Handle<Map> map(js_obj->map(), isolate_); 648 builder_.AppendCharacter('{'); 649 Indent(); 650 bool comma = false; 651 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 652 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_); 653 // TODO(rossberg): Should this throw? 654 if (!name->IsString()) continue; 655 Handle<String> key = Handle<String>::cast(name); 656 PropertyDetails details = map->instance_descriptors()->GetDetails(i); 657 if (details.IsDontEnum()) continue; 658 Handle<Object> property; 659 if (details.location() == kField && *map == js_obj->map()) { 660 DCHECK_EQ(kData, details.kind()); 661 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); 662 property = JSObject::FastPropertyAt(js_obj, details.representation(), 663 field_index); 664 } else { 665 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 666 isolate_, property, 667 Object::GetPropertyOrElement(isolate_, js_obj, key), EXCEPTION); 668 } 669 Result result = SerializeProperty(property, comma, key); 670 if (!comma && result == SUCCESS) comma = true; 671 if (result == EXCEPTION) return result; 672 } 673 Unindent(); 674 if (comma) NewLine(); 675 builder_.AppendCharacter('}'); 676 } else { 677 Result result = SerializeJSReceiverSlow(object); 678 if (result != SUCCESS) return result; 679 } 680 StackPop(); 681 return SUCCESS; 682 } 683 684 JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow( 685 Handle<JSReceiver> object) { 686 Handle<FixedArray> contents = property_list_; 687 if (contents.is_null()) { 688 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 689 isolate_, contents, 690 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, 691 ENUMERABLE_STRINGS, 692 GetKeysConversion::kConvertToString), 693 EXCEPTION); 694 } 695 builder_.AppendCharacter('{'); 696 Indent(); 697 bool comma = false; 698 for (int i = 0; i < contents->length(); i++) { 699 Handle<String> key(String::cast(contents->get(i)), isolate_); 700 Handle<Object> property; 701 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 702 isolate_, property, Object::GetPropertyOrElement(isolate_, object, key), 703 EXCEPTION); 704 Result result = SerializeProperty(property, comma, key); 705 if (!comma && result == SUCCESS) comma = true; 706 if (result == EXCEPTION) return result; 707 } 708 Unindent(); 709 if (comma) NewLine(); 710 builder_.AppendCharacter('}'); 711 return SUCCESS; 712 } 713 714 JsonStringifier::Result JsonStringifier::SerializeJSProxy( 715 Handle<JSProxy> object) { 716 HandleScope scope(isolate_); 717 Result stack_push = StackPush(object); 718 if (stack_push != SUCCESS) return stack_push; 719 Maybe<bool> is_array = Object::IsArray(object); 720 if (is_array.IsNothing()) return EXCEPTION; 721 if (is_array.FromJust()) { 722 Handle<Object> length_object; 723 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 724 isolate_, length_object, 725 Object::GetLengthFromArrayLike(isolate_, 726 Handle<JSReceiver>::cast(object)), 727 EXCEPTION); 728 uint32_t length; 729 if (!length_object->ToUint32(&length)) { 730 // Technically, we need to be able to handle lengths outside the 731 // uint32_t range. However, we would run into string size overflow 732 // if we tried to stringify such an array. 733 isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError()); 734 return EXCEPTION; 735 } 736 builder_.AppendCharacter('['); 737 Indent(); 738 Result result = SerializeArrayLikeSlow(object, 0, length); 739 if (result != SUCCESS) return result; 740 Unindent(); 741 if (length > 0) NewLine(); 742 builder_.AppendCharacter(']'); 743 } else { 744 Result result = SerializeJSReceiverSlow(object); 745 if (result != SUCCESS) return result; 746 } 747 StackPop(); 748 return SUCCESS; 749 } 750 751 template <typename SrcChar, typename DestChar> 752 void JsonStringifier::SerializeStringUnchecked_( 753 Vector<const SrcChar> src, 754 IncrementalStringBuilder::NoExtend<DestChar>* dest) { 755 // Assert that uc16 character is not truncated down to 8 bit. 756 // The <uc16, char> version of this method must not be called. 757 DCHECK(sizeof(DestChar) >= sizeof(SrcChar)); 758 759 for (int i = 0; i < src.length(); i++) { 760 SrcChar c = src[i]; 761 if (DoNotEscape(c)) { 762 dest->Append(c); 763 } else { 764 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); 765 } 766 } 767 } 768 769 template <typename SrcChar, typename DestChar> 770 void JsonStringifier::SerializeString_(Handle<String> string) { 771 int length = string->length(); 772 builder_.Append<uint8_t, DestChar>('"'); 773 // We might be able to fit the whole escaped string in the current string 774 // part, or we might need to allocate. 775 if (int worst_case_length = builder_.EscapedLengthIfCurrentPartFits(length)) { 776 DisallowHeapAllocation no_gc; 777 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(); 778 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend( 779 &builder_, worst_case_length); 780 SerializeStringUnchecked_(vector, &no_extend); 781 } else { 782 FlatStringReader reader(isolate_, string); 783 for (int i = 0; i < reader.length(); i++) { 784 SrcChar c = reader.Get<SrcChar>(i); 785 if (DoNotEscape(c)) { 786 builder_.Append<SrcChar, DestChar>(c); 787 } else { 788 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); 789 } 790 } 791 } 792 builder_.Append<uint8_t, DestChar>('"'); 793 } 794 795 template <> 796 bool JsonStringifier::DoNotEscape(uint8_t c) { 797 return c >= '#' && c <= '~' && c != '\\'; 798 } 799 800 template <> 801 bool JsonStringifier::DoNotEscape(uint16_t c) { 802 return c >= '#' && c != '\\' && c != 0x7F; 803 } 804 805 void JsonStringifier::NewLine() { 806 if (gap_ == nullptr) return; 807 builder_.AppendCharacter('\n'); 808 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_); 809 } 810 811 void JsonStringifier::Separator(bool first) { 812 if (!first) builder_.AppendCharacter(','); 813 NewLine(); 814 } 815 816 void JsonStringifier::SerializeDeferredKey(bool deferred_comma, 817 Handle<Object> deferred_key) { 818 Separator(!deferred_comma); 819 SerializeString(Handle<String>::cast(deferred_key)); 820 builder_.AppendCharacter(':'); 821 if (gap_ != nullptr) builder_.AppendCharacter(' '); 822 } 823 824 void JsonStringifier::SerializeString(Handle<String> object) { 825 object = String::Flatten(isolate_, object); 826 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { 827 if (object->IsOneByteRepresentationUnderneath()) { 828 SerializeString_<uint8_t, uint8_t>(object); 829 } else { 830 builder_.ChangeEncoding(); 831 SerializeString(object); 832 } 833 } else { 834 if (object->IsOneByteRepresentationUnderneath()) { 835 SerializeString_<uint8_t, uc16>(object); 836 } else { 837 SerializeString_<uc16, uc16>(object); 838 } 839 } 840 } 841 842 } // namespace internal 843 } // namespace v8 844