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