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 3 // found in the LICENSE file. 4 5 #ifndef V8_JSON_STRINGIFIER_H_ 6 #define V8_JSON_STRINGIFIER_H_ 7 8 #include "src/v8.h" 9 10 #include "src/conversions.h" 11 #include "src/utils.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class BasicJsonStringifier BASE_EMBEDDED { 17 public: 18 explicit BasicJsonStringifier(Isolate* isolate); 19 20 MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object); 21 22 MUST_USE_RESULT INLINE(static MaybeHandle<Object> StringifyString( 23 Isolate* isolate, 24 Handle<String> object)); 25 26 private: 27 static const int kInitialPartLength = 32; 28 static const int kMaxPartLength = 16 * 1024; 29 static const int kPartLengthGrowthFactor = 2; 30 31 enum Result { UNCHANGED, SUCCESS, EXCEPTION }; 32 33 void Accumulate(); 34 35 void Extend(); 36 37 void ChangeEncoding(); 38 39 INLINE(void ShrinkCurrentPart()); 40 41 template <bool is_one_byte, typename Char> 42 INLINE(void Append_(Char c)); 43 44 template <bool is_one_byte, typename Char> 45 INLINE(void Append_(const Char* chars)); 46 47 INLINE(void Append(uint8_t c)) { 48 if (is_one_byte_) { 49 Append_<true>(c); 50 } else { 51 Append_<false>(c); 52 } 53 } 54 55 INLINE(void AppendOneByte(const char* chars)) { 56 if (is_one_byte_) { 57 Append_<true>(reinterpret_cast<const uint8_t*>(chars)); 58 } else { 59 Append_<false>(reinterpret_cast<const uint8_t*>(chars)); 60 } 61 } 62 63 MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction( 64 Handle<Object> object, 65 Handle<Object> key); 66 67 Result SerializeGeneric(Handle<Object> object, 68 Handle<Object> key, 69 bool deferred_comma, 70 bool deferred_key); 71 72 template <typename ResultType, typename Char> 73 INLINE(static Handle<String> StringifyString_(Isolate* isolate, 74 Vector<Char> vector, 75 Handle<String> result)); 76 77 // Entry point to serialize the object. 78 INLINE(Result SerializeObject(Handle<Object> obj)) { 79 return Serialize_<false>(obj, false, factory_->empty_string()); 80 } 81 82 // Serialize an array element. 83 // The index may serve as argument for the toJSON function. 84 INLINE(Result SerializeElement(Isolate* isolate, 85 Handle<Object> object, 86 int i)) { 87 return Serialize_<false>(object, 88 false, 89 Handle<Object>(Smi::FromInt(i), isolate)); 90 } 91 92 // Serialize a object property. 93 // The key may or may not be serialized depending on the property. 94 // The key may also serve as argument for the toJSON function. 95 INLINE(Result SerializeProperty(Handle<Object> object, 96 bool deferred_comma, 97 Handle<String> deferred_key)) { 98 DCHECK(!deferred_key.is_null()); 99 return Serialize_<true>(object, deferred_comma, deferred_key); 100 } 101 102 template <bool deferred_string_key> 103 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); 104 105 void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) { 106 if (deferred_comma) Append(','); 107 SerializeString(Handle<String>::cast(deferred_key)); 108 Append(':'); 109 } 110 111 Result SerializeSmi(Smi* object); 112 113 Result SerializeDouble(double number); 114 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { 115 return SerializeDouble(object->value()); 116 } 117 118 Result SerializeJSValue(Handle<JSValue> object); 119 120 INLINE(Result SerializeJSArray(Handle<JSArray> object)); 121 INLINE(Result SerializeJSObject(Handle<JSObject> object)); 122 123 Result SerializeJSArraySlow(Handle<JSArray> object, uint32_t length); 124 125 void SerializeString(Handle<String> object); 126 127 template <typename SrcChar, typename DestChar> 128 INLINE(static int SerializeStringUnchecked_(const SrcChar* src, 129 DestChar* dest, 130 int length)); 131 132 template <bool is_one_byte, typename Char> 133 INLINE(void SerializeString_(Handle<String> string)); 134 135 template <typename Char> 136 INLINE(static bool DoNotEscape(Char c)); 137 138 template <typename Char> 139 INLINE(static Vector<const Char> GetCharVector(Handle<String> string)); 140 141 Result StackPush(Handle<Object> object); 142 void StackPop(); 143 144 INLINE(Handle<String> accumulator()) { 145 return Handle<String>(String::cast(accumulator_store_->value()), isolate_); 146 } 147 148 INLINE(void set_accumulator(Handle<String> string)) { 149 return accumulator_store_->set_value(*string); 150 } 151 152 Isolate* isolate_; 153 Factory* factory_; 154 // We use a value wrapper for the string accumulator to keep the 155 // (indirect) handle to it in the outermost handle scope. 156 Handle<JSValue> accumulator_store_; 157 Handle<String> current_part_; 158 Handle<String> tojson_string_; 159 Handle<JSArray> stack_; 160 int current_index_; 161 int part_length_; 162 bool is_one_byte_; 163 bool overflowed_; 164 165 static const int kJsonEscapeTableEntrySize = 8; 166 static const char* const JsonEscapeTable; 167 }; 168 169 170 // Translation table to escape Latin1 characters. 171 // Table entries start at a multiple of 8 and are null-terminated. 172 const char* const BasicJsonStringifier::JsonEscapeTable = 173 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " 174 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " 175 "\\b\0 \\t\0 \\n\0 \\u000b\0 " 176 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " 177 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " 178 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " 179 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " 180 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " 181 " \0 !\0 \\\"\0 #\0 " 182 "$\0 %\0 &\0 '\0 " 183 "(\0 )\0 *\0 +\0 " 184 ",\0 -\0 .\0 /\0 " 185 "0\0 1\0 2\0 3\0 " 186 "4\0 5\0 6\0 7\0 " 187 "8\0 9\0 :\0 ;\0 " 188 "<\0 =\0 >\0 ?\0 " 189 "@\0 A\0 B\0 C\0 " 190 "D\0 E\0 F\0 G\0 " 191 "H\0 I\0 J\0 K\0 " 192 "L\0 M\0 N\0 O\0 " 193 "P\0 Q\0 R\0 S\0 " 194 "T\0 U\0 V\0 W\0 " 195 "X\0 Y\0 Z\0 [\0 " 196 "\\\\\0 ]\0 ^\0 _\0 " 197 "`\0 a\0 b\0 c\0 " 198 "d\0 e\0 f\0 g\0 " 199 "h\0 i\0 j\0 k\0 " 200 "l\0 m\0 n\0 o\0 " 201 "p\0 q\0 r\0 s\0 " 202 "t\0 u\0 v\0 w\0 " 203 "x\0 y\0 z\0 {\0 " 204 "|\0 }\0 ~\0 \177\0 " 205 "\200\0 \201\0 \202\0 \203\0 " 206 "\204\0 \205\0 \206\0 \207\0 " 207 "\210\0 \211\0 \212\0 \213\0 " 208 "\214\0 \215\0 \216\0 \217\0 " 209 "\220\0 \221\0 \222\0 \223\0 " 210 "\224\0 \225\0 \226\0 \227\0 " 211 "\230\0 \231\0 \232\0 \233\0 " 212 "\234\0 \235\0 \236\0 \237\0 " 213 "\240\0 \241\0 \242\0 \243\0 " 214 "\244\0 \245\0 \246\0 \247\0 " 215 "\250\0 \251\0 \252\0 \253\0 " 216 "\254\0 \255\0 \256\0 \257\0 " 217 "\260\0 \261\0 \262\0 \263\0 " 218 "\264\0 \265\0 \266\0 \267\0 " 219 "\270\0 \271\0 \272\0 \273\0 " 220 "\274\0 \275\0 \276\0 \277\0 " 221 "\300\0 \301\0 \302\0 \303\0 " 222 "\304\0 \305\0 \306\0 \307\0 " 223 "\310\0 \311\0 \312\0 \313\0 " 224 "\314\0 \315\0 \316\0 \317\0 " 225 "\320\0 \321\0 \322\0 \323\0 " 226 "\324\0 \325\0 \326\0 \327\0 " 227 "\330\0 \331\0 \332\0 \333\0 " 228 "\334\0 \335\0 \336\0 \337\0 " 229 "\340\0 \341\0 \342\0 \343\0 " 230 "\344\0 \345\0 \346\0 \347\0 " 231 "\350\0 \351\0 \352\0 \353\0 " 232 "\354\0 \355\0 \356\0 \357\0 " 233 "\360\0 \361\0 \362\0 \363\0 " 234 "\364\0 \365\0 \366\0 \367\0 " 235 "\370\0 \371\0 \372\0 \373\0 " 236 "\374\0 \375\0 \376\0 \377\0 "; 237 238 239 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) 240 : isolate_(isolate), 241 current_index_(0), 242 is_one_byte_(true), 243 overflowed_(false) { 244 factory_ = isolate_->factory(); 245 accumulator_store_ = Handle<JSValue>::cast( 246 Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked()); 247 part_length_ = kInitialPartLength; 248 current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked(); 249 tojson_string_ = factory_->toJSON_string(); 250 stack_ = factory_->NewJSArray(8); 251 } 252 253 254 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) { 255 Result result = SerializeObject(object); 256 if (result == UNCHANGED) return isolate_->factory()->undefined_value(); 257 if (result == SUCCESS) { 258 ShrinkCurrentPart(); 259 Accumulate(); 260 if (overflowed_) { 261 THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), Object); 262 } 263 return accumulator(); 264 } 265 DCHECK(result == EXCEPTION); 266 return MaybeHandle<Object>(); 267 } 268 269 270 MaybeHandle<Object> BasicJsonStringifier::StringifyString( 271 Isolate* isolate, Handle<String> object) { 272 static const int kJsonQuoteWorstCaseBlowup = 6; 273 static const int kSpaceForQuotes = 2; 274 int worst_case_length = 275 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; 276 277 if (worst_case_length > 32 * KB) { // Slow path if too large. 278 BasicJsonStringifier stringifier(isolate); 279 return stringifier.Stringify(object); 280 } 281 282 object = String::Flatten(object); 283 DCHECK(object->IsFlat()); 284 if (object->IsOneByteRepresentationUnderneath()) { 285 Handle<String> result = isolate->factory()->NewRawOneByteString( 286 worst_case_length).ToHandleChecked(); 287 DisallowHeapAllocation no_gc; 288 return StringifyString_<SeqOneByteString>( 289 isolate, 290 object->GetFlatContent().ToOneByteVector(), 291 result); 292 } else { 293 Handle<String> result = isolate->factory()->NewRawTwoByteString( 294 worst_case_length).ToHandleChecked(); 295 DisallowHeapAllocation no_gc; 296 return StringifyString_<SeqTwoByteString>( 297 isolate, 298 object->GetFlatContent().ToUC16Vector(), 299 result); 300 } 301 } 302 303 304 template <typename ResultType, typename Char> 305 Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate, 306 Vector<Char> vector, 307 Handle<String> result) { 308 DisallowHeapAllocation no_gc; 309 int final_size = 0; 310 ResultType* dest = ResultType::cast(*result); 311 dest->Set(final_size++, '\"'); 312 final_size += SerializeStringUnchecked_(vector.start(), 313 dest->GetChars() + 1, 314 vector.length()); 315 dest->Set(final_size++, '\"'); 316 return SeqString::Truncate(Handle<SeqString>::cast(result), final_size); 317 } 318 319 320 template <bool is_one_byte, typename Char> 321 void BasicJsonStringifier::Append_(Char c) { 322 if (is_one_byte) { 323 SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet( 324 current_index_++, c); 325 } else { 326 SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet( 327 current_index_++, c); 328 } 329 if (current_index_ == part_length_) Extend(); 330 } 331 332 333 template <bool is_one_byte, typename Char> 334 void BasicJsonStringifier::Append_(const Char* chars) { 335 for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars); 336 } 337 338 339 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction( 340 Handle<Object> object, Handle<Object> key) { 341 LookupIterator it(object, tojson_string_, 342 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 343 Handle<Object> fun; 344 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); 345 if (!fun->IsJSFunction()) return object; 346 347 // Call toJSON function. 348 if (key->IsSmi()) key = factory_->NumberToString(key); 349 Handle<Object> argv[] = { key }; 350 HandleScope scope(isolate_); 351 ASSIGN_RETURN_ON_EXCEPTION( 352 isolate_, object, 353 Execution::Call(isolate_, fun, object, 1, argv), 354 Object); 355 return scope.CloseAndEscape(object); 356 } 357 358 359 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( 360 Handle<Object> object) { 361 StackLimitCheck check(isolate_); 362 if (check.HasOverflowed()) { 363 isolate_->StackOverflow(); 364 return EXCEPTION; 365 } 366 367 int length = Smi::cast(stack_->length())->value(); 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 MaybeHandle<Object> maybe_error = factory_->NewTypeError( 376 "circular_structure", HandleVector<Object>(NULL, 0)); 377 if (maybe_error.ToHandle(&error)) isolate_->Throw(*error); 378 return EXCEPTION; 379 } 380 } 381 } 382 JSArray::EnsureSize(stack_, length + 1); 383 FixedArray::cast(stack_->elements())->set(length, *object); 384 stack_->set_length(Smi::FromInt(length + 1)); 385 return SUCCESS; 386 } 387 388 389 void BasicJsonStringifier::StackPop() { 390 int length = Smi::cast(stack_->length())->value(); 391 stack_->set_length(Smi::FromInt(length - 1)); 392 } 393 394 395 template <bool deferred_string_key> 396 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( 397 Handle<Object> object, bool comma, Handle<Object> key) { 398 if (object->IsJSObject()) { 399 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 400 isolate_, object, 401 ApplyToJsonFunction(object, key), 402 EXCEPTION); 403 } 404 405 if (object->IsSmi()) { 406 if (deferred_string_key) SerializeDeferredKey(comma, key); 407 return SerializeSmi(Smi::cast(*object)); 408 } 409 410 switch (HeapObject::cast(*object)->map()->instance_type()) { 411 case HEAP_NUMBER_TYPE: 412 case MUTABLE_HEAP_NUMBER_TYPE: 413 if (deferred_string_key) SerializeDeferredKey(comma, key); 414 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); 415 case ODDBALL_TYPE: 416 switch (Oddball::cast(*object)->kind()) { 417 case Oddball::kFalse: 418 if (deferred_string_key) SerializeDeferredKey(comma, key); 419 AppendOneByte("false"); 420 return SUCCESS; 421 case Oddball::kTrue: 422 if (deferred_string_key) SerializeDeferredKey(comma, key); 423 AppendOneByte("true"); 424 return SUCCESS; 425 case Oddball::kNull: 426 if (deferred_string_key) SerializeDeferredKey(comma, key); 427 AppendOneByte("null"); 428 return SUCCESS; 429 default: 430 return UNCHANGED; 431 } 432 case JS_ARRAY_TYPE: 433 if (object->IsAccessCheckNeeded()) break; 434 if (deferred_string_key) SerializeDeferredKey(comma, key); 435 return SerializeJSArray(Handle<JSArray>::cast(object)); 436 case JS_VALUE_TYPE: 437 if (deferred_string_key) SerializeDeferredKey(comma, key); 438 return SerializeJSValue(Handle<JSValue>::cast(object)); 439 case JS_FUNCTION_TYPE: 440 return UNCHANGED; 441 default: 442 if (object->IsString()) { 443 if (deferred_string_key) SerializeDeferredKey(comma, key); 444 SerializeString(Handle<String>::cast(object)); 445 return SUCCESS; 446 } else if (object->IsJSObject()) { 447 // Go to slow path for global proxy and objects requiring access checks. 448 if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break; 449 if (deferred_string_key) SerializeDeferredKey(comma, key); 450 return SerializeJSObject(Handle<JSObject>::cast(object)); 451 } 452 } 453 454 return SerializeGeneric(object, key, comma, deferred_string_key); 455 } 456 457 458 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric( 459 Handle<Object> object, 460 Handle<Object> key, 461 bool deferred_comma, 462 bool deferred_key) { 463 Handle<JSObject> builtins(isolate_->native_context()->builtins(), isolate_); 464 Handle<JSFunction> builtin = Handle<JSFunction>::cast(Object::GetProperty( 465 isolate_, builtins, "JSONSerializeAdapter").ToHandleChecked()); 466 467 Handle<Object> argv[] = { key, object }; 468 Handle<Object> result; 469 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 470 isolate_, result, 471 Execution::Call(isolate_, builtin, object, 2, argv), 472 EXCEPTION); 473 if (result->IsUndefined()) return UNCHANGED; 474 if (deferred_key) { 475 if (key->IsSmi()) key = factory_->NumberToString(key); 476 SerializeDeferredKey(deferred_comma, key); 477 } 478 479 Handle<String> result_string = Handle<String>::cast(result); 480 // Shrink current part, attach it to the accumulator, also attach the result 481 // string to the accumulator, and allocate a new part. 482 ShrinkCurrentPart(); // Shrink. 483 part_length_ = kInitialPartLength; // Allocate conservatively. 484 Extend(); // Attach current part and allocate new part. 485 // Attach result string to the accumulator. 486 Handle<String> cons; 487 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 488 isolate_, cons, 489 factory_->NewConsString(accumulator(), result_string), 490 EXCEPTION); 491 set_accumulator(cons); 492 return SUCCESS; 493 } 494 495 496 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( 497 Handle<JSValue> object) { 498 String* class_name = object->class_name(); 499 if (class_name == isolate_->heap()->String_string()) { 500 Handle<Object> value; 501 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 502 isolate_, value, Execution::ToString(isolate_, object), EXCEPTION); 503 SerializeString(Handle<String>::cast(value)); 504 } else if (class_name == isolate_->heap()->Number_string()) { 505 Handle<Object> value; 506 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 507 isolate_, value, Execution::ToNumber(isolate_, object), EXCEPTION); 508 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); 509 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); 510 } else { 511 DCHECK(class_name == isolate_->heap()->Boolean_string()); 512 Object* value = JSValue::cast(*object)->value(); 513 DCHECK(value->IsBoolean()); 514 AppendOneByte(value->IsTrue() ? "true" : "false"); 515 } 516 return SUCCESS; 517 } 518 519 520 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { 521 static const int kBufferSize = 100; 522 char chars[kBufferSize]; 523 Vector<char> buffer(chars, kBufferSize); 524 AppendOneByte(IntToCString(object->value(), buffer)); 525 return SUCCESS; 526 } 527 528 529 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( 530 double number) { 531 if (std::isinf(number) || std::isnan(number)) { 532 AppendOneByte("null"); 533 return SUCCESS; 534 } 535 static const int kBufferSize = 100; 536 char chars[kBufferSize]; 537 Vector<char> buffer(chars, kBufferSize); 538 AppendOneByte(DoubleToCString(number, buffer)); 539 return SUCCESS; 540 } 541 542 543 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( 544 Handle<JSArray> object) { 545 HandleScope handle_scope(isolate_); 546 Result stack_push = StackPush(object); 547 if (stack_push != SUCCESS) return stack_push; 548 uint32_t length = 0; 549 CHECK(object->length()->ToArrayIndex(&length)); 550 Append('['); 551 switch (object->GetElementsKind()) { 552 case FAST_SMI_ELEMENTS: { 553 Handle<FixedArray> elements( 554 FixedArray::cast(object->elements()), isolate_); 555 for (uint32_t i = 0; i < length; i++) { 556 if (i > 0) Append(','); 557 SerializeSmi(Smi::cast(elements->get(i))); 558 } 559 break; 560 } 561 case FAST_DOUBLE_ELEMENTS: { 562 // Empty array is FixedArray but not FixedDoubleArray. 563 if (length == 0) break; 564 Handle<FixedDoubleArray> elements( 565 FixedDoubleArray::cast(object->elements()), isolate_); 566 for (uint32_t i = 0; i < length; i++) { 567 if (i > 0) Append(','); 568 SerializeDouble(elements->get_scalar(i)); 569 } 570 break; 571 } 572 case FAST_ELEMENTS: { 573 Handle<FixedArray> elements( 574 FixedArray::cast(object->elements()), isolate_); 575 for (uint32_t i = 0; i < length; i++) { 576 if (i > 0) Append(','); 577 Result result = 578 SerializeElement(isolate_, 579 Handle<Object>(elements->get(i), isolate_), 580 i); 581 if (result == SUCCESS) continue; 582 if (result == UNCHANGED) { 583 AppendOneByte("null"); 584 } else { 585 return result; 586 } 587 } 588 break; 589 } 590 // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way. 591 // They resemble the non-holey cases except that a prototype chain lookup 592 // is necessary for holes. 593 default: { 594 Result result = SerializeJSArraySlow(object, length); 595 if (result != SUCCESS) return result; 596 break; 597 } 598 } 599 Append(']'); 600 StackPop(); 601 current_part_ = handle_scope.CloseAndEscape(current_part_); 602 return SUCCESS; 603 } 604 605 606 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( 607 Handle<JSArray> object, uint32_t length) { 608 for (uint32_t i = 0; i < length; i++) { 609 if (i > 0) Append(','); 610 Handle<Object> element; 611 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 612 isolate_, element, 613 Object::GetElement(isolate_, object, i), 614 EXCEPTION); 615 if (element->IsUndefined()) { 616 AppendOneByte("null"); 617 } else { 618 Result result = SerializeElement(isolate_, element, i); 619 if (result == SUCCESS) continue; 620 if (result == UNCHANGED) { 621 AppendOneByte("null"); 622 } else { 623 return result; 624 } 625 } 626 } 627 return SUCCESS; 628 } 629 630 631 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( 632 Handle<JSObject> object) { 633 HandleScope handle_scope(isolate_); 634 Result stack_push = StackPush(object); 635 if (stack_push != SUCCESS) return stack_push; 636 DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject()); 637 638 Append('{'); 639 bool comma = false; 640 641 if (object->HasFastProperties() && 642 !object->HasIndexedInterceptor() && 643 !object->HasNamedInterceptor() && 644 object->elements()->length() == 0) { 645 Handle<Map> map(object->map()); 646 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 647 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_); 648 // TODO(rossberg): Should this throw? 649 if (!name->IsString()) continue; 650 Handle<String> key = Handle<String>::cast(name); 651 PropertyDetails details = map->instance_descriptors()->GetDetails(i); 652 if (details.IsDontEnum()) continue; 653 Handle<Object> property; 654 if (details.type() == FIELD && *map == object->map()) { 655 property = Handle<Object>(object->RawFastPropertyAt( 656 FieldIndex::ForDescriptor(*map, i)), isolate_); 657 } else { 658 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 659 isolate_, property, 660 Object::GetPropertyOrElement(object, key), 661 EXCEPTION); 662 } 663 Result result = SerializeProperty(property, comma, key); 664 if (!comma && result == SUCCESS) comma = true; 665 if (result == EXCEPTION) return result; 666 } 667 } else { 668 Handle<FixedArray> contents; 669 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 670 isolate_, contents, 671 JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY), 672 EXCEPTION); 673 674 for (int i = 0; i < contents->length(); i++) { 675 Object* key = contents->get(i); 676 Handle<String> key_handle; 677 MaybeHandle<Object> maybe_property; 678 if (key->IsString()) { 679 key_handle = Handle<String>(String::cast(key), isolate_); 680 maybe_property = Object::GetPropertyOrElement(object, key_handle); 681 } else { 682 DCHECK(key->IsNumber()); 683 key_handle = factory_->NumberToString(Handle<Object>(key, isolate_)); 684 uint32_t index; 685 if (key->IsSmi()) { 686 maybe_property = Object::GetElement( 687 isolate_, object, Smi::cast(key)->value()); 688 } else if (key_handle->AsArrayIndex(&index)) { 689 maybe_property = Object::GetElement(isolate_, object, index); 690 } else { 691 maybe_property = Object::GetPropertyOrElement(object, key_handle); 692 } 693 } 694 Handle<Object> property; 695 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 696 isolate_, property, maybe_property, EXCEPTION); 697 Result result = SerializeProperty(property, comma, key_handle); 698 if (!comma && result == SUCCESS) comma = true; 699 if (result == EXCEPTION) return result; 700 } 701 } 702 703 Append('}'); 704 StackPop(); 705 current_part_ = handle_scope.CloseAndEscape(current_part_); 706 return SUCCESS; 707 } 708 709 710 void BasicJsonStringifier::ShrinkCurrentPart() { 711 DCHECK(current_index_ < part_length_); 712 current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_), 713 current_index_); 714 } 715 716 717 void BasicJsonStringifier::Accumulate() { 718 if (accumulator()->length() + current_part_->length() > String::kMaxLength) { 719 // Screw it. Simply set the flag and carry on. Throw exception at the end. 720 set_accumulator(factory_->empty_string()); 721 overflowed_ = true; 722 } else { 723 set_accumulator(factory_->NewConsString(accumulator(), 724 current_part_).ToHandleChecked()); 725 } 726 } 727 728 729 void BasicJsonStringifier::Extend() { 730 Accumulate(); 731 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { 732 part_length_ *= kPartLengthGrowthFactor; 733 } 734 if (is_one_byte_) { 735 current_part_ = 736 factory_->NewRawOneByteString(part_length_).ToHandleChecked(); 737 } else { 738 current_part_ = 739 factory_->NewRawTwoByteString(part_length_).ToHandleChecked(); 740 } 741 DCHECK(!current_part_.is_null()); 742 current_index_ = 0; 743 } 744 745 746 void BasicJsonStringifier::ChangeEncoding() { 747 ShrinkCurrentPart(); 748 Accumulate(); 749 current_part_ = 750 factory_->NewRawTwoByteString(part_length_).ToHandleChecked(); 751 DCHECK(!current_part_.is_null()); 752 current_index_ = 0; 753 is_one_byte_ = false; 754 } 755 756 757 template <typename SrcChar, typename DestChar> 758 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, 759 DestChar* dest, 760 int length) { 761 DestChar* dest_start = dest; 762 763 // Assert that uc16 character is not truncated down to 8 bit. 764 // The <uc16, char> version of this method must not be called. 765 DCHECK(sizeof(*dest) >= sizeof(*src)); 766 767 for (int i = 0; i < length; i++) { 768 SrcChar c = src[i]; 769 if (DoNotEscape(c)) { 770 *(dest++) = static_cast<DestChar>(c); 771 } else { 772 const uint8_t* chars = reinterpret_cast<const uint8_t*>( 773 &JsonEscapeTable[c * kJsonEscapeTableEntrySize]); 774 while (*chars != '\0') *(dest++) = *(chars++); 775 } 776 } 777 778 return static_cast<int>(dest - dest_start); 779 } 780 781 782 template <bool is_one_byte, typename Char> 783 void BasicJsonStringifier::SerializeString_(Handle<String> string) { 784 int length = string->length(); 785 Append_<is_one_byte, char>('"'); 786 // We make a rough estimate to find out if the current string can be 787 // serialized without allocating a new string part. The worst case length of 788 // an escaped character is 6. Shifting the remainin string length right by 3 789 // is a more pessimistic estimate, but faster to calculate. 790 791 if (((part_length_ - current_index_) >> 3) > length) { 792 DisallowHeapAllocation no_gc; 793 Vector<const Char> vector = GetCharVector<Char>(string); 794 if (is_one_byte) { 795 current_index_ += SerializeStringUnchecked_( 796 vector.start(), 797 SeqOneByteString::cast(*current_part_)->GetChars() + current_index_, 798 length); 799 } else { 800 current_index_ += SerializeStringUnchecked_( 801 vector.start(), 802 SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_, 803 length); 804 } 805 } else { 806 String* string_location = NULL; 807 Vector<const Char> vector(NULL, 0); 808 for (int i = 0; i < length; i++) { 809 // If GC moved the string, we need to refresh the vector. 810 if (*string != string_location) { 811 DisallowHeapAllocation no_gc; 812 // This does not actually prevent the string from being relocated later. 813 vector = GetCharVector<Char>(string); 814 string_location = *string; 815 } 816 Char c = vector[i]; 817 if (DoNotEscape(c)) { 818 Append_<is_one_byte, Char>(c); 819 } else { 820 Append_<is_one_byte, uint8_t>(reinterpret_cast<const uint8_t*>( 821 &JsonEscapeTable[c * kJsonEscapeTableEntrySize])); 822 } 823 } 824 } 825 826 Append_<is_one_byte, uint8_t>('"'); 827 } 828 829 830 template <> 831 bool BasicJsonStringifier::DoNotEscape(uint8_t c) { 832 return c >= '#' && c <= '~' && c != '\\'; 833 } 834 835 836 template <> 837 bool BasicJsonStringifier::DoNotEscape(uint16_t c) { 838 return c >= '#' && c != '\\' && c != 0x7f; 839 } 840 841 842 template <> 843 Vector<const uint8_t> BasicJsonStringifier::GetCharVector( 844 Handle<String> string) { 845 String::FlatContent flat = string->GetFlatContent(); 846 DCHECK(flat.IsOneByte()); 847 return flat.ToOneByteVector(); 848 } 849 850 851 template <> 852 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) { 853 String::FlatContent flat = string->GetFlatContent(); 854 DCHECK(flat.IsTwoByte()); 855 return flat.ToUC16Vector(); 856 } 857 858 859 void BasicJsonStringifier::SerializeString(Handle<String> object) { 860 object = String::Flatten(object); 861 if (is_one_byte_) { 862 if (object->IsOneByteRepresentationUnderneath()) { 863 SerializeString_<true, uint8_t>(object); 864 } else { 865 ChangeEncoding(); 866 SerializeString(object); 867 } 868 } else { 869 if (object->IsOneByteRepresentationUnderneath()) { 870 SerializeString_<false, uint8_t>(object); 871 } else { 872 SerializeString_<false, uc16>(object); 873 } 874 } 875 } 876 877 } } // namespace v8::internal 878 879 #endif // V8_JSON_STRINGIFIER_H_ 880