1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 #include "config.h" 28 #include "SerializedScriptValue.h" 29 30 #include "File.h" 31 #include "FileList.h" 32 #include "ImageData.h" 33 #include "JSDOMGlobalObject.h" 34 #include "JSFile.h" 35 #include "JSFileList.h" 36 #include "JSImageData.h" 37 #include <JavaScriptCore/APICast.h> 38 #include <runtime/DateInstance.h> 39 #include <runtime/ExceptionHelpers.h> 40 #include <runtime/JSLock.h> 41 #include <runtime/PropertyNameArray.h> 42 #include <wtf/ByteArray.h> 43 #include <wtf/HashTraits.h> 44 #include <wtf/Vector.h> 45 46 using namespace JSC; 47 48 namespace WebCore { 49 50 class SerializedObject : public SharedSerializedData 51 { 52 public: 53 typedef Vector<RefPtr<StringImpl> > PropertyNameList; 54 typedef Vector<SerializedScriptValueData> ValueList; 55 56 void set(const Identifier& propertyName, const SerializedScriptValueData& value) 57 { 58 ASSERT(m_names.size() == m_values.size()); 59 m_names.append(String(propertyName.ustring()).crossThreadString().impl()); 60 m_values.append(value); 61 } 62 63 PropertyNameList& names() { return m_names; } 64 65 ValueList& values() { return m_values; } 66 67 static PassRefPtr<SerializedObject> create() 68 { 69 return adoptRef(new SerializedObject); 70 } 71 72 void clear() 73 { 74 m_names.clear(); 75 m_values.clear(); 76 } 77 78 private: 79 SerializedObject() { } 80 PropertyNameList m_names; 81 ValueList m_values; 82 }; 83 84 class SerializedArray : public SharedSerializedData 85 { 86 typedef HashMap<unsigned, SerializedScriptValueData, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > SparseMap; 87 public: 88 void setIndex(unsigned index, const SerializedScriptValueData& value) 89 { 90 ASSERT(index < m_length); 91 if (index == m_compactStorage.size()) 92 m_compactStorage.append(value); 93 else 94 m_sparseStorage.set(index, value); 95 } 96 97 bool canDoFastRead(unsigned index) const 98 { 99 ASSERT(index < m_length); 100 return index < m_compactStorage.size(); 101 } 102 103 const SerializedScriptValueData& getIndex(unsigned index) 104 { 105 ASSERT(index < m_compactStorage.size()); 106 return m_compactStorage[index]; 107 } 108 109 SerializedScriptValueData getSparseIndex(unsigned index, bool& hasIndex) 110 { 111 ASSERT(index >= m_compactStorage.size()); 112 ASSERT(index < m_length); 113 SparseMap::iterator iter = m_sparseStorage.find(index); 114 if (iter == m_sparseStorage.end()) { 115 hasIndex = false; 116 return SerializedScriptValueData(); 117 } 118 hasIndex = true; 119 return iter->second; 120 } 121 122 unsigned length() const 123 { 124 return m_length; 125 } 126 127 static PassRefPtr<SerializedArray> create(unsigned length) 128 { 129 return adoptRef(new SerializedArray(length)); 130 } 131 132 void clear() 133 { 134 m_compactStorage.clear(); 135 m_sparseStorage.clear(); 136 m_length = 0; 137 } 138 private: 139 SerializedArray(unsigned length) 140 : m_length(length) 141 { 142 } 143 144 Vector<SerializedScriptValueData> m_compactStorage; 145 SparseMap m_sparseStorage; 146 unsigned m_length; 147 }; 148 149 class SerializedFileList : public SharedSerializedData { 150 public: 151 static PassRefPtr<SerializedFileList> create(const FileList* list) 152 { 153 return adoptRef(new SerializedFileList(list)); 154 } 155 156 unsigned length() const { return m_files.size(); } 157 const String& item(unsigned idx) { return m_files[idx]; } 158 159 private: 160 SerializedFileList(const FileList* list) 161 { 162 unsigned length = list->length(); 163 m_files.reserveCapacity(length); 164 for (unsigned i = 0; i < length; i++) 165 m_files.append(list->item(i)->path().crossThreadString()); 166 } 167 168 Vector<String> m_files; 169 }; 170 171 class SerializedImageData : public SharedSerializedData { 172 public: 173 static PassRefPtr<SerializedImageData> create(const ImageData* imageData) 174 { 175 return adoptRef(new SerializedImageData(imageData)); 176 } 177 178 unsigned width() const { return m_width; } 179 unsigned height() const { return m_height; } 180 WTF::ByteArray* data() const { return m_storage.get(); } 181 private: 182 SerializedImageData(const ImageData* imageData) 183 : m_width(imageData->width()) 184 , m_height(imageData->height()) 185 { 186 WTF::ByteArray* array = imageData->data()->data(); 187 m_storage = WTF::ByteArray::create(array->length()); 188 memcpy(m_storage->data(), array->data(), array->length()); 189 } 190 unsigned m_width; 191 unsigned m_height; 192 RefPtr<WTF::ByteArray> m_storage; 193 }; 194 195 SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedObject> data) 196 : m_type(ObjectType) 197 , m_sharedData(data) 198 { 199 } 200 201 SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedArray> data) 202 : m_type(ArrayType) 203 , m_sharedData(data) 204 { 205 } 206 207 SerializedScriptValueData::SerializedScriptValueData(const FileList* fileList) 208 : m_type(FileListType) 209 , m_sharedData(SerializedFileList::create(fileList)) 210 { 211 } 212 213 SerializedScriptValueData::SerializedScriptValueData(const ImageData* imageData) 214 : m_type(ImageDataType) 215 , m_sharedData(SerializedImageData::create(imageData)) 216 { 217 } 218 219 SerializedScriptValueData::SerializedScriptValueData(const File* file) 220 : m_type(FileType) 221 , m_string(file->path().crossThreadString()) 222 { 223 } 224 225 SerializedArray* SharedSerializedData::asArray() 226 { 227 return static_cast<SerializedArray*>(this); 228 } 229 230 SerializedObject* SharedSerializedData::asObject() 231 { 232 return static_cast<SerializedObject*>(this); 233 } 234 235 SerializedFileList* SharedSerializedData::asFileList() 236 { 237 return static_cast<SerializedFileList*>(this); 238 } 239 240 SerializedImageData* SharedSerializedData::asImageData() 241 { 242 return static_cast<SerializedImageData*>(this); 243 } 244 245 static const unsigned maximumFilterRecursion = 40000; 246 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, 247 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; 248 template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker& context, typename TreeWalker::InputType in) 249 { 250 typedef typename TreeWalker::InputObject InputObject; 251 typedef typename TreeWalker::InputArray InputArray; 252 typedef typename TreeWalker::OutputObject OutputObject; 253 typedef typename TreeWalker::OutputArray OutputArray; 254 typedef typename TreeWalker::InputType InputType; 255 typedef typename TreeWalker::OutputType OutputType; 256 typedef typename TreeWalker::PropertyList PropertyList; 257 258 Vector<uint32_t, 16> indexStack; 259 Vector<uint32_t, 16> lengthStack; 260 Vector<PropertyList, 16> propertyStack; 261 Vector<InputObject, 16> inputObjectStack; 262 Vector<InputArray, 16> inputArrayStack; 263 Vector<OutputObject, 16> outputObjectStack; 264 Vector<OutputArray, 16> outputArrayStack; 265 Vector<WalkerState, 16> stateStack; 266 WalkerState state = StateUnknown; 267 InputType inValue = in; 268 OutputType outValue = context.null(); 269 270 unsigned tickCount = context.ticksUntilNextCheck(); 271 while (1) { 272 switch (state) { 273 arrayStartState: 274 case ArrayStartState: { 275 ASSERT(context.isArray(inValue)); 276 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { 277 context.throwStackOverflow(); 278 return context.null(); 279 } 280 281 InputArray inArray = context.asInputArray(inValue); 282 unsigned length = context.length(inArray); 283 OutputArray outArray = context.createOutputArray(length); 284 if (!context.startArray(inArray, outArray)) 285 return context.null(); 286 inputArrayStack.append(inArray); 287 outputArrayStack.append(outArray); 288 indexStack.append(0); 289 lengthStack.append(length); 290 // fallthrough 291 } 292 arrayStartVisitMember: 293 case ArrayStartVisitMember: { 294 if (!--tickCount) { 295 if (context.didTimeOut()) { 296 context.throwInterruptedException(); 297 return context.null(); 298 } 299 tickCount = context.ticksUntilNextCheck(); 300 } 301 302 InputArray array = inputArrayStack.last(); 303 uint32_t index = indexStack.last(); 304 if (index == lengthStack.last()) { 305 InputArray inArray = inputArrayStack.last(); 306 OutputArray outArray = outputArrayStack.last(); 307 context.endArray(inArray, outArray); 308 outValue = outArray; 309 inputArrayStack.removeLast(); 310 outputArrayStack.removeLast(); 311 indexStack.removeLast(); 312 lengthStack.removeLast(); 313 break; 314 } 315 if (context.canDoFastRead(array, index)) 316 inValue = context.getIndex(array, index); 317 else { 318 bool hasIndex = false; 319 inValue = context.getSparseIndex(array, index, hasIndex); 320 if (!hasIndex) { 321 indexStack.last()++; 322 goto arrayStartVisitMember; 323 } 324 } 325 326 if (OutputType transformed = context.convertIfTerminal(inValue)) 327 outValue = transformed; 328 else { 329 stateStack.append(ArrayEndVisitMember); 330 goto stateUnknown; 331 } 332 // fallthrough 333 } 334 case ArrayEndVisitMember: { 335 OutputArray outArray = outputArrayStack.last(); 336 context.putProperty(outArray, indexStack.last(), outValue); 337 indexStack.last()++; 338 goto arrayStartVisitMember; 339 } 340 objectStartState: 341 case ObjectStartState: { 342 ASSERT(context.isObject(inValue)); 343 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { 344 context.throwStackOverflow(); 345 return context.null(); 346 } 347 InputObject inObject = context.asInputObject(inValue); 348 OutputObject outObject = context.createOutputObject(); 349 if (!context.startObject(inObject, outObject)) 350 return context.null(); 351 inputObjectStack.append(inObject); 352 outputObjectStack.append(outObject); 353 indexStack.append(0); 354 context.getPropertyNames(inObject, propertyStack); 355 // fallthrough 356 } 357 objectStartVisitMember: 358 case ObjectStartVisitMember: { 359 if (!--tickCount) { 360 if (context.didTimeOut()) { 361 context.throwInterruptedException(); 362 return context.null(); 363 } 364 tickCount = context.ticksUntilNextCheck(); 365 } 366 367 InputObject object = inputObjectStack.last(); 368 uint32_t index = indexStack.last(); 369 PropertyList& properties = propertyStack.last(); 370 if (index == properties.size()) { 371 InputObject inObject = inputObjectStack.last(); 372 OutputObject outObject = outputObjectStack.last(); 373 context.endObject(inObject, outObject); 374 outValue = outObject; 375 inputObjectStack.removeLast(); 376 outputObjectStack.removeLast(); 377 indexStack.removeLast(); 378 propertyStack.removeLast(); 379 break; 380 } 381 inValue = context.getProperty(object, properties[index], index); 382 383 if (context.shouldTerminate()) 384 return context.null(); 385 386 if (OutputType transformed = context.convertIfTerminal(inValue)) 387 outValue = transformed; 388 else { 389 stateStack.append(ObjectEndVisitMember); 390 goto stateUnknown; 391 } 392 // fallthrough 393 } 394 case ObjectEndVisitMember: { 395 context.putProperty(outputObjectStack.last(), propertyStack.last()[indexStack.last()], outValue); 396 if (context.shouldTerminate()) 397 return context.null(); 398 399 indexStack.last()++; 400 goto objectStartVisitMember; 401 } 402 stateUnknown: 403 case StateUnknown: 404 if (OutputType transformed = context.convertIfTerminal(inValue)) { 405 outValue = transformed; 406 break; 407 } 408 if (context.isArray(inValue)) 409 goto arrayStartState; 410 goto objectStartState; 411 } 412 if (stateStack.isEmpty()) 413 break; 414 415 state = stateStack.last(); 416 stateStack.removeLast(); 417 418 if (!--tickCount) { 419 if (context.didTimeOut()) { 420 context.throwInterruptedException(); 421 return context.null(); 422 } 423 tickCount = context.ticksUntilNextCheck(); 424 } 425 } 426 return outValue; 427 } 428 429 struct BaseWalker { 430 BaseWalker(ExecState* exec) 431 : m_exec(exec) 432 , m_timeoutChecker(exec->globalData().timeoutChecker) 433 { 434 m_timeoutChecker.reset(); 435 } 436 ExecState* m_exec; 437 TimeoutChecker m_timeoutChecker; 438 MarkedArgumentBuffer m_gcBuffer; 439 440 bool shouldTerminate() 441 { 442 return m_exec->hadException(); 443 } 444 445 unsigned ticksUntilNextCheck() 446 { 447 return m_timeoutChecker.ticksUntilNextCheck(); 448 } 449 450 bool didTimeOut() 451 { 452 return m_timeoutChecker.didTimeOut(m_exec); 453 } 454 455 void throwStackOverflow() 456 { 457 m_exec->setException(createStackOverflowError(m_exec)); 458 } 459 460 void throwInterruptedException() 461 { 462 m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); 463 } 464 }; 465 466 struct SerializingTreeWalker : public BaseWalker { 467 typedef JSValue InputType; 468 typedef JSArray* InputArray; 469 typedef JSObject* InputObject; 470 typedef SerializedScriptValueData OutputType; 471 typedef RefPtr<SerializedArray> OutputArray; 472 typedef RefPtr<SerializedObject> OutputObject; 473 typedef PropertyNameArray PropertyList; 474 475 SerializingTreeWalker(ExecState* exec) 476 : BaseWalker(exec) 477 { 478 } 479 480 OutputType null() { return SerializedScriptValueData(); } 481 482 bool isArray(JSValue value) 483 { 484 if (!value.isObject()) 485 return false; 486 JSObject* object = asObject(value); 487 return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info); 488 } 489 490 bool isObject(JSValue value) 491 { 492 return value.isObject(); 493 } 494 495 JSArray* asInputArray(JSValue value) 496 { 497 return asArray(value); 498 } 499 500 JSObject* asInputObject(JSValue value) 501 { 502 return asObject(value); 503 } 504 505 PassRefPtr<SerializedArray> createOutputArray(unsigned length) 506 { 507 return SerializedArray::create(length); 508 } 509 510 PassRefPtr<SerializedObject> createOutputObject() 511 { 512 return SerializedObject::create(); 513 } 514 515 uint32_t length(JSValue array) 516 { 517 ASSERT(array.isObject()); 518 JSObject* object = asObject(array); 519 return object->get(m_exec, m_exec->propertyNames().length).toUInt32(m_exec); 520 } 521 522 bool canDoFastRead(JSArray* array, unsigned index) 523 { 524 return isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index); 525 } 526 527 JSValue getIndex(JSArray* array, unsigned index) 528 { 529 return array->getIndex(index); 530 } 531 532 JSValue getSparseIndex(JSObject* object, unsigned propertyName, bool& hasIndex) 533 { 534 PropertySlot slot(object); 535 if (object->getOwnPropertySlot(m_exec, propertyName, slot)) { 536 hasIndex = true; 537 return slot.getValue(m_exec, propertyName); 538 } 539 hasIndex = false; 540 return jsNull(); 541 } 542 543 JSValue getProperty(JSObject* object, const Identifier& propertyName, unsigned) 544 { 545 PropertySlot slot(object); 546 if (object->getOwnPropertySlot(m_exec, propertyName, slot)) 547 return slot.getValue(m_exec, propertyName); 548 return jsNull(); 549 } 550 551 SerializedScriptValueData convertIfTerminal(JSValue value) 552 { 553 if (!value.isCell()) 554 return SerializedScriptValueData(value); 555 556 if (value.isString()) 557 return SerializedScriptValueData(asString(value)->value(m_exec)); 558 559 if (value.isNumber()) 560 return SerializedScriptValueData(SerializedScriptValueData::NumberType, value.uncheckedGetNumber()); 561 562 if (value.isObject() && asObject(value)->inherits(&DateInstance::info)) 563 return SerializedScriptValueData(SerializedScriptValueData::DateType, asDateInstance(value)->internalNumber()); 564 565 if (isArray(value)) 566 return SerializedScriptValueData(); 567 568 if (value.isObject()) { 569 JSObject* obj = asObject(value); 570 if (obj->inherits(&JSFile::s_info)) 571 return SerializedScriptValueData(toFile(obj)); 572 if (obj->inherits(&JSFileList::s_info)) 573 return SerializedScriptValueData(toFileList(obj)); 574 if (obj->inherits(&JSImageData::s_info)) 575 return SerializedScriptValueData(toImageData(obj)); 576 577 CallData unusedData; 578 if (value.getCallData(unusedData) == CallTypeNone) 579 return SerializedScriptValueData(); 580 } 581 // Any other types are expected to serialize as null. 582 return SerializedScriptValueData(jsNull()); 583 } 584 585 void getPropertyNames(JSObject* object, Vector<PropertyNameArray, 16>& propertyStack) 586 { 587 propertyStack.append(PropertyNameArray(m_exec)); 588 object->getOwnPropertyNames(m_exec, propertyStack.last()); 589 } 590 591 void putProperty(RefPtr<SerializedArray> array, unsigned propertyName, const SerializedScriptValueData& value) 592 { 593 array->setIndex(propertyName, value); 594 } 595 596 void putProperty(RefPtr<SerializedObject> object, const Identifier& propertyName, const SerializedScriptValueData& value) 597 { 598 object->set(propertyName, value); 599 } 600 601 bool startArray(JSArray* inArray, RefPtr<SerializedArray>) 602 { 603 // Cycle detection 604 if (!m_cycleDetector.add(inArray).second) { 605 m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures.")); 606 return false; 607 } 608 m_gcBuffer.append(inArray); 609 return true; 610 } 611 612 void endArray(JSArray* inArray, RefPtr<SerializedArray>) 613 { 614 m_cycleDetector.remove(inArray); 615 m_gcBuffer.removeLast(); 616 } 617 618 bool startObject(JSObject* inObject, RefPtr<SerializedObject>) 619 { 620 // Cycle detection 621 if (!m_cycleDetector.add(inObject).second) { 622 m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures.")); 623 return false; 624 } 625 m_gcBuffer.append(inObject); 626 return true; 627 } 628 629 void endObject(JSObject* inObject, RefPtr<SerializedObject>) 630 { 631 m_cycleDetector.remove(inObject); 632 m_gcBuffer.removeLast(); 633 } 634 635 private: 636 HashSet<JSObject*> m_cycleDetector; 637 }; 638 639 SerializedScriptValueData SerializedScriptValueData::serialize(ExecState* exec, JSValue inValue) 640 { 641 SerializingTreeWalker context(exec); 642 return walk<SerializingTreeWalker>(context, inValue); 643 } 644 645 646 struct DeserializingTreeWalker : public BaseWalker { 647 typedef SerializedScriptValueData InputType; 648 typedef RefPtr<SerializedArray> InputArray; 649 typedef RefPtr<SerializedObject> InputObject; 650 typedef JSValue OutputType; 651 typedef JSArray* OutputArray; 652 typedef JSObject* OutputObject; 653 typedef SerializedObject::PropertyNameList PropertyList; 654 655 DeserializingTreeWalker(ExecState* exec, JSGlobalObject* globalObject, bool mustCopy) 656 : BaseWalker(exec) 657 , m_globalObject(globalObject) 658 , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info)) 659 , m_mustCopy(mustCopy) 660 { 661 } 662 663 OutputType null() { return jsNull(); } 664 665 bool isArray(const SerializedScriptValueData& value) 666 { 667 return value.type() == SerializedScriptValueData::ArrayType; 668 } 669 670 bool isObject(const SerializedScriptValueData& value) 671 { 672 return value.type() == SerializedScriptValueData::ObjectType; 673 } 674 675 SerializedArray* asInputArray(const SerializedScriptValueData& value) 676 { 677 return value.asArray(); 678 } 679 680 SerializedObject* asInputObject(const SerializedScriptValueData& value) 681 { 682 return value.asObject(); 683 } 684 685 JSArray* createOutputArray(unsigned length) 686 { 687 JSArray* array = constructEmptyArray(m_exec, m_globalObject); 688 array->setLength(length); 689 return array; 690 } 691 692 JSObject* createOutputObject() 693 { 694 return constructEmptyObject(m_exec, m_globalObject); 695 } 696 697 uint32_t length(RefPtr<SerializedArray> array) 698 { 699 return array->length(); 700 } 701 702 bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index) 703 { 704 return array->canDoFastRead(index); 705 } 706 707 SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index) 708 { 709 return array->getIndex(index); 710 } 711 712 SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex) 713 { 714 return array->getSparseIndex(propertyName, hasIndex); 715 } 716 717 SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex) 718 { 719 ASSERT(object->names()[propertyIndex] == propertyName); 720 UNUSED_PARAM(propertyName); 721 return object->values()[propertyIndex]; 722 } 723 724 JSValue convertIfTerminal(SerializedScriptValueData& value) 725 { 726 switch (value.type()) { 727 case SerializedScriptValueData::ArrayType: 728 case SerializedScriptValueData::ObjectType: 729 return JSValue(); 730 case SerializedScriptValueData::StringType: 731 return jsString(m_exec, value.asString().crossThreadString()); 732 case SerializedScriptValueData::ImmediateType: 733 return value.asImmediate(); 734 case SerializedScriptValueData::NumberType: 735 return jsNumber(m_exec, value.asDouble()); 736 case SerializedScriptValueData::DateType: 737 return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), value.asDouble()); 738 case SerializedScriptValueData::FileType: 739 if (!m_isDOMGlobalObject) 740 return jsNull(); 741 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), File::create(value.asString().crossThreadString())); 742 case SerializedScriptValueData::FileListType: { 743 if (!m_isDOMGlobalObject) 744 return jsNull(); 745 RefPtr<FileList> result = FileList::create(); 746 SerializedFileList* serializedFileList = value.asFileList(); 747 unsigned length = serializedFileList->length(); 748 for (unsigned i = 0; i < length; i++) 749 result->append(File::create(serializedFileList->item(i))); 750 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get()); 751 } 752 case SerializedScriptValueData::ImageDataType: { 753 if (!m_isDOMGlobalObject) 754 return jsNull(); 755 SerializedImageData* serializedImageData = value.asImageData(); 756 RefPtr<ImageData> result = ImageData::create(serializedImageData->width(), serializedImageData->height()); 757 memcpy(result->data()->data()->data(), serializedImageData->data()->data(), serializedImageData->data()->length()); 758 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get()); 759 } 760 case SerializedScriptValueData::EmptyType: 761 ASSERT_NOT_REACHED(); 762 return jsNull(); 763 } 764 ASSERT_NOT_REACHED(); 765 return jsNull(); 766 } 767 768 void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties) 769 { 770 properties.append(object->names()); 771 } 772 773 void putProperty(JSArray* array, unsigned propertyName, JSValue value) 774 { 775 array->put(m_exec, propertyName, value); 776 } 777 778 void putProperty(JSObject* object, const RefPtr<StringImpl> propertyName, JSValue value) 779 { 780 object->putDirect(Identifier(m_exec, String(propertyName)), value); 781 } 782 783 bool startArray(RefPtr<SerializedArray>, JSArray* outArray) 784 { 785 m_gcBuffer.append(outArray); 786 return true; 787 } 788 void endArray(RefPtr<SerializedArray>, JSArray*) 789 { 790 m_gcBuffer.removeLast(); 791 } 792 bool startObject(RefPtr<SerializedObject>, JSObject* outObject) 793 { 794 m_gcBuffer.append(outObject); 795 return true; 796 } 797 void endObject(RefPtr<SerializedObject>, JSObject*) 798 { 799 m_gcBuffer.removeLast(); 800 } 801 802 private: 803 void* operator new(size_t); 804 JSGlobalObject* m_globalObject; 805 bool m_isDOMGlobalObject; 806 bool m_mustCopy; 807 }; 808 809 JSValue SerializedScriptValueData::deserialize(ExecState* exec, JSGlobalObject* global, bool mustCopy) const 810 { 811 DeserializingTreeWalker context(exec, global, mustCopy); 812 return walk<DeserializingTreeWalker>(context, *this); 813 } 814 815 struct TeardownTreeWalker { 816 typedef SerializedScriptValueData InputType; 817 typedef RefPtr<SerializedArray> InputArray; 818 typedef RefPtr<SerializedObject> InputObject; 819 typedef bool OutputType; 820 typedef bool OutputArray; 821 typedef bool OutputObject; 822 typedef SerializedObject::PropertyNameList PropertyList; 823 824 bool shouldTerminate() 825 { 826 return false; 827 } 828 829 unsigned ticksUntilNextCheck() 830 { 831 return 0xFFFFFFFF; 832 } 833 834 bool didTimeOut() 835 { 836 return false; 837 } 838 839 void throwStackOverflow() 840 { 841 } 842 843 void throwInterruptedException() 844 { 845 } 846 847 bool null() { return false; } 848 849 bool isArray(const SerializedScriptValueData& value) 850 { 851 return value.type() == SerializedScriptValueData::ArrayType; 852 } 853 854 bool isObject(const SerializedScriptValueData& value) 855 { 856 return value.type() == SerializedScriptValueData::ObjectType; 857 } 858 859 SerializedArray* asInputArray(const SerializedScriptValueData& value) 860 { 861 return value.asArray(); 862 } 863 864 SerializedObject* asInputObject(const SerializedScriptValueData& value) 865 { 866 return value.asObject(); 867 } 868 869 bool createOutputArray(unsigned) 870 { 871 return false; 872 } 873 874 bool createOutputObject() 875 { 876 return false; 877 } 878 879 uint32_t length(RefPtr<SerializedArray> array) 880 { 881 return array->length(); 882 } 883 884 bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index) 885 { 886 return array->canDoFastRead(index); 887 } 888 889 SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index) 890 { 891 return array->getIndex(index); 892 } 893 894 SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex) 895 { 896 return array->getSparseIndex(propertyName, hasIndex); 897 } 898 899 SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex) 900 { 901 ASSERT(object->names()[propertyIndex] == propertyName); 902 UNUSED_PARAM(propertyName); 903 return object->values()[propertyIndex]; 904 } 905 906 bool convertIfTerminal(SerializedScriptValueData& value) 907 { 908 switch (value.type()) { 909 case SerializedScriptValueData::ArrayType: 910 case SerializedScriptValueData::ObjectType: 911 return false; 912 case SerializedScriptValueData::StringType: 913 case SerializedScriptValueData::ImmediateType: 914 case SerializedScriptValueData::NumberType: 915 case SerializedScriptValueData::DateType: 916 case SerializedScriptValueData::EmptyType: 917 case SerializedScriptValueData::FileType: 918 case SerializedScriptValueData::FileListType: 919 case SerializedScriptValueData::ImageDataType: 920 return true; 921 } 922 ASSERT_NOT_REACHED(); 923 return true; 924 } 925 926 void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties) 927 { 928 properties.append(object->names()); 929 } 930 931 void putProperty(bool, unsigned, bool) 932 { 933 } 934 935 void putProperty(bool, const RefPtr<StringImpl>&, bool) 936 { 937 } 938 939 bool startArray(RefPtr<SerializedArray>, bool) 940 { 941 return true; 942 } 943 void endArray(RefPtr<SerializedArray> array, bool) 944 { 945 array->clear(); 946 } 947 bool startObject(RefPtr<SerializedObject>, bool) 948 { 949 return true; 950 } 951 void endObject(RefPtr<SerializedObject> object, bool) 952 { 953 object->clear(); 954 } 955 }; 956 957 void SerializedScriptValueData::tearDownSerializedData() 958 { 959 if (m_sharedData && m_sharedData->refCount() > 1) 960 return; 961 TeardownTreeWalker context; 962 walk<TeardownTreeWalker>(context, *this); 963 } 964 965 SerializedScriptValue::~SerializedScriptValue() 966 { 967 } 968 969 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception) 970 { 971 JSLock lock(SilenceAssertionsOnly); 972 ExecState* exec = toJS(originContext); 973 JSValue value = toJS(exec, apiValue); 974 PassRefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value); 975 if (exec->hadException()) { 976 if (exception) 977 *exception = toRef(exec, exec->exception()); 978 exec->clearException(); 979 return 0; 980 } 981 982 return serializedValue; 983 } 984 985 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception) 986 { 987 JSLock lock(SilenceAssertionsOnly); 988 ExecState* exec = toJS(destinationContext); 989 JSValue value = deserialize(exec, exec->lexicalGlobalObject()); 990 if (exec->hadException()) { 991 if (exception) 992 *exception = toRef(exec, exec->exception()); 993 exec->clearException(); 994 return 0; 995 } 996 return toRef(exec, value); 997 } 998 999 } 1000