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 "SharedBuffer.h"
41 #include <JavaScriptCore/APICast.h>
42 #include <runtime/DateInstance.h>
43 #include <runtime/Error.h>
44 #include <runtime/ExceptionHelpers.h>
45 #include <runtime/JSLock.h>
46 #include <runtime/PropertyNameArray.h>
47 #include <runtime/RegExp.h>
48 #include <runtime/RegExpObject.h>
49 #include <wtf/ByteArray.h>
50 #include <wtf/HashTraits.h>
51 #include <wtf/Vector.h>
56 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
57 #define ASSUME_LITTLE_ENDIAN 0
59 #define ASSUME_LITTLE_ENDIAN 1
64 static const unsigned maximumFilterRecursion = 40000;
66 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
67 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
69 // These can't be reordered, and any new types must be added to the end of the list
70 enum SerializationTag {
93 static const unsigned int CurrentVersion = 1;
94 static const unsigned int TerminatorTag = 0xFFFFFFFF;
95 static const unsigned int StringPoolTag = 0xFFFFFFFE;
98 * Object serialization is performed according to the following grammar, all tags
99 * are recorded as a single uint8_t.
101 * IndexType (used for StringData's constant pool) is the sized unsigned integer type
102 * required to represent the maximum index in the constant pool.
104 * SerializedValue :- <CurrentVersion:uint32_t> Value
105 * Value :- Array | Object | Terminal
108 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
111 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
116 * | IntTag <value:int32_t>
119 * | DoubleTag <value:double>
120 * | DateTag <value:double>
130 * StringTag StringData
133 * StringPoolTag <cpIndex:IndexType>
134 * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
140 * <path:StringData> <url:StringData> <type:StringData>
143 * FileListTag <length:uint32_t>(<file:FileData>){length}
146 * ImageDataTag <width:uint32_t><height:uint32_t><length:uint32_t><data:uint8_t{length}>
149 * BlobTag <url:StringData><type:StringData><size:long long>
152 * RegExpTag <pattern:StringData><flags:StringData>
157 CloneBase(ExecState* exec)
160 , m_timeoutChecker(exec->globalData().timeoutChecker)
164 bool shouldTerminate()
166 return m_exec->hadException();
169 unsigned ticksUntilNextCheck()
171 return m_timeoutChecker.ticksUntilNextCheck();
176 return m_timeoutChecker.didTimeOut(m_exec);
179 void throwStackOverflow()
181 throwError(m_exec, createStackOverflowError(m_exec));
184 void throwInterruptedException()
186 throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
191 ASSERT_NOT_REACHED();
197 TimeoutChecker m_timeoutChecker;
198 MarkedArgumentBuffer m_gcBuffer;
201 class CloneSerializer : CloneBase {
203 static bool serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out)
205 CloneSerializer serializer(exec, out);
206 return serializer.serialize(value);
209 static bool serialize(String s, Vector<uint8_t>& out)
211 writeLittleEndian(out, CurrentVersion);
213 writeLittleEndian<uint8_t>(out, EmptyStringTag);
216 writeLittleEndian<uint8_t>(out, StringTag);
217 writeLittleEndian(out, s.length());
218 return writeLittleEndian(out, s.impl()->characters(), s.length());
222 CloneSerializer(ExecState* exec, Vector<uint8_t>& out)
225 , m_emptyIdentifier(exec, UString("", 0))
227 write(CurrentVersion);
230 bool serialize(JSValue in);
232 bool isArray(JSValue value)
234 if (!value.isObject())
236 JSObject* object = asObject(value);
237 return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info);
240 bool startObject(JSObject* object)
243 if (!m_cycleDetector.add(object).second) {
244 throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
247 m_gcBuffer.append(object);
253 bool startArray(JSArray* array)
256 if (!m_cycleDetector.add(array).second) {
257 throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
260 m_gcBuffer.append(array);
261 unsigned length = array->length();
267 void endObject(JSObject* object)
269 write(TerminatorTag);
270 m_cycleDetector.remove(object);
271 m_gcBuffer.removeLast();
274 JSValue getSparseIndex(JSArray* array, unsigned propertyName, bool& hasIndex)
276 PropertySlot slot(array);
277 if (isJSArray(&m_exec->globalData(), array)) {
278 if (array->JSArray::getOwnPropertySlot(m_exec, propertyName, slot)) {
280 return slot.getValue(m_exec, propertyName);
282 } else if (array->getOwnPropertySlot(m_exec, propertyName, slot)) {
284 return slot.getValue(m_exec, propertyName);
290 JSValue getProperty(JSObject* object, const Identifier& propertyName)
292 PropertySlot slot(object);
293 if (object->getOwnPropertySlot(m_exec, propertyName, slot))
294 return slot.getValue(m_exec, propertyName);
298 void dumpImmediate(JSValue value)
302 else if (value.isUndefined())
304 else if (value.isNumber()) {
305 if (value.isInt32()) {
306 if (!value.asInt32())
308 else if (value.asInt32() == 1)
312 write(static_cast<uint32_t>(value.asInt32()));
316 write(value.asDouble());
318 } else if (value.isBoolean()) {
326 void dumpString(UString str)
329 write(EmptyStringTag);
336 bool dumpIfTerminal(JSValue value)
338 if (!value.isCell()) {
339 dumpImmediate(value);
343 if (value.isString()) {
344 UString str = asString(value)->value(m_exec);
349 if (value.isNumber()) {
351 write(value.uncheckedGetNumber());
355 if (value.isObject() && asObject(value)->inherits(&DateInstance::info)) {
357 write(asDateInstance(value)->internalNumber());
364 if (value.isObject()) {
365 JSObject* obj = asObject(value);
366 if (obj->inherits(&JSFile::s_info)) {
371 if (obj->inherits(&JSFileList::s_info)) {
372 FileList* list = toFileList(obj);
374 unsigned length = list->length();
376 for (unsigned i = 0; i < length; i++)
377 write(list->item(i));
380 if (obj->inherits(&JSBlob::s_info)) {
382 Blob* blob = toBlob(obj);
388 if (obj->inherits(&JSImageData::s_info)) {
389 ImageData* data = toImageData(obj);
391 write(data->width());
392 write(data->height());
393 write(data->data()->length());
394 write(data->data()->data()->data(), data->data()->length());
397 if (obj->inherits(&RegExpObject::info)) {
398 RegExpObject* regExp = asRegExpObject(obj);
401 if (regExp->regExp()->global())
402 flags[flagCount++] = 'g';
403 if (regExp->regExp()->ignoreCase())
404 flags[flagCount++] = 'i';
405 if (regExp->regExp()->multiline())
406 flags[flagCount++] = 'm';
408 write(regExp->regExp()->pattern());
409 write(UString(flags, flagCount));
414 if (getCallData(value, unusedData) == CallTypeNone)
417 // Any other types are expected to serialize as null.
422 void write(SerializationTag tag)
424 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
427 void write(uint8_t c)
429 writeLittleEndian(m_buffer, c);
432 #if ASSUME_LITTLE_ENDIAN
433 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
436 buffer.append(value);
438 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
441 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
443 for (unsigned i = 0; i < sizeof(T); i++) {
444 buffer.append(value & 0xFF);
450 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
452 if (length > numeric_limits<uint32_t>::max() / sizeof(T))
455 #if ASSUME_LITTLE_ENDIAN
456 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
458 for (unsigned i = 0; i < length; i++) {
460 for (unsigned j = 0; j < sizeof(T); j++) {
461 buffer.append(static_cast<uint8_t>(value & 0xFF));
469 void write(uint32_t i)
471 writeLittleEndian(m_buffer, i);
481 writeLittleEndian(m_buffer, u.i);
484 void write(unsigned long long i)
486 writeLittleEndian(m_buffer, i);
489 void write(uint16_t ch)
491 writeLittleEndian(m_buffer, ch);
494 void writeStringIndex(unsigned i)
496 if (m_constantPool.size() <= 0xFF)
497 write(static_cast<uint8_t>(i));
498 else if (m_constantPool.size() <= 0xFFFF)
499 write(static_cast<uint16_t>(i));
501 write(static_cast<uint32_t>(i));
504 void write(const Identifier& ident)
506 UString str = ident.ustring();
507 pair<ConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
509 write(StringPoolTag);
510 writeStringIndex(iter.first->second);
514 // This condition is unlikely to happen as they would imply an ~8gb
515 // string but we should guard against it anyway
516 if (str.length() >= StringPoolTag) {
521 // Guard against overflow
522 if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
527 writeLittleEndian<uint32_t>(m_buffer, str.length());
528 if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
532 void write(const UString& str)
535 write(m_emptyIdentifier);
537 write(Identifier(m_exec, str));
540 void write(const String& str)
543 write(m_emptyIdentifier);
545 write(Identifier(m_exec, str.impl()));
548 void write(const File* file)
555 void write(const uint8_t* data, unsigned length)
557 m_buffer.append(data, length);
560 Vector<uint8_t>& m_buffer;
561 HashSet<JSObject*> m_cycleDetector;
562 typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> ConstantPool;
563 ConstantPool m_constantPool;
564 Identifier m_emptyIdentifier;
567 bool CloneSerializer::serialize(JSValue in)
569 Vector<uint32_t, 16> indexStack;
570 Vector<uint32_t, 16> lengthStack;
571 Vector<PropertyNameArray, 16> propertyStack;
572 Vector<JSObject*, 16> inputObjectStack;
573 Vector<JSArray*, 16> inputArrayStack;
574 Vector<WalkerState, 16> stateStack;
575 WalkerState state = StateUnknown;
576 JSValue inValue = in;
577 unsigned tickCount = ticksUntilNextCheck();
581 case ArrayStartState: {
582 ASSERT(isArray(inValue));
583 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
584 throwStackOverflow();
588 JSArray* inArray = asArray(inValue);
589 unsigned length = inArray->length();
590 if (!startArray(inArray))
592 inputArrayStack.append(inArray);
593 indexStack.append(0);
594 lengthStack.append(length);
597 arrayStartVisitMember:
598 case ArrayStartVisitMember: {
601 throwInterruptedException();
604 tickCount = ticksUntilNextCheck();
607 JSArray* array = inputArrayStack.last();
608 uint32_t index = indexStack.last();
609 if (index == lengthStack.last()) {
611 inputArrayStack.removeLast();
612 indexStack.removeLast();
613 lengthStack.removeLast();
616 if (array->canGetIndex(index))
617 inValue = array->getIndex(index);
619 bool hasIndex = false;
620 inValue = getSparseIndex(array, index, hasIndex);
623 goto arrayStartVisitMember;
628 if (dumpIfTerminal(inValue)) {
630 goto arrayStartVisitMember;
632 stateStack.append(ArrayEndVisitMember);
635 case ArrayEndVisitMember: {
637 goto arrayStartVisitMember;
640 case ObjectStartState: {
641 ASSERT(inValue.isObject());
642 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
643 throwStackOverflow();
646 JSObject* inObject = asObject(inValue);
647 if (!startObject(inObject))
649 inputObjectStack.append(inObject);
650 indexStack.append(0);
651 propertyStack.append(PropertyNameArray(m_exec));
652 inObject->getOwnPropertyNames(m_exec, propertyStack.last());
655 objectStartVisitMember:
656 case ObjectStartVisitMember: {
659 throwInterruptedException();
662 tickCount = ticksUntilNextCheck();
665 JSObject* object = inputObjectStack.last();
666 uint32_t index = indexStack.last();
667 PropertyNameArray& properties = propertyStack.last();
668 if (index == properties.size()) {
670 inputObjectStack.removeLast();
671 indexStack.removeLast();
672 propertyStack.removeLast();
675 inValue = getProperty(object, properties[index]);
676 if (shouldTerminate())
680 // Property was removed during serialisation
682 goto objectStartVisitMember;
684 write(properties[index]);
686 if (shouldTerminate())
689 if (!dumpIfTerminal(inValue)) {
690 stateStack.append(ObjectEndVisitMember);
695 case ObjectEndVisitMember: {
696 if (shouldTerminate())
700 goto objectStartVisitMember;
704 if (dumpIfTerminal(inValue))
707 if (isArray(inValue))
708 goto arrayStartState;
709 goto objectStartState;
711 if (stateStack.isEmpty())
714 state = stateStack.last();
715 stateStack.removeLast();
719 throwInterruptedException();
722 tickCount = ticksUntilNextCheck();
731 class CloneDeserializer : CloneBase {
733 static String deserializeString(const Vector<uint8_t>& buffer)
735 const uint8_t* ptr = buffer.begin();
736 const uint8_t* end = buffer.end();
738 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
741 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
744 if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
747 if (!readString(ptr, end, str, length))
749 return String(str.impl());
752 static JSValue deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
756 CloneDeserializer deserializer(exec, globalObject, buffer);
757 if (!deserializer.isValid()) {
758 deserializer.throwValidationError();
761 return deserializer.deserialize();
765 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
767 , m_globalObject(globalObject)
768 , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
769 , m_ptr(buffer.data())
770 , m_end(buffer.data() + buffer.size())
771 , m_version(0xFFFFFFFF)
773 if (!read(m_version))
774 m_version = 0xFFFFFFFF;
777 JSValue deserialize();
779 void throwValidationError()
781 throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
784 bool isValid() const { return m_version <= CurrentVersion; }
786 template <typename T> bool readLittleEndian(T& value)
788 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
794 #if ASSUME_LITTLE_ENDIAN
795 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
797 if (ptr > end - sizeof(value))
803 value = *reinterpret_cast<const T*>(ptr);
809 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
811 if (ptr > end - sizeof(value))
818 for (unsigned i = 0; i < sizeof(T); i++)
819 value += ((T)*ptr++) << (i * 8);
825 bool read(uint32_t& i)
827 return readLittleEndian(i);
830 bool read(int32_t& i)
832 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
835 bool read(uint16_t& i)
837 return readLittleEndian(i);
840 bool read(uint8_t& i)
842 return readLittleEndian(i);
851 if (!readLittleEndian(u.i64))
857 bool read(unsigned long long& i)
859 return readLittleEndian(i);
862 bool readStringIndex(uint32_t& i)
864 if (m_constantPool.size() <= 0xFF) {
871 if (m_constantPool.size() <= 0xFFFF) {
881 static bool readString(const uint8_t*& ptr, const uint8_t* end, UString& str, unsigned length)
883 if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
886 unsigned size = length * sizeof(UChar);
887 if ((end - ptr) < static_cast<int>(size))
890 #if ASSUME_LITTLE_ENDIAN
891 str = UString(reinterpret_cast<const UChar*>(ptr), length);
892 ptr += length * sizeof(UChar);
894 Vector<UChar> buffer;
895 buffer.reserveCapacity(length);
896 for (unsigned i = 0; i < length; i++) {
898 readLittleEndian(ptr, end, ch);
901 str = UString::adopt(buffer);
906 bool readStringData(Identifier& ident)
909 return readStringData(ident, scratch);
912 bool readStringData(Identifier& ident, bool& wasTerminator)
919 if (length == TerminatorTag) {
920 wasTerminator = true;
923 if (length == StringPoolTag) {
925 if (!readStringIndex(index)) {
929 if (index >= m_constantPool.size()) {
933 ident = m_constantPool[index];
937 if (!readString(m_ptr, m_end, str, length)) {
941 ident = Identifier(m_exec, str);
942 m_constantPool.append(ident);
946 SerializationTag readTag()
950 return static_cast<SerializationTag>(*m_ptr++);
953 void putProperty(JSArray* array, unsigned index, JSValue value)
955 if (array->canSetIndex(index))
956 array->setIndex(index, value);
958 array->put(m_exec, index, value);
961 void putProperty(JSObject* object, Identifier& property, JSValue value)
963 object->putDirect(property, value);
966 bool readFile(RefPtr<File>& file)
969 if (!readStringData(path))
972 if (!readStringData(url))
975 if (!readStringData(type))
977 if (m_isDOMGlobalObject) {
978 ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
979 file = File::create(scriptExecutionContext, String(path.ustring().impl()), KURL(KURL(), String(url.ustring().impl())), String(type.ustring().impl()));
984 JSValue readTerminal()
986 SerializationTag tag = readTag();
989 return jsUndefined();
996 return jsNumber(m_exec, i);
999 return jsNumber(m_exec, 0);
1001 return jsNumber(m_exec, 1);
1003 return jsBoolean(false);
1005 return jsBoolean(true);
1010 return jsNumber(m_exec, d);
1016 return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), d);
1020 if (!readFile(file))
1022 if (!m_isDOMGlobalObject)
1024 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), file.get());
1027 unsigned length = 0;
1030 RefPtr<FileList> result = FileList::create();
1031 for (unsigned i = 0; i < length; i++) {
1033 if (!readFile(file))
1035 if (m_isDOMGlobalObject)
1036 result->append(file.get());
1038 if (!m_isDOMGlobalObject)
1040 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1042 case ImageDataTag: {
1052 if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1056 if (!m_isDOMGlobalObject) {
1060 RefPtr<ImageData> result = ImageData::create(width, height);
1061 memcpy(result->data()->data()->data(), m_ptr, length);
1063 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1067 if (!readStringData(url))
1070 if (!readStringData(type))
1072 unsigned long long size = 0;
1075 if (!m_isDOMGlobalObject)
1077 ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
1078 ASSERT(scriptExecutionContext);
1079 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(scriptExecutionContext, KURL(KURL(), url.ustring().impl()), String(type.ustring().impl()), size));
1083 if (!readStringData(ident))
1085 return jsString(m_exec, ident.ustring());
1087 case EmptyStringTag:
1088 return jsEmptyString(&m_exec->globalData());
1091 if (!readStringData(pattern))
1094 if (!readStringData(flags))
1096 RefPtr<RegExp> regExp = RegExp::create(&m_exec->globalData(), pattern.ustring(), flags.ustring());
1097 return new (m_exec) RegExpObject(m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp);
1100 m_ptr--; // Push the tag back
1105 JSGlobalObject* m_globalObject;
1106 bool m_isDOMGlobalObject;
1107 const uint8_t* m_ptr;
1108 const uint8_t* m_end;
1110 Vector<Identifier> m_constantPool;
1113 JSValue CloneDeserializer::deserialize()
1115 Vector<uint32_t, 16> indexStack;
1116 Vector<Identifier, 16> propertyNameStack;
1117 Vector<JSObject*, 16> outputObjectStack;
1118 Vector<JSArray*, 16> outputArrayStack;
1119 Vector<WalkerState, 16> stateStack;
1120 WalkerState state = StateUnknown;
1123 unsigned tickCount = ticksUntilNextCheck();
1127 case ArrayStartState: {
1129 if (!read(length)) {
1133 JSArray* outArray = constructEmptyArray(m_exec, m_globalObject);
1134 outArray->setLength(length);
1135 m_gcBuffer.append(outArray);
1136 outputArrayStack.append(outArray);
1139 arrayStartVisitMember:
1140 case ArrayStartVisitMember: {
1143 throwInterruptedException();
1146 tickCount = ticksUntilNextCheck();
1154 if (index == TerminatorTag) {
1155 JSArray* outArray = outputArrayStack.last();
1156 m_gcBuffer.removeLast();
1157 outValue = outArray;
1158 outputArrayStack.removeLast();
1162 if (JSValue terminal = readTerminal()) {
1163 putProperty(outputArrayStack.last(), index, terminal);
1164 goto arrayStartVisitMember;
1168 indexStack.append(index);
1169 stateStack.append(ArrayEndVisitMember);
1172 case ArrayEndVisitMember: {
1173 JSArray* outArray = outputArrayStack.last();
1174 putProperty(outArray, indexStack.last(), outValue);
1175 indexStack.removeLast();
1176 goto arrayStartVisitMember;
1179 case ObjectStartState: {
1180 if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion) {
1181 throwStackOverflow();
1184 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject);
1185 m_gcBuffer.append(outObject);
1186 outputObjectStack.append(outObject);
1189 objectStartVisitMember:
1190 case ObjectStartVisitMember: {
1193 throwInterruptedException();
1196 tickCount = ticksUntilNextCheck();
1200 bool wasTerminator = false;
1201 if (!readStringData(ident, wasTerminator)) {
1204 JSObject* outObject = outputObjectStack.last();
1205 m_gcBuffer.removeLast();
1206 outValue = outObject;
1207 outputObjectStack.removeLast();
1211 if (JSValue terminal = readTerminal()) {
1212 putProperty(outputObjectStack.last(), ident, terminal);
1213 goto objectStartVisitMember;
1215 stateStack.append(ObjectEndVisitMember);
1216 propertyNameStack.append(ident);
1219 case ObjectEndVisitMember: {
1220 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1221 propertyNameStack.removeLast();
1222 goto objectStartVisitMember;
1226 if (JSValue terminal = readTerminal()) {
1227 outValue = terminal;
1230 SerializationTag tag = readTag();
1231 if (tag == ArrayTag)
1232 goto arrayStartState;
1233 if (tag == ObjectTag)
1234 goto objectStartState;
1237 if (stateStack.isEmpty())
1240 state = stateStack.last();
1241 stateStack.removeLast();
1245 throwInterruptedException();
1248 tickCount = ticksUntilNextCheck();
1256 throwValidationError();
1262 SerializedScriptValue::~SerializedScriptValue()
1266 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1268 m_data.swap(buffer);
1271 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value)
1273 Vector<uint8_t> buffer;
1274 if (!CloneSerializer::serialize(exec, value, buffer))
1276 return adoptRef(new SerializedScriptValue(buffer));
1279 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1281 Vector<uint8_t> buffer;
1282 return adoptRef(new SerializedScriptValue(buffer));
1285 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(String string)
1287 Vector<uint8_t> buffer;
1288 if (!CloneSerializer::serialize(string, buffer))
1290 return adoptRef(new SerializedScriptValue(buffer));
1293 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
1295 JSLock lock(SilenceAssertionsOnly);
1296 ExecState* exec = toJS(originContext);
1297 JSValue value = toJS(exec, apiValue);
1298 PassRefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value);
1299 if (exec->hadException()) {
1301 *exception = toRef(exec, exec->exception());
1302 exec->clearException();
1305 ASSERT(serializedValue);
1306 return serializedValue;
1309 String SerializedScriptValue::toString()
1311 return CloneDeserializer::deserializeString(m_data);
1314 JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject)
1316 return CloneDeserializer::deserialize(exec, globalObject, m_data);
1319 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
1321 JSLock lock(SilenceAssertionsOnly);
1322 ExecState* exec = toJS(destinationContext);
1323 JSValue value = deserialize(exec, exec->lexicalGlobalObject());
1324 if (exec->hadException()) {
1326 *exception = toRef(exec, exec->exception());
1327 exec->clearException();
1331 return toRef(exec, value);
1334 SerializedScriptValue* SerializedScriptValue::nullValue()
1336 DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, emptyValue, (SerializedScriptValue::create()));
1337 return emptyValue.get();