2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "SerializedScriptValue.h"
33 #include "ImageData.h"
35 #include "JSDOMGlobalObject.h"
37 #include "JSFileList.h"
38 #include "JSImageData.h"
39 #include "JSNavigator.h"
40 #include "SharedBuffer.h"
42 #include <JavaScriptCore/APICast.h>
43 #include <JavaScriptCore/APIShims.h>
44 #include <runtime/DateInstance.h>
45 #include <runtime/Error.h>
46 #include <runtime/ExceptionHelpers.h>
47 #include <runtime/PropertyNameArray.h>
48 #include <runtime/RegExp.h>
49 #include <runtime/RegExpObject.h>
50 #include <wtf/ByteArray.h>
51 #include <wtf/HashTraits.h>
52 #include <wtf/Vector.h>
57 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
58 #define ASSUME_LITTLE_ENDIAN 0
60 #define ASSUME_LITTLE_ENDIAN 1
65 static const unsigned maximumFilterRecursion = 40000;
67 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
68 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
70 // These can't be reordered, and any new types must be added to the end of the list
71 enum SerializationTag {
90 ObjectReferenceTag = 19,
94 /* CurrentVersion tracks the serialization version so that persistant stores
95 * are able to correctly bail out in the case of encountering newer formats.
97 * Initial version was 1.
98 * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
100 static const unsigned int CurrentVersion = 2;
101 static const unsigned int TerminatorTag = 0xFFFFFFFF;
102 static const unsigned int StringPoolTag = 0xFFFFFFFE;
105 * Object serialization is performed according to the following grammar, all tags
106 * are recorded as a single uint8_t.
108 * IndexType (used for the object pool and StringData's constant pool) is the
109 * minimum sized unsigned integer type required to represent the maximum index
110 * in the constant pool.
112 * SerializedValue :- <CurrentVersion:uint32_t> Value
113 * Value :- Array | Object | Terminal
116 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
119 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
124 * | IntTag <value:int32_t>
127 * | DoubleTag <value:double>
128 * | DateTag <value:double>
135 * | ObjectReferenceTag <opIndex:IndexType>
139 * StringTag StringData
142 * StringPoolTag <cpIndex:IndexType>
143 * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
149 * <path:StringData> <url:StringData> <type:StringData>
152 * FileListTag <length:uint32_t>(<file:FileData>){length}
155 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
158 * BlobTag <url:StringData><type:StringData><size:long long>
161 * RegExpTag <pattern:StringData><flags:StringData>
164 typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
168 CloneBase(ExecState* exec)
171 , m_timeoutChecker(exec->globalData().timeoutChecker)
175 bool shouldTerminate()
177 return m_exec->hadException();
180 unsigned ticksUntilNextCheck()
182 return m_timeoutChecker.ticksUntilNextCheck();
187 return m_timeoutChecker.didTimeOut(m_exec);
190 void throwStackOverflow()
192 throwError(m_exec, createStackOverflowError(m_exec));
195 void throwInterruptedException()
197 throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
200 NO_RETURN_DUE_TO_ASSERT
203 ASSERT_NOT_REACHED();
209 TimeoutChecker m_timeoutChecker;
210 MarkedArgumentBuffer m_gcBuffer;
213 #if ASSUME_LITTLE_ENDIAN
214 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
216 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
219 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
221 for (unsigned i = 0; i < sizeof(T); i++) {
222 buffer.append(value & 0xFF);
228 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
230 buffer.append(value);
233 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
235 if (length > numeric_limits<uint32_t>::max() / sizeof(T))
238 #if ASSUME_LITTLE_ENDIAN
239 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
241 for (unsigned i = 0; i < length; i++) {
243 for (unsigned j = 0; j < sizeof(T); j++) {
244 buffer.append(static_cast<uint8_t>(value & 0xFF));
252 class CloneSerializer : CloneBase {
254 static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out)
256 CloneSerializer serializer(exec, out);
257 return serializer.serialize(value);
260 static bool serialize(const String& s, Vector<uint8_t>& out)
262 writeLittleEndian(out, CurrentVersion);
264 writeLittleEndian<uint8_t>(out, EmptyStringTag);
267 writeLittleEndian<uint8_t>(out, StringTag);
268 writeLittleEndian(out, s.length());
269 return writeLittleEndian(out, s.impl()->characters(), s.length());
273 CloneSerializer(ExecState* exec, Vector<uint8_t>& out)
276 , m_emptyIdentifier(exec, UString("", 0))
278 write(CurrentVersion);
281 SerializationReturnCode serialize(JSValue in);
283 bool isArray(JSValue value)
285 if (!value.isObject())
287 JSObject* object = asObject(value);
288 return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::s_info);
291 bool startObjectInternal(JSObject* object)
293 // Record object for graph reconstruction
294 pair<ObjectPool::iterator, bool> iter = m_objectPool.add(object, m_objectPool.size());
296 // Handle duplicate references
298 write(ObjectReferenceTag);
299 ASSERT(static_cast<int32_t>(iter.first->second) < m_objectPool.size());
300 writeObjectIndex(iter.first->second);
304 m_gcBuffer.append(object);
308 bool startObject(JSObject* object)
310 if (!startObjectInternal(object))
316 bool startArray(JSArray* array)
318 if (!startObjectInternal(array))
321 unsigned length = array->length();
329 write(TerminatorTag);
332 JSValue getSparseIndex(JSArray* array, unsigned propertyName, bool& hasIndex)
334 PropertySlot slot(array);
335 if (isJSArray(&m_exec->globalData(), array)) {
336 if (array->JSArray::getOwnPropertySlot(m_exec, propertyName, slot)) {
338 return slot.getValue(m_exec, propertyName);
340 } else if (array->getOwnPropertySlot(m_exec, propertyName, slot)) {
342 return slot.getValue(m_exec, propertyName);
348 JSValue getProperty(JSObject* object, const Identifier& propertyName)
350 PropertySlot slot(object);
351 if (object->getOwnPropertySlot(m_exec, propertyName, slot))
352 return slot.getValue(m_exec, propertyName);
356 void dumpImmediate(JSValue value)
360 else if (value.isUndefined())
362 else if (value.isNumber()) {
363 if (value.isInt32()) {
364 if (!value.asInt32())
366 else if (value.asInt32() == 1)
370 write(static_cast<uint32_t>(value.asInt32()));
374 write(value.asDouble());
376 } else if (value.isBoolean()) {
384 void dumpString(UString str)
387 write(EmptyStringTag);
394 bool dumpIfTerminal(JSValue value)
396 if (!value.isCell()) {
397 dumpImmediate(value);
401 if (value.isString()) {
402 UString str = asString(value)->value(m_exec);
407 if (value.isNumber()) {
409 write(value.uncheckedGetNumber());
413 if (value.isObject() && asObject(value)->inherits(&DateInstance::s_info)) {
415 write(asDateInstance(value)->internalNumber());
422 // Object cannot be serialized because the act of walking the object creates new objects
423 if (value.isObject() && asObject(value)->inherits(&JSNavigator::s_info)) {
429 if (value.isObject()) {
430 JSObject* obj = asObject(value);
431 if (obj->inherits(&JSFile::s_info)) {
436 if (obj->inherits(&JSFileList::s_info)) {
437 FileList* list = toFileList(obj);
439 unsigned length = list->length();
441 for (unsigned i = 0; i < length; i++)
442 write(list->item(i));
445 if (obj->inherits(&JSBlob::s_info)) {
447 Blob* blob = toBlob(obj);
453 if (obj->inherits(&JSImageData::s_info)) {
454 ImageData* data = toImageData(obj);
456 write(data->width());
457 write(data->height());
458 write(data->data()->length());
459 write(data->data()->data()->data(), data->data()->length());
462 if (obj->inherits(&RegExpObject::s_info)) {
463 RegExpObject* regExp = asRegExpObject(obj);
466 if (regExp->regExp()->global())
467 flags[flagCount++] = 'g';
468 if (regExp->regExp()->ignoreCase())
469 flags[flagCount++] = 'i';
470 if (regExp->regExp()->multiline())
471 flags[flagCount++] = 'm';
473 write(regExp->regExp()->pattern());
474 write(UString(flags, flagCount));
479 if (getCallData(value, unusedData) == CallTypeNone)
482 // Any other types are expected to serialize as null.
487 void write(SerializationTag tag)
489 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
492 void write(uint8_t c)
494 writeLittleEndian(m_buffer, c);
497 void write(uint32_t i)
499 writeLittleEndian(m_buffer, i);
509 writeLittleEndian(m_buffer, u.i);
512 void write(int32_t i)
514 writeLittleEndian(m_buffer, i);
517 void write(unsigned long long i)
519 writeLittleEndian(m_buffer, i);
522 void write(uint16_t ch)
524 writeLittleEndian(m_buffer, ch);
527 void writeStringIndex(unsigned i)
529 writeConstantPoolIndex(m_constantPool, i);
532 void writeObjectIndex(unsigned i)
534 writeConstantPoolIndex(m_objectPool, i);
537 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
539 ASSERT(static_cast<int32_t>(i) < constantPool.size());
540 if (constantPool.size() <= 0xFF)
541 write(static_cast<uint8_t>(i));
542 else if (constantPool.size() <= 0xFFFF)
543 write(static_cast<uint16_t>(i));
545 write(static_cast<uint32_t>(i));
548 void write(const Identifier& ident)
550 UString str = ident.ustring();
551 pair<StringConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
553 write(StringPoolTag);
554 writeStringIndex(iter.first->second);
558 // This condition is unlikely to happen as they would imply an ~8gb
559 // string but we should guard against it anyway
560 if (str.length() >= StringPoolTag) {
565 // Guard against overflow
566 if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
571 writeLittleEndian<uint32_t>(m_buffer, str.length());
572 if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
576 void write(const UString& str)
579 write(m_emptyIdentifier);
581 write(Identifier(m_exec, str));
584 void write(const String& str)
587 write(m_emptyIdentifier);
589 write(Identifier(m_exec, str.impl()));
592 void write(const File* file)
599 void write(const uint8_t* data, unsigned length)
601 m_buffer.append(data, length);
604 Vector<uint8_t>& m_buffer;
605 typedef HashMap<JSObject*, uint32_t> ObjectPool;
606 ObjectPool m_objectPool;
607 typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
608 StringConstantPool m_constantPool;
609 Identifier m_emptyIdentifier;
612 SerializationReturnCode CloneSerializer::serialize(JSValue in)
614 Vector<uint32_t, 16> indexStack;
615 Vector<uint32_t, 16> lengthStack;
616 Vector<PropertyNameArray, 16> propertyStack;
617 Vector<JSObject*, 16> inputObjectStack;
618 Vector<JSArray*, 16> inputArrayStack;
619 Vector<WalkerState, 16> stateStack;
620 WalkerState state = StateUnknown;
621 JSValue inValue = in;
622 unsigned tickCount = ticksUntilNextCheck();
626 case ArrayStartState: {
627 ASSERT(isArray(inValue));
628 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion)
629 return StackOverflowError;
631 JSArray* inArray = asArray(inValue);
632 unsigned length = inArray->length();
633 if (!startArray(inArray))
635 inputArrayStack.append(inArray);
636 indexStack.append(0);
637 lengthStack.append(length);
640 arrayStartVisitMember:
641 case ArrayStartVisitMember: {
644 return InterruptedExecutionError;
645 tickCount = ticksUntilNextCheck();
648 JSArray* array = inputArrayStack.last();
649 uint32_t index = indexStack.last();
650 if (index == lengthStack.last()) {
652 inputArrayStack.removeLast();
653 indexStack.removeLast();
654 lengthStack.removeLast();
657 if (array->canGetIndex(index))
658 inValue = array->getIndex(index);
660 bool hasIndex = false;
661 inValue = getSparseIndex(array, index, hasIndex);
664 goto arrayStartVisitMember;
669 if (dumpIfTerminal(inValue)) {
671 goto arrayStartVisitMember;
673 stateStack.append(ArrayEndVisitMember);
676 case ArrayEndVisitMember: {
678 goto arrayStartVisitMember;
681 case ObjectStartState: {
682 ASSERT(inValue.isObject());
683 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion)
684 return StackOverflowError;
685 JSObject* inObject = asObject(inValue);
686 if (!startObject(inObject))
688 inputObjectStack.append(inObject);
689 indexStack.append(0);
690 propertyStack.append(PropertyNameArray(m_exec));
691 inObject->getOwnPropertyNames(m_exec, propertyStack.last());
694 objectStartVisitMember:
695 case ObjectStartVisitMember: {
698 return InterruptedExecutionError;
699 tickCount = ticksUntilNextCheck();
702 JSObject* object = inputObjectStack.last();
703 uint32_t index = indexStack.last();
704 PropertyNameArray& properties = propertyStack.last();
705 if (index == properties.size()) {
707 inputObjectStack.removeLast();
708 indexStack.removeLast();
709 propertyStack.removeLast();
712 inValue = getProperty(object, properties[index]);
713 if (shouldTerminate())
714 return ExistingExceptionError;
717 // Property was removed during serialisation
719 goto objectStartVisitMember;
721 write(properties[index]);
723 if (shouldTerminate())
724 return ExistingExceptionError;
726 if (!dumpIfTerminal(inValue)) {
727 stateStack.append(ObjectEndVisitMember);
732 case ObjectEndVisitMember: {
733 if (shouldTerminate())
734 return ExistingExceptionError;
737 goto objectStartVisitMember;
741 if (dumpIfTerminal(inValue))
744 if (isArray(inValue))
745 goto arrayStartState;
746 goto objectStartState;
748 if (stateStack.isEmpty())
751 state = stateStack.last();
752 stateStack.removeLast();
756 return InterruptedExecutionError;
757 tickCount = ticksUntilNextCheck();
761 return UnspecifiedError;
763 return SuccessfullyCompleted;
766 class CloneDeserializer : CloneBase {
768 static String deserializeString(const Vector<uint8_t>& buffer)
770 const uint8_t* ptr = buffer.begin();
771 const uint8_t* end = buffer.end();
773 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
776 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
779 if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
782 if (!readString(ptr, end, str, length))
784 return String(str.impl());
787 static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
790 return make_pair(jsNull(), UnspecifiedError);
791 CloneDeserializer deserializer(exec, globalObject, buffer);
792 if (!deserializer.isValid())
793 return make_pair(JSValue(), ValidationError);
794 return deserializer.deserialize();
798 struct CachedString {
799 CachedString(const UString& string)
804 JSValue jsString(ExecState* exec)
807 m_jsString = JSC::jsString(exec, m_string);
810 const UString& ustring() { return m_string; }
817 struct CachedStringRef {
823 CachedStringRef(Vector<CachedString>* base, size_t index)
829 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
832 Vector<CachedString>* m_base;
836 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
838 , m_globalObject(globalObject)
839 , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
840 , m_ptr(buffer.data())
841 , m_end(buffer.data() + buffer.size())
842 , m_version(0xFFFFFFFF)
844 if (!read(m_version))
845 m_version = 0xFFFFFFFF;
848 DeserializationResult deserialize();
850 void throwValidationError()
852 throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
855 bool isValid() const { return m_version <= CurrentVersion; }
857 template <typename T> bool readLittleEndian(T& value)
859 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
865 #if ASSUME_LITTLE_ENDIAN
866 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
868 if (ptr > end - sizeof(value))
874 value = *reinterpret_cast<const T*>(ptr);
880 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
882 if (ptr > end - sizeof(value))
889 for (unsigned i = 0; i < sizeof(T); i++)
890 value += ((T)*ptr++) << (i * 8);
896 bool read(uint32_t& i)
898 return readLittleEndian(i);
901 bool read(int32_t& i)
903 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
906 bool read(uint16_t& i)
908 return readLittleEndian(i);
911 bool read(uint8_t& i)
913 return readLittleEndian(i);
922 if (!readLittleEndian(u.i64))
928 bool read(unsigned long long& i)
930 return readLittleEndian(i);
933 bool readStringIndex(uint32_t& i)
935 return readConstantPoolIndex(m_constantPool, i);
938 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
940 if (constantPool.size() <= 0xFF) {
947 if (constantPool.size() <= 0xFFFF) {
957 static bool readString(const uint8_t*& ptr, const uint8_t* end, UString& str, unsigned length)
959 if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
962 unsigned size = length * sizeof(UChar);
963 if ((end - ptr) < static_cast<int>(size))
966 #if ASSUME_LITTLE_ENDIAN
967 str = UString(reinterpret_cast<const UChar*>(ptr), length);
968 ptr += length * sizeof(UChar);
970 Vector<UChar> buffer;
971 buffer.reserveCapacity(length);
972 for (unsigned i = 0; i < length; i++) {
974 readLittleEndian(ptr, end, ch);
977 str = UString::adopt(buffer);
982 bool readStringData(CachedStringRef& cachedString)
985 return readStringData(cachedString, scratch);
988 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
995 if (length == TerminatorTag) {
996 wasTerminator = true;
999 if (length == StringPoolTag) {
1001 if (!readStringIndex(index)) {
1005 if (index >= m_constantPool.size()) {
1009 cachedString = CachedStringRef(&m_constantPool, index);
1013 if (!readString(m_ptr, m_end, str, length)) {
1017 m_constantPool.append(str);
1018 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
1022 SerializationTag readTag()
1026 return static_cast<SerializationTag>(*m_ptr++);
1029 void putProperty(JSArray* array, unsigned index, JSValue value)
1031 if (array->canSetIndex(index))
1032 array->setIndex(m_exec->globalData(), index, value);
1034 array->put(m_exec, index, value);
1037 void putProperty(JSObject* object, const Identifier& property, JSValue value)
1039 object->putDirect(m_exec->globalData(), property, value);
1042 bool readFile(RefPtr<File>& file)
1044 CachedStringRef path;
1045 if (!readStringData(path))
1047 CachedStringRef url;
1048 if (!readStringData(url))
1050 CachedStringRef type;
1051 if (!readStringData(type))
1053 if (m_isDOMGlobalObject)
1054 file = File::create(String(path->ustring().impl()), KURL(KURL(), String(url->ustring().impl())), String(type->ustring().impl()));
1058 JSValue readTerminal()
1060 SerializationTag tag = readTag();
1063 return jsUndefined();
1077 return jsBoolean(false);
1079 return jsBoolean(true);
1090 return DateInstance::create(m_exec, m_globalObject->dateStructure(), d);
1094 if (!readFile(file))
1096 if (!m_isDOMGlobalObject)
1098 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), file.get());
1101 unsigned length = 0;
1104 RefPtr<FileList> result = FileList::create();
1105 for (unsigned i = 0; i < length; i++) {
1107 if (!readFile(file))
1109 if (m_isDOMGlobalObject)
1110 result->append(file.get());
1112 if (!m_isDOMGlobalObject)
1114 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1116 case ImageDataTag: {
1126 if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1130 if (!m_isDOMGlobalObject) {
1134 RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
1135 memcpy(result->data()->data()->data(), m_ptr, length);
1137 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1140 CachedStringRef url;
1141 if (!readStringData(url))
1143 CachedStringRef type;
1144 if (!readStringData(type))
1146 unsigned long long size = 0;
1149 if (!m_isDOMGlobalObject)
1151 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(KURL(KURL(), url->ustring().impl()), String(type->ustring().impl()), size));
1154 CachedStringRef cachedString;
1155 if (!readStringData(cachedString))
1157 return cachedString->jsString(m_exec);
1159 case EmptyStringTag:
1160 return jsEmptyString(&m_exec->globalData());
1162 CachedStringRef pattern;
1163 if (!readStringData(pattern))
1165 CachedStringRef flags;
1166 if (!readStringData(flags))
1168 RegExpFlags reFlags = regExpFlags(flags->ustring());
1169 ASSERT(reFlags != InvalidFlags);
1170 RegExp* regExp = RegExp::create(m_exec->globalData(), pattern->ustring(), reFlags);
1171 return RegExpObject::create(m_exec, m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp);
1173 case ObjectReferenceTag: {
1175 if (!readConstantPoolIndex(m_gcBuffer, index)) {
1179 return m_gcBuffer.at(index);
1182 m_ptr--; // Push the tag back
1187 JSGlobalObject* m_globalObject;
1188 bool m_isDOMGlobalObject;
1189 const uint8_t* m_ptr;
1190 const uint8_t* m_end;
1192 Vector<CachedString> m_constantPool;
1195 DeserializationResult CloneDeserializer::deserialize()
1197 Vector<uint32_t, 16> indexStack;
1198 Vector<Identifier, 16> propertyNameStack;
1199 Vector<JSObject*, 16> outputObjectStack;
1200 Vector<JSArray*, 16> outputArrayStack;
1201 Vector<WalkerState, 16> stateStack;
1202 WalkerState state = StateUnknown;
1205 unsigned tickCount = ticksUntilNextCheck();
1209 case ArrayStartState: {
1211 if (!read(length)) {
1215 JSArray* outArray = constructEmptyArray(m_exec, m_globalObject);
1216 outArray->setLength(length);
1217 m_gcBuffer.append(outArray);
1218 outputArrayStack.append(outArray);
1221 arrayStartVisitMember:
1222 case ArrayStartVisitMember: {
1225 return make_pair(JSValue(), InterruptedExecutionError);
1226 tickCount = ticksUntilNextCheck();
1234 if (index == TerminatorTag) {
1235 JSArray* outArray = outputArrayStack.last();
1236 outValue = outArray;
1237 outputArrayStack.removeLast();
1241 if (JSValue terminal = readTerminal()) {
1242 putProperty(outputArrayStack.last(), index, terminal);
1243 goto arrayStartVisitMember;
1247 indexStack.append(index);
1248 stateStack.append(ArrayEndVisitMember);
1251 case ArrayEndVisitMember: {
1252 JSArray* outArray = outputArrayStack.last();
1253 putProperty(outArray, indexStack.last(), outValue);
1254 indexStack.removeLast();
1255 goto arrayStartVisitMember;
1258 case ObjectStartState: {
1259 if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion)
1260 return make_pair(JSValue(), StackOverflowError);
1261 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject);
1262 m_gcBuffer.append(outObject);
1263 outputObjectStack.append(outObject);
1266 objectStartVisitMember:
1267 case ObjectStartVisitMember: {
1270 return make_pair(JSValue(), InterruptedExecutionError);
1271 tickCount = ticksUntilNextCheck();
1274 CachedStringRef cachedString;
1275 bool wasTerminator = false;
1276 if (!readStringData(cachedString, wasTerminator)) {
1279 JSObject* outObject = outputObjectStack.last();
1280 outValue = outObject;
1281 outputObjectStack.removeLast();
1285 if (JSValue terminal = readTerminal()) {
1286 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->ustring()), terminal);
1287 goto objectStartVisitMember;
1289 stateStack.append(ObjectEndVisitMember);
1290 propertyNameStack.append(Identifier(m_exec, cachedString->ustring()));
1293 case ObjectEndVisitMember: {
1294 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1295 propertyNameStack.removeLast();
1296 goto objectStartVisitMember;
1300 if (JSValue terminal = readTerminal()) {
1301 outValue = terminal;
1304 SerializationTag tag = readTag();
1305 if (tag == ArrayTag)
1306 goto arrayStartState;
1307 if (tag == ObjectTag)
1308 goto objectStartState;
1311 if (stateStack.isEmpty())
1314 state = stateStack.last();
1315 stateStack.removeLast();
1319 return make_pair(JSValue(), InterruptedExecutionError);
1320 tickCount = ticksUntilNextCheck();
1325 return make_pair(outValue, SuccessfullyCompleted);
1328 return make_pair(JSValue(), ValidationError);
1333 SerializedScriptValue::~SerializedScriptValue()
1337 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1339 m_data.swap(buffer);
1342 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value, SerializationErrorMode throwExceptions)
1344 Vector<uint8_t> buffer;
1345 SerializationReturnCode code = CloneSerializer::serialize(exec, value, buffer);
1346 if (throwExceptions == Throwing)
1347 maybeThrowExceptionIfSerializationFailed(exec, code);
1349 if (!serializationDidCompleteSuccessfully(code))
1352 return adoptRef(new SerializedScriptValue(buffer));
1355 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1357 Vector<uint8_t> buffer;
1358 return adoptRef(new SerializedScriptValue(buffer));
1361 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
1363 Vector<uint8_t> buffer;
1364 if (!CloneSerializer::serialize(string, buffer))
1366 return adoptRef(new SerializedScriptValue(buffer));
1369 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
1371 ExecState* exec = toJS(originContext);
1372 APIEntryShim entryShim(exec);
1373 JSValue value = toJS(exec, apiValue);
1374 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value);
1375 if (exec->hadException()) {
1377 *exception = toRef(exec, exec->exception());
1378 exec->clearException();
1381 ASSERT(serializedValue);
1382 return serializedValue.release();
1385 String SerializedScriptValue::toString()
1387 return CloneDeserializer::deserializeString(m_data);
1390 JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions)
1392 DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, m_data);
1393 if (throwExceptions == Throwing)
1394 maybeThrowExceptionIfSerializationFailed(exec, result.second);
1395 return result.first;
1398 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
1400 ExecState* exec = toJS(destinationContext);
1401 APIEntryShim entryShim(exec);
1402 JSValue value = deserialize(exec, exec->lexicalGlobalObject());
1403 if (exec->hadException()) {
1405 *exception = toRef(exec, exec->exception());
1406 exec->clearException();
1410 return toRef(exec, value);
1413 SerializedScriptValue* SerializedScriptValue::nullValue()
1415 DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, emptyValue, (SerializedScriptValue::create()));
1416 return emptyValue.get();
1419 void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
1421 if (code == SuccessfullyCompleted)
1425 case StackOverflowError:
1426 throwError(exec, createStackOverflowError(exec));
1428 case InterruptedExecutionError:
1429 throwError(exec, createInterruptedExecutionException(&exec->globalData()));
1431 case ValidationError:
1432 throwError(exec, createTypeError(exec, "Unable to deserialize data."));
1434 case ExistingExceptionError:
1436 case UnspecifiedError:
1439 ASSERT_NOT_REACHED();
1443 bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
1445 return (code == SuccessfullyCompleted);