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 35 namespace v8 { 36 namespace internal { 37 38 class 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. 189 const 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 256 BasicJsonStringifier::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 268 MaybeObject* 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 286 MaybeObject* 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 320 template <typename ResultType, typename Char> 321 MaybeObject* 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 336 template <bool is_ascii, typename Char> 337 void 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 349 template <bool is_ascii, typename Char> 350 void BasicJsonStringifier::Append_(const Char* chars) { 351 for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars); 352 } 353 354 355 Handle<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->IsJSFunction()) return object; 364 365 // Call toJSON function. 366 if (key->IsSmi()) key = factory_->NumberToString(key); 367 Handle<Object> argv[] = { key }; 368 bool has_exception = false; 369 HandleScope scope(isolate_); 370 object = Execution::Call(fun, object, 1, argv, &has_exception); 371 // Return empty handle to signal an exception. 372 if (has_exception) return Handle<Object>::null(); 373 return scope.CloseAndEscape(object); 374 } 375 376 377 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( 378 Handle<Object> object) { 379 StackLimitCheck check(isolate_); 380 if (check.HasOverflowed()) return STACK_OVERFLOW; 381 382 int length = Smi::cast(stack_->length())->value(); 383 FixedArray* elements = FixedArray::cast(stack_->elements()); 384 for (int i = 0; i < length; i++) { 385 if (elements->get(i) == *object) { 386 return CIRCULAR; 387 } 388 } 389 stack_->EnsureSize(length + 1); 390 FixedArray::cast(stack_->elements())->set(length, *object); 391 stack_->set_length(Smi::FromInt(length + 1)); 392 return SUCCESS; 393 } 394 395 396 void BasicJsonStringifier::StackPop() { 397 int length = Smi::cast(stack_->length())->value(); 398 stack_->set_length(Smi::FromInt(length - 1)); 399 } 400 401 402 template <bool deferred_string_key> 403 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( 404 Handle<Object> object, bool comma, Handle<Object> key) { 405 if (object->IsJSObject()) { 406 object = ApplyToJsonFunction(object, key); 407 if (object.is_null()) return EXCEPTION; 408 } 409 410 if (object->IsSmi()) { 411 if (deferred_string_key) SerializeDeferredKey(comma, key); 412 return SerializeSmi(Smi::cast(*object)); 413 } 414 415 switch (HeapObject::cast(*object)->map()->instance_type()) { 416 case HEAP_NUMBER_TYPE: 417 if (deferred_string_key) SerializeDeferredKey(comma, key); 418 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); 419 case ODDBALL_TYPE: 420 switch (Oddball::cast(*object)->kind()) { 421 case Oddball::kFalse: 422 if (deferred_string_key) SerializeDeferredKey(comma, key); 423 AppendAscii("false"); 424 return SUCCESS; 425 case Oddball::kTrue: 426 if (deferred_string_key) SerializeDeferredKey(comma, key); 427 AppendAscii("true"); 428 return SUCCESS; 429 case Oddball::kNull: 430 if (deferred_string_key) SerializeDeferredKey(comma, key); 431 AppendAscii("null"); 432 return SUCCESS; 433 default: 434 return UNCHANGED; 435 } 436 case JS_ARRAY_TYPE: 437 if (object->IsAccessCheckNeeded()) break; 438 if (deferred_string_key) SerializeDeferredKey(comma, key); 439 return SerializeJSArray(Handle<JSArray>::cast(object)); 440 case JS_VALUE_TYPE: 441 if (deferred_string_key) SerializeDeferredKey(comma, key); 442 return SerializeJSValue(Handle<JSValue>::cast(object)); 443 case JS_FUNCTION_TYPE: 444 return UNCHANGED; 445 default: 446 if (object->IsString()) { 447 if (deferred_string_key) SerializeDeferredKey(comma, key); 448 SerializeString(Handle<String>::cast(object)); 449 return SUCCESS; 450 } else if (object->IsJSObject()) { 451 if (object->IsAccessCheckNeeded()) break; 452 if (deferred_string_key) SerializeDeferredKey(comma, key); 453 return SerializeJSObject(Handle<JSObject>::cast(object)); 454 } 455 } 456 457 return SerializeGeneric(object, key, comma, deferred_string_key); 458 } 459 460 461 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric( 462 Handle<Object> object, 463 Handle<Object> key, 464 bool deferred_comma, 465 bool deferred_key) { 466 Handle<JSObject> builtins(isolate_->native_context()->builtins()); 467 Handle<JSFunction> builtin = 468 Handle<JSFunction>::cast(GetProperty(builtins, "JSONSerializeAdapter")); 469 470 Handle<Object> argv[] = { key, object }; 471 bool has_exception = false; 472 Handle<Object> result = 473 Execution::Call(builtin, object, 2, argv, &has_exception); 474 if (has_exception) return EXCEPTION; 475 if (result->IsUndefined()) return UNCHANGED; 476 if (deferred_key) { 477 if (key->IsSmi()) key = factory_->NumberToString(key); 478 SerializeDeferredKey(deferred_comma, key); 479 } 480 481 Handle<String> result_string = Handle<String>::cast(result); 482 // Shrink current part, attach it to the accumulator, also attach the result 483 // string to the accumulator, and allocate a new part. 484 ShrinkCurrentPart(); // Shrink. 485 part_length_ = kInitialPartLength; // Allocate conservatively. 486 Extend(); // Attach current part and allocate new part. 487 // Attach result string to the accumulator. 488 set_accumulator(factory_->NewConsString(accumulator(), result_string)); 489 return SUCCESS; 490 } 491 492 493 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( 494 Handle<JSValue> object) { 495 bool has_exception = false; 496 String* class_name = object->class_name(); 497 if (class_name == isolate_->heap()->String_string()) { 498 Handle<Object> value = Execution::ToString(object, &has_exception); 499 if (has_exception) return EXCEPTION; 500 SerializeString(Handle<String>::cast(value)); 501 } else if (class_name == isolate_->heap()->Number_string()) { 502 Handle<Object> value = Execution::ToNumber(object, &has_exception); 503 if (has_exception) return EXCEPTION; 504 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); 505 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); 506 } else { 507 ASSERT(class_name == isolate_->heap()->Boolean_string()); 508 Object* value = JSValue::cast(*object)->value(); 509 ASSERT(value->IsBoolean()); 510 AppendAscii(value->IsTrue() ? "true" : "false"); 511 } 512 return SUCCESS; 513 } 514 515 516 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { 517 static const int kBufferSize = 100; 518 char chars[kBufferSize]; 519 Vector<char> buffer(chars, kBufferSize); 520 AppendAscii(IntToCString(object->value(), buffer)); 521 return SUCCESS; 522 } 523 524 525 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( 526 double number) { 527 if (std::isinf(number) || std::isnan(number)) { 528 AppendAscii("null"); 529 return SUCCESS; 530 } 531 static const int kBufferSize = 100; 532 char chars[kBufferSize]; 533 Vector<char> buffer(chars, kBufferSize); 534 AppendAscii(DoubleToCString(number, buffer)); 535 return SUCCESS; 536 } 537 538 539 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( 540 Handle<JSArray> object) { 541 HandleScope handle_scope(isolate_); 542 Result stack_push = StackPush(object); 543 if (stack_push != SUCCESS) return stack_push; 544 int length = Smi::cast(object->length())->value(); 545 Append('['); 546 switch (object->GetElementsKind()) { 547 case FAST_SMI_ELEMENTS: { 548 Handle<FixedArray> elements( 549 FixedArray::cast(object->elements()), isolate_); 550 for (int 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 Handle<FixedDoubleArray> elements( 558 FixedDoubleArray::cast(object->elements()), isolate_); 559 for (int i = 0; i < length; i++) { 560 if (i > 0) Append(','); 561 SerializeDouble(elements->get_scalar(i)); 562 } 563 break; 564 } 565 case FAST_ELEMENTS: { 566 Handle<FixedArray> elements( 567 FixedArray::cast(object->elements()), isolate_); 568 for (int i = 0; i < length; i++) { 569 if (i > 0) Append(','); 570 Result result = 571 SerializeElement(isolate_, 572 Handle<Object>(elements->get(i), isolate_), 573 i); 574 if (result == SUCCESS) continue; 575 if (result == UNCHANGED) { 576 AppendAscii("null"); 577 } else { 578 return result; 579 } 580 } 581 break; 582 } 583 // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way. 584 // They resemble the non-holey cases except that a prototype chain lookup 585 // is necessary for holes. 586 default: { 587 Result result = SerializeJSArraySlow(object, length); 588 if (result != SUCCESS) return result; 589 break; 590 } 591 } 592 Append(']'); 593 StackPop(); 594 current_part_ = handle_scope.CloseAndEscape(current_part_); 595 return SUCCESS; 596 } 597 598 599 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( 600 Handle<JSArray> object, int length) { 601 for (int i = 0; i < length; i++) { 602 if (i > 0) Append(','); 603 Handle<Object> element = Object::GetElement(object, i); 604 RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, element, EXCEPTION); 605 if (element->IsUndefined()) { 606 AppendAscii("null"); 607 } else { 608 Result result = SerializeElement(object->GetIsolate(), element, i); 609 if (result == SUCCESS) continue; 610 if (result == UNCHANGED) { 611 AppendAscii("null"); 612 } else { 613 return result; 614 } 615 } 616 } 617 return SUCCESS; 618 } 619 620 621 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( 622 Handle<JSObject> object) { 623 HandleScope handle_scope(isolate_); 624 Result stack_push = StackPush(object); 625 if (stack_push != SUCCESS) return stack_push; 626 if (object->IsJSGlobalProxy()) { 627 object = Handle<JSObject>( 628 JSObject::cast(object->GetPrototype()), isolate_); 629 ASSERT(object->IsGlobalObject()); 630 } 631 632 Append('{'); 633 bool comma = false; 634 635 if (object->HasFastProperties() && 636 !object->HasIndexedInterceptor() && 637 !object->HasNamedInterceptor() && 638 object->elements()->length() == 0) { 639 Handle<Map> map(object->map()); 640 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 641 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_); 642 // TODO(rossberg): Should this throw? 643 if (!name->IsString()) continue; 644 Handle<String> key = Handle<String>::cast(name); 645 PropertyDetails details = map->instance_descriptors()->GetDetails(i); 646 if (details.IsDontEnum()) continue; 647 Handle<Object> property; 648 if (details.type() == FIELD && *map == object->map()) { 649 property = Handle<Object>( 650 object->RawFastPropertyAt( 651 map->instance_descriptors()->GetFieldIndex(i)), 652 isolate_); 653 } else { 654 property = GetProperty(isolate_, object, key); 655 if (property.is_null()) return EXCEPTION; 656 } 657 Result result = SerializeProperty(property, comma, key); 658 if (!comma && result == SUCCESS) comma = true; 659 if (result >= EXCEPTION) return result; 660 } 661 } else { 662 bool has_exception = false; 663 Handle<FixedArray> contents = 664 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception); 665 if (has_exception) return EXCEPTION; 666 667 for (int i = 0; i < contents->length(); i++) { 668 Object* key = contents->get(i); 669 Handle<String> key_handle; 670 Handle<Object> property; 671 if (key->IsString()) { 672 key_handle = Handle<String>(String::cast(key), isolate_); 673 property = GetProperty(isolate_, object, key_handle); 674 } else { 675 ASSERT(key->IsNumber()); 676 key_handle = factory_->NumberToString(Handle<Object>(key, isolate_)); 677 uint32_t index; 678 if (key->IsSmi()) { 679 property = Object::GetElement(object, Smi::cast(key)->value()); 680 } else if (key_handle->AsArrayIndex(&index)) { 681 property = Object::GetElement(object, index); 682 } else { 683 property = GetProperty(isolate_, object, key_handle); 684 } 685 } 686 if (property.is_null()) return EXCEPTION; 687 Result result = SerializeProperty(property, comma, key_handle); 688 if (!comma && result == SUCCESS) comma = true; 689 if (result >= EXCEPTION) return result; 690 } 691 } 692 693 Append('}'); 694 StackPop(); 695 current_part_ = handle_scope.CloseAndEscape(current_part_); 696 return SUCCESS; 697 } 698 699 700 void BasicJsonStringifier::ShrinkCurrentPart() { 701 ASSERT(current_index_ < part_length_); 702 current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_), 703 current_index_); 704 } 705 706 707 void BasicJsonStringifier::Extend() { 708 set_accumulator(factory_->NewConsString(accumulator(), current_part_)); 709 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { 710 part_length_ *= kPartLengthGrowthFactor; 711 } 712 if (is_ascii_) { 713 current_part_ = factory_->NewRawOneByteString(part_length_); 714 } else { 715 current_part_ = factory_->NewRawTwoByteString(part_length_); 716 } 717 current_index_ = 0; 718 } 719 720 721 void BasicJsonStringifier::ChangeEncoding() { 722 ShrinkCurrentPart(); 723 set_accumulator(factory_->NewConsString(accumulator(), current_part_)); 724 current_part_ = factory_->NewRawTwoByteString(part_length_); 725 current_index_ = 0; 726 is_ascii_ = false; 727 } 728 729 730 template <typename SrcChar, typename DestChar> 731 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, 732 DestChar* dest, 733 int length) { 734 DestChar* dest_start = dest; 735 736 // Assert that uc16 character is not truncated down to 8 bit. 737 // The <uc16, char> version of this method must not be called. 738 ASSERT(sizeof(*dest) >= sizeof(*src)); 739 740 for (int i = 0; i < length; i++) { 741 SrcChar c = src[i]; 742 if (DoNotEscape(c)) { 743 *(dest++) = static_cast<DestChar>(c); 744 } else { 745 const uint8_t* chars = reinterpret_cast<const uint8_t*>( 746 &JsonEscapeTable[c * kJsonEscapeTableEntrySize]); 747 while (*chars != '\0') *(dest++) = *(chars++); 748 } 749 } 750 751 return static_cast<int>(dest - dest_start); 752 } 753 754 755 template <bool is_ascii, typename Char> 756 void BasicJsonStringifier::SerializeString_(Handle<String> string) { 757 int length = string->length(); 758 Append_<is_ascii, char>('"'); 759 // We make a rough estimate to find out if the current string can be 760 // serialized without allocating a new string part. The worst case length of 761 // an escaped character is 6. Shifting the remainin string length right by 3 762 // is a more pessimistic estimate, but faster to calculate. 763 764 if (((part_length_ - current_index_) >> 3) > length) { 765 DisallowHeapAllocation no_gc; 766 Vector<const Char> vector = GetCharVector<Char>(string); 767 if (is_ascii) { 768 current_index_ += SerializeStringUnchecked_( 769 vector.start(), 770 SeqOneByteString::cast(*current_part_)->GetChars() + current_index_, 771 length); 772 } else { 773 current_index_ += SerializeStringUnchecked_( 774 vector.start(), 775 SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_, 776 length); 777 } 778 } else { 779 String* string_location = NULL; 780 Vector<const Char> vector(NULL, 0); 781 for (int i = 0; i < length; i++) { 782 // If GC moved the string, we need to refresh the vector. 783 if (*string != string_location) { 784 DisallowHeapAllocation no_gc; 785 // This does not actually prevent the string from being relocated later. 786 vector = GetCharVector<Char>(string); 787 string_location = *string; 788 } 789 Char c = vector[i]; 790 if (DoNotEscape(c)) { 791 Append_<is_ascii, Char>(c); 792 } else { 793 Append_<is_ascii, uint8_t>(reinterpret_cast<const uint8_t*>( 794 &JsonEscapeTable[c * kJsonEscapeTableEntrySize])); 795 } 796 } 797 } 798 799 Append_<is_ascii, uint8_t>('"'); 800 } 801 802 803 template <> 804 bool BasicJsonStringifier::DoNotEscape(uint8_t c) { 805 return c >= '#' && c <= '~' && c != '\\'; 806 } 807 808 809 template <> 810 bool BasicJsonStringifier::DoNotEscape(uint16_t c) { 811 return c >= '#' && c != '\\' && c != 0x7f; 812 } 813 814 815 template <> 816 Vector<const uint8_t> BasicJsonStringifier::GetCharVector( 817 Handle<String> string) { 818 String::FlatContent flat = string->GetFlatContent(); 819 ASSERT(flat.IsAscii()); 820 return flat.ToOneByteVector(); 821 } 822 823 824 template <> 825 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) { 826 String::FlatContent flat = string->GetFlatContent(); 827 ASSERT(flat.IsTwoByte()); 828 return flat.ToUC16Vector(); 829 } 830 831 832 void BasicJsonStringifier::SerializeString(Handle<String> object) { 833 object = FlattenGetString(object); 834 if (is_ascii_) { 835 if (object->IsOneByteRepresentationUnderneath()) { 836 SerializeString_<true, uint8_t>(object); 837 } else { 838 ChangeEncoding(); 839 SerializeString(object); 840 } 841 } else { 842 if (object->IsOneByteRepresentationUnderneath()) { 843 SerializeString_<false, uint8_t>(object); 844 } else { 845 SerializeString_<false, uc16>(object); 846 } 847 } 848 } 849 850 } } // namespace v8::internal 851 852 #endif // V8_JSON_STRINGIFIER_H_ 853