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