Pass VM instead of JSGlobalObject to RegExp constructor.
[WebKit-https.git] / Source / WebCore / bindings / js / SerializedScriptValue.cpp
1 /*
2  * Copyright (C) 2009, 2013 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 "Blob.h"
31 #include "ExceptionCode.h"
32 #include "File.h"
33 #include "FileList.h"
34 #include "ImageData.h"
35 #include "JSBlob.h"
36 #include "JSDOMGlobalObject.h"
37 #include "JSFile.h"
38 #include "JSFileList.h"
39 #include "JSImageData.h"
40 #include "JSMessagePort.h"
41 #include "JSNavigator.h"
42 #include "NotImplemented.h"
43 #include "ScriptValue.h"
44 #include "SharedBuffer.h"
45 #include "WebCoreJSClientData.h"
46 #include <limits>
47 #include <JavaScriptCore/APICast.h>
48 #include <JavaScriptCore/APIShims.h>
49 #include <runtime/ArrayBuffer.h>
50 #include <runtime/BooleanObject.h>
51 #include <runtime/DateInstance.h>
52 #include <runtime/Error.h>
53 #include <runtime/ExceptionHelpers.h>
54 #include <runtime/JSArrayBuffer.h>
55 #include <runtime/JSArrayBufferView.h>
56 #include <runtime/JSDataView.h>
57 #include <runtime/JSMap.h>
58 #include <runtime/JSSet.h>
59 #include <runtime/JSTypedArrays.h>
60 #include <runtime/MapData.h>
61 #include <runtime/ObjectConstructor.h>
62 #include <runtime/Operations.h>
63 #include <runtime/PropertyNameArray.h>
64 #include <runtime/RegExp.h>
65 #include <runtime/RegExpObject.h>
66 #include <runtime/TypedArrayInlines.h>
67 #include <runtime/TypedArrays.h>
68 #include <wtf/HashTraits.h>
69 #include <wtf/Vector.h>
70
71 using namespace JSC;
72 using namespace std;
73
74 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
75 #define ASSUME_LITTLE_ENDIAN 0
76 #else
77 #define ASSUME_LITTLE_ENDIAN 1
78 #endif
79
80 namespace WebCore {
81
82 static const unsigned maximumFilterRecursion = 40000;
83
84 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
85     ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
86     MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue };
87
88 // These can't be reordered, and any new types must be added to the end of the list
89 enum SerializationTag {
90     ArrayTag = 1,
91     ObjectTag = 2,
92     UndefinedTag = 3,
93     NullTag = 4,
94     IntTag = 5,
95     ZeroTag = 6,
96     OneTag = 7,
97     FalseTag = 8,
98     TrueTag = 9,
99     DoubleTag = 10,
100     DateTag = 11,
101     FileTag = 12,
102     FileListTag = 13,
103     ImageDataTag = 14,
104     BlobTag = 15,
105     StringTag = 16,
106     EmptyStringTag = 17,
107     RegExpTag = 18,
108     ObjectReferenceTag = 19,
109     MessagePortReferenceTag = 20,
110     ArrayBufferTag = 21,
111     ArrayBufferViewTag = 22,
112     ArrayBufferTransferTag = 23,
113     TrueObjectTag = 24,
114     FalseObjectTag = 25,
115     StringObjectTag = 26,
116     EmptyStringObjectTag = 27,
117     NumberObjectTag = 28,
118     SetObjectTag = 29,
119     MapObjectTag = 30,
120     NonMapPropertiesTag = 31,
121     ErrorTag = 255
122 };
123
124 enum ArrayBufferViewSubtag {
125     DataViewTag = 0,
126     Int8ArrayTag = 1,
127     Uint8ArrayTag = 2,
128     Uint8ClampedArrayTag = 3,
129     Int16ArrayTag = 4,
130     Uint16ArrayTag = 5,
131     Int32ArrayTag = 6,
132     Uint32ArrayTag = 7,
133     Float32ArrayTag = 8,
134     Float64ArrayTag = 9
135 };
136
137 static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
138 {
139     switch (tag) {
140     case DataViewTag:
141     case Int8ArrayTag:
142     case Uint8ArrayTag:
143     case Uint8ClampedArrayTag:
144         return 1;
145     case Int16ArrayTag:
146     case Uint16ArrayTag:
147         return 2;
148     case Int32ArrayTag:
149     case Uint32ArrayTag:
150     case Float32ArrayTag:
151         return 4;
152     case Float64ArrayTag:
153         return 8;
154     default:
155         return 0;
156     }
157
158 }
159
160 /* CurrentVersion tracks the serialization version so that persistant stores
161  * are able to correctly bail out in the case of encountering newer formats.
162  *
163  * Initial version was 1.
164  * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
165  * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
166  * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
167  * Version 4. added support for serializing non-index properties of arrays.
168  * Version 5. added support for Map and Set types.
169  */
170 static const unsigned CurrentVersion = 5;
171 static const unsigned TerminatorTag = 0xFFFFFFFF;
172 static const unsigned StringPoolTag = 0xFFFFFFFE;
173 static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
174
175 /*
176  * Object serialization is performed according to the following grammar, all tags
177  * are recorded as a single uint8_t.
178  *
179  * IndexType (used for the object pool and StringData's constant pool) is the
180  * minimum sized unsigned integer type required to represent the maximum index
181  * in the constant pool.
182  *
183  * SerializedValue :- <CurrentVersion:uint32_t> Value
184  * Value :- Array | Object | Map | Set | Terminal
185  *
186  * Array :-
187  *     ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
188  *
189  * Object :-
190  *     ObjectTag (<name:StringData><value:Value>)* TerminatorTag
191  *
192  * Map :- MapObjectTag MapData
193  *
194  * Set :- SetObjectTag MapData
195  *
196  * MapData :- (<key:Value><value:Value>) NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
197  *
198  * Terminal :-
199  *      UndefinedTag
200  *    | NullTag
201  *    | IntTag <value:int32_t>
202  *    | ZeroTag
203  *    | OneTag
204  *    | FalseTag
205  *    | TrueTag
206  *    | FalseObjectTag
207  *    | TrueObjectTag
208  *    | DoubleTag <value:double>
209  *    | NumberObjectTag <value:double>
210  *    | DateTag <value:double>
211  *    | String
212  *    | EmptyStringTag
213  *    | EmptyStringObjectTag
214  *    | File
215  *    | FileList
216  *    | ImageData
217  *    | Blob
218  *    | ObjectReference
219  *    | MessagePortReferenceTag <value:uint32_t>
220  *    | ArrayBuffer
221  *    | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLenght:uint32_t> (ArrayBuffer | ObjectReference)
222  *    | ArrayBufferTransferTag <value:uint32_t>
223  *
224  * String :-
225  *      EmptyStringTag
226  *      StringTag StringData
227  *
228  * StringObject:
229  *      EmptyStringObjectTag
230  *      StringObjectTag StringData
231  *
232  * StringData :-
233  *      StringPoolTag <cpIndex:IndexType>
234  *      (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
235  *
236  * File :-
237  *    FileTag FileData
238  *
239  * FileData :-
240  *    <path:StringData> <url:StringData> <type:StringData>
241  *
242  * FileList :-
243  *    FileListTag <length:uint32_t>(<file:FileData>){length}
244  *
245  * ImageData :-
246  *    ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
247  *
248  * Blob :-
249  *    BlobTag <url:StringData><type:StringData><size:long long>
250  *
251  * RegExp :-
252  *    RegExpTag <pattern:StringData><flags:StringData>
253  *
254  * ObjectReference :-
255  *    ObjectReferenceTag <opIndex:IndexType>
256  *
257  * ArrayBuffer :-
258  *    ArrayBufferTag <length:uint32_t> <contents:byte{length}>
259  */
260
261 typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
262
263 class CloneBase {
264 protected:
265     CloneBase(ExecState* exec)
266         : m_exec(exec)
267         , m_failed(false)
268     {
269     }
270
271     bool shouldTerminate()
272     {
273         return m_exec->hadException();
274     }
275
276     void throwStackOverflow()
277     {
278         m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
279     }
280
281     NO_RETURN_DUE_TO_ASSERT
282     void fail()
283     {
284         ASSERT_NOT_REACHED();
285         m_failed = true;
286     }
287
288     ExecState* m_exec;
289     bool m_failed;
290     MarkedArgumentBuffer m_gcBuffer;
291 };
292
293 #if ASSUME_LITTLE_ENDIAN
294 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
295 {
296     buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
297 }
298 #else
299 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
300 {
301     for (unsigned i = 0; i < sizeof(T); i++) {
302         buffer.append(value & 0xFF);
303         value >>= 8;
304     }
305 }
306 #endif
307
308 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
309 {
310     buffer.append(value);
311 }
312
313 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
314 {
315     if (length > numeric_limits<uint32_t>::max() / sizeof(T))
316         return false;
317
318 #if ASSUME_LITTLE_ENDIAN
319     buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
320 #else
321     for (unsigned i = 0; i < length; i++) {
322         T value = values[i];
323         for (unsigned j = 0; j < sizeof(T); j++) {
324             buffer.append(static_cast<uint8_t>(value & 0xFF));
325             value >>= 8;
326         }
327     }
328 #endif
329     return true;
330 }
331
332 class CloneSerializer : CloneBase {
333 public:
334     static SerializationReturnCode serialize(ExecState* exec, JSValue value,
335                                              MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
336                                              Vector<String>& blobURLs, Vector<uint8_t>& out)
337     {
338         CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out);
339         return serializer.serialize(value);
340     }
341
342     static bool serialize(const String& s, Vector<uint8_t>& out)
343     {
344         writeLittleEndian(out, CurrentVersion);
345         if (s.isEmpty()) {
346             writeLittleEndian<uint8_t>(out, EmptyStringTag);
347             return true;
348         }
349         writeLittleEndian<uint8_t>(out, StringTag);
350         writeLittleEndian(out, s.length());
351         return writeLittleEndian(out, s.impl()->characters(), s.length());
352     }
353
354     static void serializeUndefined(Vector<uint8_t>& out)
355     {
356         writeLittleEndian(out, CurrentVersion);
357         writeLittleEndian<uint8_t>(out, UndefinedTag);
358     }
359
360     static void serializeBoolean(bool value, Vector<uint8_t>& out)
361     {
362         writeLittleEndian(out, CurrentVersion);
363         writeLittleEndian<uint8_t>(out, value ? TrueTag : FalseTag);
364     }
365
366     static void serializeNumber(double value, Vector<uint8_t>& out)
367     {
368         writeLittleEndian(out, CurrentVersion);
369         writeLittleEndian<uint8_t>(out, DoubleTag);
370         union {
371             double d;
372             int64_t i;
373         } u;
374         u.d = value;
375         writeLittleEndian(out, u.i);
376     }
377
378 private:
379     typedef HashMap<JSObject*, uint32_t> ObjectPool;
380
381     CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
382         : CloneBase(exec)
383         , m_buffer(out)
384         , m_blobURLs(blobURLs)
385         , m_emptyIdentifier(exec, emptyString())
386     {
387         write(CurrentVersion);
388         fillTransferMap(messagePorts, m_transferredMessagePorts);
389         fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
390     }
391
392     template <class T>
393     void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result)
394     {
395         if (!input)
396             return;
397         JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
398         for (size_t i = 0; i < input->size(); i++) {
399             JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get());
400             JSC::JSObject* obj = value.getObject();
401             if (obj && !result.contains(obj))
402                 result.add(obj, i);
403         }
404     }
405
406     SerializationReturnCode serialize(JSValue in);
407
408     bool isArray(JSValue value)
409     {
410         if (!value.isObject())
411             return false;
412         JSObject* object = asObject(value);
413         return isJSArray(object) || object->inherits(JSArray::info());
414     }
415
416     bool isMap(JSValue value)
417     {
418         if (!value.isObject())
419             return false;
420         JSObject* object = asObject(value);
421         return object->inherits(JSMap::info());
422     }
423     bool isSet(JSValue value)
424     {
425         if (!value.isObject())
426             return false;
427         JSObject* object = asObject(value);
428         return object->inherits(JSSet::info());
429     }
430
431     bool checkForDuplicate(JSObject* object)
432     {
433         // Record object for graph reconstruction
434         ObjectPool::const_iterator found = m_objectPool.find(object);
435
436         // Handle duplicate references
437         if (found != m_objectPool.end()) {
438             write(ObjectReferenceTag);
439             ASSERT(static_cast<int32_t>(found->value) < m_objectPool.size());
440             writeObjectIndex(found->value);
441             return true;
442         }
443
444         return false;
445     }
446
447     void recordObject(JSObject* object)
448     {
449         m_objectPool.add(object, m_objectPool.size());
450         m_gcBuffer.append(object);
451     }
452
453     bool startObjectInternal(JSObject* object)
454     {
455         if (checkForDuplicate(object))
456             return false;
457         recordObject(object);
458         return true;
459     }
460
461     bool startObject(JSObject* object)
462     {
463         if (!startObjectInternal(object))
464             return false;
465         write(ObjectTag);
466         return true;
467     }
468
469     bool startArray(JSArray* array)
470     {
471         if (!startObjectInternal(array))
472             return false;
473
474         unsigned length = array->length();
475         write(ArrayTag);
476         write(length);
477         return true;
478     }
479
480     bool startSet(JSSet* set)
481     {
482         if (!startObjectInternal(set))
483             return false;
484
485         write(SetObjectTag);
486         return true;
487     }
488
489     bool startMap(JSMap* map)
490     {
491         if (!startObjectInternal(map))
492             return false;
493
494         write(MapObjectTag);
495         return true;
496     }
497
498     void endObject()
499     {
500         write(TerminatorTag);
501     }
502
503     JSValue getProperty(JSObject* object, const Identifier& propertyName)
504     {
505         PropertySlot slot(object);
506         if (object->methodTable()->getOwnPropertySlot(object, m_exec, propertyName, slot))
507             return slot.getValue(m_exec, propertyName);
508         return JSValue();
509     }
510
511     void dumpImmediate(JSValue value)
512     {
513         if (value.isNull())
514             write(NullTag);
515         else if (value.isUndefined())
516             write(UndefinedTag);
517         else if (value.isNumber()) {
518             if (value.isInt32()) {
519                 if (!value.asInt32())
520                     write(ZeroTag);
521                 else if (value.asInt32() == 1)
522                     write(OneTag);
523                 else {
524                     write(IntTag);
525                     write(static_cast<uint32_t>(value.asInt32()));
526                 }
527             } else {
528                 write(DoubleTag);
529                 write(value.asDouble());
530             }
531         } else if (value.isBoolean()) {
532             if (value.isTrue())
533                 write(TrueTag);
534             else
535                 write(FalseTag);
536         }
537     }
538
539     void dumpString(String str)
540     {
541         if (str.isEmpty())
542             write(EmptyStringTag);
543         else {
544             write(StringTag);
545             write(str);
546         }
547     }
548
549     void dumpStringObject(String str)
550     {
551         if (str.isEmpty())
552             write(EmptyStringObjectTag);
553         else {
554             write(StringObjectTag);
555             write(str);
556         }
557     }
558
559     bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
560     {
561         write(ArrayBufferViewTag);
562         if (obj->inherits(JSDataView::info()))
563             write(DataViewTag);
564         else if (obj->inherits(JSUint8ClampedArray::info()))
565             write(Uint8ClampedArrayTag);
566         else if (obj->inherits(JSInt8Array::info()))
567             write(Int8ArrayTag);
568         else if (obj->inherits(JSUint8Array::info()))
569             write(Uint8ArrayTag);
570         else if (obj->inherits(JSInt16Array::info()))
571             write(Int16ArrayTag);
572         else if (obj->inherits(JSUint16Array::info()))
573             write(Uint16ArrayTag);
574         else if (obj->inherits(JSInt32Array::info()))
575             write(Int32ArrayTag);
576         else if (obj->inherits(JSUint32Array::info()))
577             write(Uint32ArrayTag);
578         else if (obj->inherits(JSFloat32Array::info()))
579             write(Float32ArrayTag);
580         else if (obj->inherits(JSFloat64Array::info()))
581             write(Float64ArrayTag);
582         else
583             return false;
584
585         RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj);
586         write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
587         write(static_cast<uint32_t>(arrayBufferView->byteLength()));
588         RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
589         if (!arrayBuffer) {
590             code = ValidationError;
591             return true;
592         }
593         JSValue bufferObj = toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get());
594         return dumpIfTerminal(bufferObj, code);
595     }
596
597     bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
598     {
599         if (!value.isCell()) {
600             dumpImmediate(value);
601             return true;
602         }
603
604         if (value.isString()) {
605             String str = asString(value)->value(m_exec);
606             dumpString(str);
607             return true;
608         }
609
610         if (value.isNumber()) {
611             write(DoubleTag);
612             write(value.asNumber());
613             return true;
614         }
615
616         if (value.isObject() && asObject(value)->inherits(DateInstance::info())) {
617             write(DateTag);
618             write(asDateInstance(value)->internalNumber());
619             return true;
620         }
621
622         if (isArray(value))
623             return false;
624
625         if (value.isObject()) {
626             JSObject* obj = asObject(value);
627             if (obj->inherits(BooleanObject::info())) {
628                 if (!startObjectInternal(obj)) // handle duplicates
629                     return true;
630                 write(asBooleanObject(value)->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
631                 return true;
632             }
633             if (obj->inherits(StringObject::info())) {
634                 if (!startObjectInternal(obj)) // handle duplicates
635                     return true;
636                 String str = asString(asStringObject(value)->internalValue())->value(m_exec);
637                 dumpStringObject(str);
638                 return true;
639             }
640             if (obj->inherits(NumberObject::info())) {
641                 if (!startObjectInternal(obj)) // handle duplicates
642                     return true;
643                 write(NumberObjectTag);
644                 NumberObject* obj = static_cast<NumberObject*>(asObject(value));
645                 write(obj->internalValue().asNumber());
646                 return true;
647             }
648             if (obj->inherits(JSFile::info())) {
649                 write(FileTag);
650                 write(toFile(obj));
651                 return true;
652             }
653             if (obj->inherits(JSFileList::info())) {
654                 FileList* list = toFileList(obj);
655                 write(FileListTag);
656                 unsigned length = list->length();
657                 write(length);
658                 for (unsigned i = 0; i < length; i++)
659                     write(list->item(i));
660                 return true;
661             }
662             if (obj->inherits(JSBlob::info())) {
663                 write(BlobTag);
664                 Blob* blob = toBlob(obj);
665                 m_blobURLs.append(blob->url());
666                 write(blob->url());
667                 write(blob->type());
668                 write(blob->size());
669                 return true;
670             }
671             if (obj->inherits(JSImageData::info())) {
672                 ImageData* data = toImageData(obj);
673                 write(ImageDataTag);
674                 write(data->width());
675                 write(data->height());
676                 write(data->data()->length());
677                 write(data->data()->data(), data->data()->length());
678                 return true;
679             }
680             if (obj->inherits(RegExpObject::info())) {
681                 RegExpObject* regExp = asRegExpObject(obj);
682                 char flags[3];
683                 int flagCount = 0;
684                 if (regExp->regExp()->global())
685                     flags[flagCount++] = 'g';
686                 if (regExp->regExp()->ignoreCase())
687                     flags[flagCount++] = 'i';
688                 if (regExp->regExp()->multiline())
689                     flags[flagCount++] = 'm';
690                 write(RegExpTag);
691                 write(regExp->regExp()->pattern());
692                 write(String(flags, flagCount));
693                 return true;
694             }
695             if (obj->inherits(JSMessagePort::info())) {
696                 ObjectPool::iterator index = m_transferredMessagePorts.find(obj);
697                 if (index != m_transferredMessagePorts.end()) {
698                     write(MessagePortReferenceTag);
699                     write(index->value);
700                     return true;
701                 }
702                 // MessagePort object could not be found in transferred message ports
703                 code = ValidationError;
704                 return true;
705             }
706             if (obj->inherits(JSArrayBuffer::info())) {
707                 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(obj);
708                 if (arrayBuffer->isNeutered()) {
709                     code = ValidationError;
710                     return true;
711                 }
712                 ObjectPool::iterator index = m_transferredArrayBuffers.find(obj);
713                 if (index != m_transferredArrayBuffers.end()) {
714                     write(ArrayBufferTransferTag);
715                     write(index->value);
716                     return true;
717                 }
718                 if (!startObjectInternal(obj)) // handle duplicates
719                     return true;
720                 write(ArrayBufferTag);
721                 write(arrayBuffer->byteLength());
722                 write(static_cast<const uint8_t *>(arrayBuffer->data()), arrayBuffer->byteLength());
723                 return true;
724             }
725             if (obj->inherits(JSArrayBufferView::info())) {
726                 if (checkForDuplicate(obj))
727                     return true;
728                 bool success = dumpArrayBufferView(obj, code);
729                 recordObject(obj);
730                 return success;
731             }
732
733             return false;
734         }
735         // Any other types are expected to serialize as null.
736         write(NullTag);
737         return true;
738     }
739
740     void write(SerializationTag tag)
741     {
742         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
743     }
744
745     void write(ArrayBufferViewSubtag tag)
746     {
747         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
748     }
749
750     void write(uint8_t c)
751     {
752         writeLittleEndian(m_buffer, c);
753     }
754
755     void write(uint32_t i)
756     {
757         writeLittleEndian(m_buffer, i);
758     }
759
760     void write(double d)
761     {
762         union {
763             double d;
764             int64_t i;
765         } u;
766         u.d = d;
767         writeLittleEndian(m_buffer, u.i);
768     }
769
770     void write(int32_t i)
771     {
772         writeLittleEndian(m_buffer, i);
773     }
774
775     void write(unsigned long long i)
776     {
777         writeLittleEndian(m_buffer, i);
778     }
779     
780     void write(uint16_t ch)
781     {
782         writeLittleEndian(m_buffer, ch);
783     }
784
785     void writeStringIndex(unsigned i)
786     {
787         writeConstantPoolIndex(m_constantPool, i);
788     }
789     
790     void writeObjectIndex(unsigned i)
791     {
792         writeConstantPoolIndex(m_objectPool, i);
793     }
794
795     template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
796     {
797         ASSERT(static_cast<int32_t>(i) < constantPool.size());
798         if (constantPool.size() <= 0xFF)
799             write(static_cast<uint8_t>(i));
800         else if (constantPool.size() <= 0xFFFF)
801             write(static_cast<uint16_t>(i));
802         else
803             write(static_cast<uint32_t>(i));
804     }
805
806     void write(const Identifier& ident)
807     {
808         const String& str = ident.string();
809         StringConstantPool::AddResult addResult = m_constantPool.add(str.impl(), m_constantPool.size());
810         if (!addResult.isNewEntry) {
811             write(StringPoolTag);
812             writeStringIndex(addResult.iterator->value);
813             return;
814         }
815
816         // This condition is unlikely to happen as they would imply an ~8gb
817         // string but we should guard against it anyway
818         if (str.length() >= StringPoolTag) {
819             fail();
820             return;
821         }
822
823         // Guard against overflow
824         if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
825             fail();
826             return;
827         }
828
829         writeLittleEndian<uint32_t>(m_buffer, str.length());
830         if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
831             fail();
832     }
833
834     void write(const String& str)
835     {
836         if (str.isNull())
837             write(m_emptyIdentifier);
838         else
839             write(Identifier(m_exec, str));
840     }
841
842     void write(const File* file)
843     {
844         m_blobURLs.append(file->url());
845         write(file->path());
846         write(file->url());
847         write(file->type());
848     }
849
850     void write(const uint8_t* data, unsigned length)
851     {
852         m_buffer.append(data, length);
853     }
854
855     Vector<uint8_t>& m_buffer;
856     Vector<String>& m_blobURLs;
857     ObjectPool m_objectPool;
858     ObjectPool m_transferredMessagePorts;
859     ObjectPool m_transferredArrayBuffers;
860     typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
861     StringConstantPool m_constantPool;
862     Identifier m_emptyIdentifier;
863 };
864
865 SerializationReturnCode CloneSerializer::serialize(JSValue in)
866 {
867     Vector<uint32_t, 16> indexStack;
868     Vector<uint32_t, 16> lengthStack;
869     Vector<PropertyNameArray, 16> propertyStack;
870     Vector<JSObject*, 32> inputObjectStack;
871     Vector<MapData*, 4> mapDataStack;
872     Vector<MapData::const_iterator, 4> iteratorStack;
873     Vector<WalkerState, 16> stateStack;
874     WalkerState state = StateUnknown;
875     JSValue inValue = in;
876     while (1) {
877         switch (state) {
878             arrayStartState:
879             case ArrayStartState: {
880                 ASSERT(isArray(inValue));
881                 if (inputObjectStack.size() > maximumFilterRecursion)
882                     return StackOverflowError;
883
884                 JSArray* inArray = asArray(inValue);
885                 unsigned length = inArray->length();
886                 if (!startArray(inArray))
887                     break;
888                 inputObjectStack.append(inArray);
889                 indexStack.append(0);
890                 lengthStack.append(length);
891                 // fallthrough
892             }
893             arrayStartVisitMember:
894             case ArrayStartVisitMember: {
895                 JSObject* array = inputObjectStack.last();
896                 uint32_t index = indexStack.last();
897                 if (index == lengthStack.last()) {
898                     indexStack.removeLast();
899                     lengthStack.removeLast();
900
901                     propertyStack.append(PropertyNameArray(m_exec));
902                     array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
903                     if (propertyStack.last().size()) {
904                         write(NonIndexPropertiesTag);
905                         indexStack.append(0);
906                         goto objectStartVisitMember;
907                     }
908                     propertyStack.removeLast();
909
910                     endObject();
911                     inputObjectStack.removeLast();
912                     break;
913                 }
914                 inValue = array->getDirectIndex(m_exec, index);
915                 if (!inValue) {
916                     indexStack.last()++;
917                     goto arrayStartVisitMember;
918                 }
919
920                 write(index);
921                 SerializationReturnCode terminalCode = SuccessfullyCompleted;
922                 if (dumpIfTerminal(inValue, terminalCode)) {
923                     if (terminalCode != SuccessfullyCompleted)
924                         return terminalCode;
925                     indexStack.last()++;
926                     goto arrayStartVisitMember;
927                 }
928                 stateStack.append(ArrayEndVisitMember);
929                 goto stateUnknown;
930             }
931             case ArrayEndVisitMember: {
932                 indexStack.last()++;
933                 goto arrayStartVisitMember;
934             }
935             objectStartState:
936             case ObjectStartState: {
937                 ASSERT(inValue.isObject());
938                 if (inputObjectStack.size() > maximumFilterRecursion)
939                     return StackOverflowError;
940                 JSObject* inObject = asObject(inValue);
941                 if (!startObject(inObject))
942                     break;
943                 // At this point, all supported objects other than Object
944                 // objects have been handled. If we reach this point and
945                 // the input is not an Object object then we should throw
946                 // a DataCloneError.
947                 if (inObject->classInfo() != JSFinalObject::info())
948                     return DataCloneError;
949                 inputObjectStack.append(inObject);
950                 indexStack.append(0);
951                 propertyStack.append(PropertyNameArray(m_exec));
952                 inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
953                 // fallthrough
954             }
955             objectStartVisitMember:
956             case ObjectStartVisitMember: {
957                 JSObject* object = inputObjectStack.last();
958                 uint32_t index = indexStack.last();
959                 PropertyNameArray& properties = propertyStack.last();
960                 if (index == properties.size()) {
961                     endObject();
962                     inputObjectStack.removeLast();
963                     indexStack.removeLast();
964                     propertyStack.removeLast();
965                     break;
966                 }
967                 inValue = getProperty(object, properties[index]);
968                 if (shouldTerminate())
969                     return ExistingExceptionError;
970
971                 if (!inValue) {
972                     // Property was removed during serialisation
973                     indexStack.last()++;
974                     goto objectStartVisitMember;
975                 }
976                 write(properties[index]);
977
978                 if (shouldTerminate())
979                     return ExistingExceptionError;
980
981                 SerializationReturnCode terminalCode = SuccessfullyCompleted;
982                 if (!dumpIfTerminal(inValue, terminalCode)) {
983                     stateStack.append(ObjectEndVisitMember);
984                     goto stateUnknown;
985                 }
986                 if (terminalCode != SuccessfullyCompleted)
987                     return terminalCode;
988                 // fallthrough
989             }
990             case ObjectEndVisitMember: {
991                 if (shouldTerminate())
992                     return ExistingExceptionError;
993
994                 indexStack.last()++;
995                 goto objectStartVisitMember;
996             }
997             mapStartState: {
998                 ASSERT(inValue.isObject());
999                 if (inputObjectStack.size() > maximumFilterRecursion)
1000                     return StackOverflowError;
1001                 JSMap* inMap = jsCast<JSMap*>(inValue);
1002                 if (!startMap(inMap))
1003                     break;
1004                 MapData* mapData = inMap->mapData();
1005                 m_gcBuffer.append(mapData);
1006                 mapDataStack.append(mapData);
1007                 iteratorStack.append(mapData->begin());
1008                 inputObjectStack.append(inMap);
1009                 goto mapDataStartVisitEntry;
1010             }
1011             setStartState: {
1012                 ASSERT(inValue.isObject());
1013                 if (inputObjectStack.size() > maximumFilterRecursion)
1014                     return StackOverflowError;
1015                 JSSet* inSet = jsCast<JSSet*>(inValue);
1016                 if (!startSet(inSet))
1017                     break;
1018                 MapData* mapData = inSet->mapData();
1019                 m_gcBuffer.append(mapData);
1020                 mapDataStack.append(mapData);
1021                 iteratorStack.append(mapData->begin());
1022                 inputObjectStack.append(inSet);
1023                 goto mapDataStartVisitEntry;
1024             }
1025             mapDataStartVisitEntry:
1026             case MapDataStartVisitEntry: {
1027                 MapData::const_iterator& ptr = iteratorStack.last();
1028                 MapData* mapData = mapDataStack.last();
1029                 if (ptr == mapData->end()) {
1030                     iteratorStack.removeLast();
1031                     mapDataStack.removeLast();
1032                     JSObject* object = inputObjectStack.last();
1033                     ASSERT(jsDynamicCast<JSSet*>(object) || jsDynamicCast<JSMap*>(object));
1034                     propertyStack.append(PropertyNameArray(m_exec));
1035                     object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
1036                     write(NonMapPropertiesTag);
1037                     indexStack.append(0);
1038                     goto objectStartVisitMember;
1039                 }
1040                 inValue = ptr.key();
1041                 stateStack.append(MapDataEndVisitKey);
1042                 goto stateUnknown;
1043             }
1044             case MapDataEndVisitKey: {
1045                 inValue = iteratorStack.last().value();
1046                 stateStack.append(MapDataEndVisitValue);
1047                 goto stateUnknown;
1048             }
1049             case MapDataEndVisitValue: {
1050                 ++iteratorStack.last();
1051                 goto mapDataStartVisitEntry;
1052             }
1053
1054             stateUnknown:
1055             case StateUnknown: {
1056                 SerializationReturnCode terminalCode = SuccessfullyCompleted;
1057                 if (dumpIfTerminal(inValue, terminalCode)) {
1058                     if (terminalCode != SuccessfullyCompleted)
1059                         return terminalCode;
1060                     break;
1061                 }
1062
1063                 if (isArray(inValue))
1064                     goto arrayStartState;
1065                 if (isMap(inValue))
1066                     goto mapStartState;
1067                 if (isSet(inValue))
1068                     goto setStartState;
1069                 goto objectStartState;
1070             }
1071         }
1072         if (stateStack.isEmpty())
1073             break;
1074
1075         state = stateStack.last();
1076         stateStack.removeLast();
1077     }
1078     if (m_failed)
1079         return UnspecifiedError;
1080
1081     return SuccessfullyCompleted;
1082 }
1083
1084 typedef Vector<JSC::ArrayBufferContents> ArrayBufferContentsArray;
1085
1086 class CloneDeserializer : CloneBase {
1087 public:
1088     static String deserializeString(const Vector<uint8_t>& buffer)
1089     {
1090         const uint8_t* ptr = buffer.begin();
1091         const uint8_t* end = buffer.end();
1092         uint32_t version;
1093         if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1094             return String();
1095         uint8_t tag;
1096         if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1097             return String();
1098         uint32_t length;
1099         if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
1100             return String();
1101         String str;
1102         if (!readString(ptr, end, str, length))
1103             return String();
1104         return String(str.impl());
1105     }
1106
1107     static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
1108                                              MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
1109                                              const Vector<uint8_t>& buffer)
1110     {
1111         if (!buffer.size())
1112             return make_pair(jsNull(), UnspecifiedError);
1113         CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
1114         if (!deserializer.isValid())
1115             return make_pair(JSValue(), ValidationError);
1116         return deserializer.deserialize();
1117     }
1118
1119 private:
1120     struct CachedString {
1121         CachedString(const String& string)
1122             : m_string(string)
1123         {
1124         }
1125
1126         JSValue jsString(ExecState* exec)
1127         {
1128             if (!m_jsString)
1129                 m_jsString = JSC::jsString(exec, m_string);
1130             return m_jsString;
1131         }
1132         const String& string() { return m_string; }
1133
1134     private:
1135         String m_string;
1136         JSValue m_jsString;
1137     };
1138
1139     struct CachedStringRef {
1140         CachedStringRef()
1141             : m_base(0)
1142             , m_index(0)
1143         {
1144         }
1145         CachedStringRef(Vector<CachedString>* base, size_t index)
1146             : m_base(base)
1147             , m_index(index)
1148         {
1149         }
1150         
1151         CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1152         
1153     private:
1154         Vector<CachedString>* m_base;
1155         size_t m_index;
1156     };
1157
1158     CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, 
1159                       MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
1160                       const Vector<uint8_t>& buffer)
1161         : CloneBase(exec)
1162         , m_globalObject(globalObject)
1163         , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info()))
1164         , m_ptr(buffer.data())
1165         , m_end(buffer.data() + buffer.size())
1166         , m_version(0xFFFFFFFF)
1167         , m_messagePorts(messagePorts)
1168         , m_arrayBufferContents(arrayBufferContents)
1169         , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1170     {
1171         if (!read(m_version))
1172             m_version = 0xFFFFFFFF;
1173     }
1174
1175     DeserializationResult deserialize();
1176
1177     void throwValidationError()
1178     {
1179         m_exec->vm().throwException(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
1180     }
1181
1182     bool isValid() const { return m_version <= CurrentVersion; }
1183
1184     template <typename T> bool readLittleEndian(T& value)
1185     {
1186         if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1187             fail();
1188             return false;
1189         }
1190         return true;
1191     }
1192 #if ASSUME_LITTLE_ENDIAN
1193     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1194     {
1195         if (ptr > end - sizeof(value))
1196             return false;
1197
1198         if (sizeof(T) == 1)
1199             value = *ptr++;
1200         else {
1201             value = *reinterpret_cast<const T*>(ptr);
1202             ptr += sizeof(T);
1203         }
1204         return true;
1205     }
1206 #else
1207     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1208     {
1209         if (ptr > end - sizeof(value))
1210             return false;
1211
1212         if (sizeof(T) == 1)
1213             value = *ptr++;
1214         else {
1215             value = 0;
1216             for (unsigned i = 0; i < sizeof(T); i++)
1217                 value += ((T)*ptr++) << (i * 8);
1218         }
1219         return true;
1220     }
1221 #endif
1222
1223     bool read(uint32_t& i)
1224     {
1225         return readLittleEndian(i);
1226     }
1227
1228     bool read(int32_t& i)
1229     {
1230         return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1231     }
1232
1233     bool read(uint16_t& i)
1234     {
1235         return readLittleEndian(i);
1236     }
1237
1238     bool read(uint8_t& i)
1239     {
1240         return readLittleEndian(i);
1241     }
1242
1243     bool read(double& d)
1244     {
1245         union {
1246             double d;
1247             uint64_t i64;
1248         } u;
1249         if (!readLittleEndian(u.i64))
1250             return false;
1251         d = u.d;
1252         return true;
1253     }
1254
1255     bool read(unsigned long long& i)
1256     {
1257         return readLittleEndian(i);
1258     }
1259
1260     bool readStringIndex(uint32_t& i)
1261     {
1262         return readConstantPoolIndex(m_constantPool, i);
1263     }
1264
1265     template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1266     {
1267         if (constantPool.size() <= 0xFF) {
1268             uint8_t i8;
1269             if (!read(i8))
1270                 return false;
1271             i = i8;
1272             return true;
1273         }
1274         if (constantPool.size() <= 0xFFFF) {
1275             uint16_t i16;
1276             if (!read(i16))
1277                 return false;
1278             i = i16;
1279             return true;
1280         }
1281         return read(i);
1282     }
1283
1284     static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length)
1285     {
1286         if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
1287             return false;
1288
1289         unsigned size = length * sizeof(UChar);
1290         if ((end - ptr) < static_cast<int>(size))
1291             return false;
1292
1293 #if ASSUME_LITTLE_ENDIAN
1294         str = String(reinterpret_cast<const UChar*>(ptr), length);
1295         ptr += length * sizeof(UChar);
1296 #else
1297         Vector<UChar> buffer;
1298         buffer.reserveCapacity(length);
1299         for (unsigned i = 0; i < length; i++) {
1300             uint16_t ch;
1301             readLittleEndian(ptr, end, ch);
1302             buffer.append(ch);
1303         }
1304         str = String::adopt(buffer);
1305 #endif
1306         return true;
1307     }
1308
1309     bool readStringData(CachedStringRef& cachedString)
1310     {
1311         bool scratch;
1312         return readStringData(cachedString, scratch);
1313     }
1314
1315     bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
1316     {
1317         if (m_failed)
1318             return false;
1319         uint32_t length = 0;
1320         if (!read(length))
1321             return false;
1322         if (length == TerminatorTag) {
1323             wasTerminator = true;
1324             return false;
1325         }
1326         if (length == StringPoolTag) {
1327             unsigned index = 0;
1328             if (!readStringIndex(index)) {
1329                 fail();
1330                 return false;
1331             }
1332             if (index >= m_constantPool.size()) {
1333                 fail();
1334                 return false;
1335             }
1336             cachedString = CachedStringRef(&m_constantPool, index);
1337             return true;
1338         }
1339         String str;
1340         if (!readString(m_ptr, m_end, str, length)) {
1341             fail();
1342             return false;
1343         }
1344         m_constantPool.append(str);
1345         cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
1346         return true;
1347     }
1348
1349     SerializationTag readTag()
1350     {
1351         if (m_ptr >= m_end)
1352             return ErrorTag;
1353         return static_cast<SerializationTag>(*m_ptr++);
1354     }
1355
1356     bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
1357     {
1358         if (m_ptr >= m_end)
1359             return false;
1360         tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
1361         return true;
1362     }
1363
1364     void putProperty(JSObject* object, unsigned index, JSValue value)
1365     {
1366         object->putDirectIndex(m_exec, index, value);
1367     }
1368
1369     void putProperty(JSObject* object, const Identifier& property, JSValue value)
1370     {
1371         object->putDirectMayBeIndex(m_exec, property, value);
1372     }
1373
1374     bool readFile(RefPtr<File>& file)
1375     {
1376         CachedStringRef path;
1377         if (!readStringData(path))
1378             return 0;
1379         CachedStringRef url;
1380         if (!readStringData(url))
1381             return 0;
1382         CachedStringRef type;
1383         if (!readStringData(type))
1384             return 0;
1385         if (m_isDOMGlobalObject)
1386             file = File::create(path->string(), URL(URL(), url->string()), type->string());
1387         return true;
1388     }
1389
1390     bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
1391     {
1392         uint32_t length;
1393         if (!read(length))
1394             return false;
1395         if (m_ptr + length > m_end)
1396             return false;
1397         arrayBuffer = ArrayBuffer::create(m_ptr, length);
1398         m_ptr += length;
1399         return true;
1400     }
1401
1402     bool readArrayBufferView(JSValue& arrayBufferView)
1403     {
1404         ArrayBufferViewSubtag arrayBufferViewSubtag;
1405         if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
1406             return false;
1407         uint32_t byteOffset;
1408         if (!read(byteOffset))
1409             return false;
1410         uint32_t byteLength;
1411         if (!read(byteLength))
1412             return false;
1413         JSObject* arrayBufferObj = asObject(readTerminal());
1414         if (!arrayBufferObj || !arrayBufferObj->inherits(JSArrayBuffer::info()))
1415             return false;
1416
1417         unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
1418         if (!elementSize)
1419             return false;
1420         unsigned length = byteLength / elementSize;
1421         if (length * elementSize != byteLength)
1422             return false;
1423
1424         RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj);
1425         switch (arrayBufferViewSubtag) {
1426         case DataViewTag:
1427             arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get());
1428             return true;
1429         case Int8ArrayTag:
1430             arrayBufferView = getJSValue(Int8Array::create(arrayBuffer, byteOffset, length).get());
1431             return true;
1432         case Uint8ArrayTag:
1433             arrayBufferView = getJSValue(Uint8Array::create(arrayBuffer, byteOffset, length).get());
1434             return true;
1435         case Uint8ClampedArrayTag:
1436             arrayBufferView = getJSValue(Uint8ClampedArray::create(arrayBuffer, byteOffset, length).get());
1437             return true;
1438         case Int16ArrayTag:
1439             arrayBufferView = getJSValue(Int16Array::create(arrayBuffer, byteOffset, length).get());
1440             return true;
1441         case Uint16ArrayTag:
1442             arrayBufferView = getJSValue(Uint16Array::create(arrayBuffer, byteOffset, length).get());
1443             return true;
1444         case Int32ArrayTag:
1445             arrayBufferView = getJSValue(Int32Array::create(arrayBuffer, byteOffset, length).get());
1446             return true;
1447         case Uint32ArrayTag:
1448             arrayBufferView = getJSValue(Uint32Array::create(arrayBuffer, byteOffset, length).get());
1449             return true;
1450         case Float32ArrayTag:
1451             arrayBufferView = getJSValue(Float32Array::create(arrayBuffer, byteOffset, length).get());
1452             return true;
1453         case Float64ArrayTag:
1454             arrayBufferView = getJSValue(Float64Array::create(arrayBuffer, byteOffset, length).get());
1455             return true;
1456         default:
1457             return false;
1458         }
1459     }
1460
1461     template<class T>
1462     JSValue getJSValue(T* nativeObj)
1463     {
1464         return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
1465     }
1466
1467     JSValue readTerminal()
1468     {
1469         SerializationTag tag = readTag();
1470         switch (tag) {
1471         case UndefinedTag:
1472             return jsUndefined();
1473         case NullTag:
1474             return jsNull();
1475         case IntTag: {
1476             int32_t i;
1477             if (!read(i))
1478                 return JSValue();
1479             return jsNumber(i);
1480         }
1481         case ZeroTag:
1482             return jsNumber(0);
1483         case OneTag:
1484             return jsNumber(1);
1485         case FalseTag:
1486             return jsBoolean(false);
1487         case TrueTag:
1488             return jsBoolean(true);
1489         case FalseObjectTag: {
1490             BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
1491             obj->setInternalValue(m_exec->vm(), jsBoolean(false));
1492             m_gcBuffer.append(obj);
1493             return obj;
1494         }
1495         case TrueObjectTag: {
1496             BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
1497             obj->setInternalValue(m_exec->vm(), jsBoolean(true));
1498              m_gcBuffer.append(obj);
1499             return obj;
1500         }
1501         case DoubleTag: {
1502             double d;
1503             if (!read(d))
1504                 return JSValue();
1505             return jsNumber(d);
1506         }
1507         case NumberObjectTag: {
1508             double d;
1509             if (!read(d))
1510                 return JSValue();
1511             NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
1512             m_gcBuffer.append(obj);
1513             return obj;
1514         }
1515         case DateTag: {
1516             double d;
1517             if (!read(d))
1518                 return JSValue();
1519             return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
1520         }
1521         case FileTag: {
1522             RefPtr<File> file;
1523             if (!readFile(file))
1524                 return JSValue();
1525             if (!m_isDOMGlobalObject)
1526                 return jsNull();
1527             return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
1528         }
1529         case FileListTag: {
1530             unsigned length = 0;
1531             if (!read(length))
1532                 return JSValue();
1533             RefPtr<FileList> result = FileList::create();
1534             for (unsigned i = 0; i < length; i++) {
1535                 RefPtr<File> file;
1536                 if (!readFile(file))
1537                     return JSValue();
1538                 if (m_isDOMGlobalObject)
1539                     result->append(file.get());
1540             }
1541             if (!m_isDOMGlobalObject)
1542                 return jsNull();
1543             return getJSValue(result.get());
1544         }
1545         case ImageDataTag: {
1546             int32_t width;
1547             if (!read(width))
1548                 return JSValue();
1549             int32_t height;
1550             if (!read(height))
1551                 return JSValue();
1552             uint32_t length;
1553             if (!read(length))
1554                 return JSValue();
1555             if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1556                 fail();
1557                 return JSValue();
1558             }
1559             if (!m_isDOMGlobalObject) {
1560                 m_ptr += length;
1561                 return jsNull();
1562             }
1563             RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
1564             memcpy(result->data()->data(), m_ptr, length);
1565             m_ptr += length;
1566             return getJSValue(result.get());
1567         }
1568         case BlobTag: {
1569             CachedStringRef url;
1570             if (!readStringData(url))
1571                 return JSValue();
1572             CachedStringRef type;
1573             if (!readStringData(type))
1574                 return JSValue();
1575             unsigned long long size = 0;
1576             if (!read(size))
1577                 return JSValue();
1578             if (!m_isDOMGlobalObject)
1579                 return jsNull();
1580             return getJSValue(Blob::create(URL(URL(), url->string()), type->string(), size).get());
1581         }
1582         case StringTag: {
1583             CachedStringRef cachedString;
1584             if (!readStringData(cachedString))
1585                 return JSValue();
1586             return cachedString->jsString(m_exec);
1587         }
1588         case EmptyStringTag:
1589             return jsEmptyString(&m_exec->vm());
1590         case StringObjectTag: {
1591             CachedStringRef cachedString;
1592             if (!readStringData(cachedString))
1593                 return JSValue();
1594             StringObject* obj = constructString(m_exec, m_globalObject, cachedString->jsString(m_exec));
1595             m_gcBuffer.append(obj);
1596             return obj;
1597         }
1598         case EmptyStringObjectTag: {
1599             StringObject* obj = constructString(m_exec, m_globalObject, jsEmptyString(&m_exec->vm()));
1600             m_gcBuffer.append(obj);
1601             return obj;
1602         }
1603         case RegExpTag: {
1604             CachedStringRef pattern;
1605             if (!readStringData(pattern))
1606                 return JSValue();
1607             CachedStringRef flags;
1608             if (!readStringData(flags))
1609                 return JSValue();
1610             RegExpFlags reFlags = regExpFlags(flags->string());
1611             ASSERT(reFlags != InvalidFlags);
1612             VM& vm = m_exec->vm();
1613             RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags);
1614             return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
1615         }
1616         case ObjectReferenceTag: {
1617             unsigned index = 0;
1618             if (!readConstantPoolIndex(m_gcBuffer, index)) {
1619                 fail();
1620                 return JSValue();
1621             }
1622             return m_gcBuffer.at(index);
1623         }
1624         case MessagePortReferenceTag: {
1625             uint32_t index;
1626             bool indexSuccessfullyRead = read(index);
1627             if (!indexSuccessfullyRead || !m_messagePorts || index >= m_messagePorts->size()) {
1628                 fail();
1629                 return JSValue();
1630             }
1631             return getJSValue(m_messagePorts->at(index).get());
1632         }
1633         case ArrayBufferTag: {
1634             RefPtr<ArrayBuffer> arrayBuffer;
1635             if (!readArrayBuffer(arrayBuffer)) {
1636                 fail();
1637                 return JSValue();
1638             }
1639             JSValue result = getJSValue(arrayBuffer.get());
1640             m_gcBuffer.append(result);
1641             return result;
1642         }
1643         case ArrayBufferTransferTag: {
1644             uint32_t index;
1645             bool indexSuccessfullyRead = read(index);
1646             if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
1647                 fail();
1648                 return JSValue();
1649             }
1650
1651             if (!m_arrayBuffers[index])
1652                 m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
1653
1654             return getJSValue(m_arrayBuffers[index].get());
1655         }
1656         case ArrayBufferViewTag: {
1657             JSValue arrayBufferView;
1658             if (!readArrayBufferView(arrayBufferView)) {
1659                 fail();
1660                 return JSValue();
1661             }
1662             m_gcBuffer.append(arrayBufferView);
1663             return arrayBufferView;
1664         }
1665         default:
1666             m_ptr--; // Push the tag back
1667             return JSValue();
1668         }
1669     }
1670
1671     bool consumeMapDataTerminationIfPossible()
1672     {
1673         if (readTag() == NonMapPropertiesTag)
1674             return true;
1675         m_ptr--;
1676         return false;
1677     }
1678
1679     JSGlobalObject* m_globalObject;
1680     bool m_isDOMGlobalObject;
1681     const uint8_t* m_ptr;
1682     const uint8_t* m_end;
1683     unsigned m_version;
1684     Vector<CachedString> m_constantPool;
1685     MessagePortArray* m_messagePorts;
1686     ArrayBufferContentsArray* m_arrayBufferContents;
1687     ArrayBufferArray m_arrayBuffers;
1688 };
1689
1690 DeserializationResult CloneDeserializer::deserialize()
1691 {
1692     Vector<uint32_t, 16> indexStack;
1693     Vector<Identifier, 16> propertyNameStack;
1694     Vector<JSObject*, 32> outputObjectStack;
1695     Vector<JSValue, 4> keyStack;
1696     Vector<MapData*, 4> mapDataStack;
1697     Vector<WalkerState, 16> stateStack;
1698     WalkerState state = StateUnknown;
1699     JSValue outValue;
1700
1701     while (1) {
1702         switch (state) {
1703         arrayStartState:
1704         case ArrayStartState: {
1705             uint32_t length;
1706             if (!read(length)) {
1707                 fail();
1708                 goto error;
1709             }
1710             JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
1711             m_gcBuffer.append(outArray);
1712             outputObjectStack.append(outArray);
1713             // fallthrough
1714         }
1715         arrayStartVisitMember:
1716         case ArrayStartVisitMember: {
1717             uint32_t index;
1718             if (!read(index)) {
1719                 fail();
1720                 goto error;
1721             }
1722             if (index == TerminatorTag) {
1723                 JSObject* outArray = outputObjectStack.last();
1724                 outValue = outArray;
1725                 outputObjectStack.removeLast();
1726                 break;
1727             } else if (index == NonIndexPropertiesTag) {
1728                 goto objectStartVisitMember;
1729             }
1730
1731             if (JSValue terminal = readTerminal()) {
1732                 putProperty(outputObjectStack.last(), index, terminal);
1733                 goto arrayStartVisitMember;
1734             }
1735             if (m_failed)
1736                 goto error;
1737             indexStack.append(index);
1738             stateStack.append(ArrayEndVisitMember);
1739             goto stateUnknown;
1740         }
1741         case ArrayEndVisitMember: {
1742             JSObject* outArray = outputObjectStack.last();
1743             putProperty(outArray, indexStack.last(), outValue);
1744             indexStack.removeLast();
1745             goto arrayStartVisitMember;
1746         }
1747         objectStartState:
1748         case ObjectStartState: {
1749             if (outputObjectStack.size() > maximumFilterRecursion)
1750                 return make_pair(JSValue(), StackOverflowError);
1751             JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
1752             m_gcBuffer.append(outObject);
1753             outputObjectStack.append(outObject);
1754             // fallthrough
1755         }
1756         objectStartVisitMember:
1757         case ObjectStartVisitMember: {
1758             CachedStringRef cachedString;
1759             bool wasTerminator = false;
1760             if (!readStringData(cachedString, wasTerminator)) {
1761                 if (!wasTerminator)
1762                     goto error;
1763
1764                 JSObject* outObject = outputObjectStack.last();
1765                 outValue = outObject;
1766                 outputObjectStack.removeLast();
1767                 break;
1768             }
1769
1770             if (JSValue terminal = readTerminal()) {
1771                 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->string()), terminal);
1772                 goto objectStartVisitMember;
1773             }
1774             stateStack.append(ObjectEndVisitMember);
1775             propertyNameStack.append(Identifier(m_exec, cachedString->string()));
1776             goto stateUnknown;
1777         }
1778         case ObjectEndVisitMember: {
1779             putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1780             propertyNameStack.removeLast();
1781             goto objectStartVisitMember;
1782         }
1783         mapObjectStartState: {
1784             if (outputObjectStack.size() > maximumFilterRecursion)
1785                 return make_pair(JSValue(), StackOverflowError);
1786             JSMap* map = JSMap::create(m_exec->vm(), m_globalObject->mapStructure());
1787             m_gcBuffer.append(map);
1788             outputObjectStack.append(map);
1789             MapData* mapData = map->mapData();
1790             mapDataStack.append(mapData);
1791             goto mapDataStartVisitEntry;
1792         }
1793         setObjectStartState: {
1794             if (outputObjectStack.size() > maximumFilterRecursion)
1795                 return make_pair(JSValue(), StackOverflowError);
1796             JSSet* set = JSSet::create(m_exec->vm(), m_globalObject->setStructure());
1797             m_gcBuffer.append(set);
1798             outputObjectStack.append(set);
1799             MapData* mapData = set->mapData();
1800             mapDataStack.append(mapData);
1801             goto mapDataStartVisitEntry;
1802         }
1803         mapDataStartVisitEntry:
1804         case MapDataStartVisitEntry: {
1805             if (consumeMapDataTerminationIfPossible()) {
1806                 mapDataStack.removeLast();
1807                 goto objectStartVisitMember;
1808             }
1809             stateStack.append(MapDataEndVisitKey);
1810             goto stateUnknown;
1811         }
1812
1813         case MapDataEndVisitKey: {
1814             keyStack.append(outValue);
1815             stateStack.append(MapDataEndVisitValue);
1816             goto stateUnknown;
1817         }
1818
1819         case MapDataEndVisitValue: {
1820             mapDataStack.last()->set(m_exec, keyStack.last(), outValue);
1821             keyStack.removeLast();
1822             goto mapDataStartVisitEntry;
1823         }
1824         stateUnknown:
1825         case StateUnknown:
1826             if (JSValue terminal = readTerminal()) {
1827                 outValue = terminal;
1828                 break;
1829             }
1830             SerializationTag tag = readTag();
1831             if (tag == ArrayTag)
1832                 goto arrayStartState;
1833             if (tag == ObjectTag)
1834                 goto objectStartState;
1835             if (tag == MapObjectTag)
1836                 goto mapObjectStartState;
1837             if (tag == SetObjectTag)
1838                 goto setObjectStartState;
1839             goto error;
1840         }
1841         if (stateStack.isEmpty())
1842             break;
1843
1844         state = stateStack.last();
1845         stateStack.removeLast();
1846     }
1847     ASSERT(outValue);
1848     ASSERT(!m_failed);
1849     return make_pair(outValue, SuccessfullyCompleted);
1850 error:
1851     fail();
1852     return make_pair(JSValue(), ValidationError);
1853 }
1854
1855
1856
1857 SerializedScriptValue::~SerializedScriptValue()
1858 {
1859 }
1860
1861 SerializedScriptValue::SerializedScriptValue(const Vector<uint8_t>& buffer)
1862     : m_data(buffer)
1863 {
1864 }
1865
1866 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1867 {
1868     m_data.swap(buffer);
1869 }
1870
1871 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs)
1872 {
1873     m_data.swap(buffer);
1874     m_blobURLs.swap(blobURLs);
1875 }
1876
1877 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray)
1878     : m_arrayBufferContentsArray(arrayBufferContentsArray)
1879 {
1880     m_data.swap(buffer);
1881     m_blobURLs.swap(blobURLs);
1882 }
1883
1884 PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
1885     ExecState* exec, ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
1886 {
1887     for (size_t i = 0; i < arrayBuffers.size(); i++) {
1888         if (arrayBuffers[i]->isNeutered()) {
1889             code = ValidationError;
1890             return nullptr;
1891         }
1892     }
1893
1894     OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
1895     Vector<RefPtr<DOMWrapperWorld> > worlds;
1896     static_cast<WebCoreJSClientData*>(exec->vm().clientData)->getAllWorlds(worlds);
1897
1898     HashSet<JSC::ArrayBuffer*> visited;
1899     for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
1900         if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
1901             continue;
1902         visited.add(arrayBuffers[arrayBufferIndex].get());
1903
1904         bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex));
1905         if (!result) {
1906             code = ValidationError;
1907             return nullptr;
1908         }
1909     }
1910     return contents.release();
1911 }
1912
1913
1914 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value,
1915                                                                 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1916                                                                 SerializationErrorMode throwExceptions)
1917 {
1918     Vector<uint8_t> buffer;
1919     Vector<String> blobURLs;
1920     SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, blobURLs, buffer);
1921
1922     OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
1923
1924     if (arrayBuffers && serializationDidCompleteSuccessfully(code))
1925         arrayBufferContentsArray = transferArrayBuffers(exec, *arrayBuffers, code);
1926
1927     if (throwExceptions == Throwing)
1928         maybeThrowExceptionIfSerializationFailed(exec, code);
1929
1930     if (!serializationDidCompleteSuccessfully(code))
1931         return 0;
1932
1933     return adoptRef(new SerializedScriptValue(buffer, blobURLs, arrayBufferContentsArray.release()));
1934 }
1935
1936 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1937 {
1938     Vector<uint8_t> buffer;
1939     return adoptRef(new SerializedScriptValue(buffer));
1940 }
1941
1942 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
1943 {
1944     Vector<uint8_t> buffer;
1945     if (!CloneSerializer::serialize(string, buffer))
1946         return 0;
1947     return adoptRef(new SerializedScriptValue(buffer));
1948 }
1949
1950 #if ENABLE(INDEXED_DATABASE)
1951 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::ExecState* exec, JSC::JSValue value)
1952 {
1953     return SerializedScriptValue::create(exec, value, 0, 0);
1954 }
1955
1956 PassRefPtr<SerializedScriptValue> SerializedScriptValue::numberValue(double value)
1957 {
1958     Vector<uint8_t> buffer;
1959     CloneSerializer::serializeNumber(value, buffer);
1960     return adoptRef(new SerializedScriptValue(buffer));
1961 }
1962
1963 JSValue SerializedScriptValue::deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
1964 {
1965     return deserialize(exec, globalObject, 0);
1966 }
1967 #endif
1968
1969 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, 
1970                                                                 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1971                                                                 JSValueRef* exception)
1972 {
1973     ExecState* exec = toJS(originContext);
1974     APIEntryShim entryShim(exec);
1975     JSValue value = toJS(exec, apiValue);
1976     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts, arrayBuffers);
1977     if (exec->hadException()) {
1978         if (exception)
1979             *exception = toRef(exec, exec->exception());
1980         exec->clearException();
1981         return 0;
1982     }
1983     ASSERT(serializedValue);
1984     return serializedValue.release();
1985 }
1986
1987 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
1988                                                                 JSValueRef* exception)
1989 {
1990     return create(originContext, apiValue, 0, 0, exception);
1991 }
1992
1993 String SerializedScriptValue::toString()
1994 {
1995     return CloneDeserializer::deserializeString(m_data);
1996 }
1997
1998 JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
1999                                            MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
2000 {
2001     DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
2002                                                                   m_arrayBufferContentsArray.get(), m_data);
2003     if (throwExceptions == Throwing)
2004         maybeThrowExceptionIfSerializationFailed(exec, result.second);
2005     return result.first;
2006 }
2007
2008 #if ENABLE(INSPECTOR)
2009 ScriptValue SerializedScriptValue::deserializeForInspector(JSC::ExecState* scriptState)
2010 {
2011     JSValue value = deserialize(scriptState, scriptState->lexicalGlobalObject(), 0);
2012     return ScriptValue(scriptState->vm(), value);
2013 }
2014 #endif
2015
2016 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception, MessagePortArray* messagePorts)
2017 {
2018     ExecState* exec = toJS(destinationContext);
2019     APIEntryShim entryShim(exec);
2020     JSValue value = deserialize(exec, exec->lexicalGlobalObject(), messagePorts);
2021     if (exec->hadException()) {
2022         if (exception)
2023             *exception = toRef(exec, exec->exception());
2024         exec->clearException();
2025         return 0;
2026     }
2027     ASSERT(value);
2028     return toRef(exec, value);
2029 }
2030
2031
2032 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
2033 {
2034     return deserialize(destinationContext, exception, 0);
2035 }
2036
2037 PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
2038 {
2039     return SerializedScriptValue::create();
2040 }
2041
2042 PassRefPtr<SerializedScriptValue> SerializedScriptValue::undefinedValue()
2043 {
2044     Vector<uint8_t> buffer;
2045     CloneSerializer::serializeUndefined(buffer);
2046     return adoptRef(new SerializedScriptValue(buffer));
2047 }
2048
2049 PassRefPtr<SerializedScriptValue> SerializedScriptValue::booleanValue(bool value)
2050 {
2051     Vector<uint8_t> buffer;
2052     CloneSerializer::serializeBoolean(value, buffer);
2053     return adoptRef(new SerializedScriptValue(buffer));
2054 }
2055
2056 void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
2057 {
2058     if (code == SuccessfullyCompleted)
2059         return;
2060     
2061     switch (code) {
2062     case StackOverflowError:
2063         exec->vm().throwException(exec, createStackOverflowError(exec));
2064         break;
2065     case ValidationError:
2066         exec->vm().throwException(exec, createTypeError(exec, "Unable to deserialize data."));
2067         break;
2068     case DataCloneError:
2069         setDOMException(exec, DATA_CLONE_ERR);
2070         break;
2071     case ExistingExceptionError:
2072         break;
2073     case UnspecifiedError:
2074         break;
2075     default:
2076         ASSERT_NOT_REACHED();
2077     }
2078 }
2079
2080 bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
2081 {
2082     return (code == SuccessfullyCompleted);
2083 }
2084
2085 uint32_t SerializedScriptValue::wireFormatVersion()
2086 {
2087     return CurrentVersion;
2088 }
2089
2090 }