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