2 * Copyright (C) 2010 Google 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 are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "bindings/v8/SerializedScriptValue.h"
34 #include "bindings/core/v8/V8Blob.h"
35 #include "bindings/core/v8/V8File.h"
36 #include "bindings/core/v8/V8FileList.h"
37 #include "bindings/core/v8/V8ImageData.h"
38 #include "bindings/core/v8/V8MessagePort.h"
39 #include "bindings/modules/v8/V8DOMFileSystem.h"
40 #include "bindings/modules/v8/V8Key.h"
41 #include "bindings/v8/ExceptionState.h"
42 #include "bindings/v8/V8Binding.h"
43 #include "bindings/v8/WorkerScriptController.h"
44 #include "bindings/v8/custom/V8ArrayBufferCustom.h"
45 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
46 #include "bindings/v8/custom/V8DataViewCustom.h"
47 #include "bindings/v8/custom/V8Float32ArrayCustom.h"
48 #include "bindings/v8/custom/V8Float64ArrayCustom.h"
49 #include "bindings/v8/custom/V8Int16ArrayCustom.h"
50 #include "bindings/v8/custom/V8Int32ArrayCustom.h"
51 #include "bindings/v8/custom/V8Int8ArrayCustom.h"
52 #include "bindings/v8/custom/V8Uint16ArrayCustom.h"
53 #include "bindings/v8/custom/V8Uint32ArrayCustom.h"
54 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
55 #include "bindings/v8/custom/V8Uint8ClampedArrayCustom.h"
56 #include "core/dom/ExceptionCode.h"
57 #include "core/dom/MessagePort.h"
58 #include "core/fileapi/Blob.h"
59 #include "core/fileapi/File.h"
60 #include "core/fileapi/FileList.h"
61 #include "core/html/ImageData.h"
62 #include "core/html/canvas/DataView.h"
63 #include "platform/SharedBuffer.h"
64 #include "platform/heap/Handle.h"
65 #include "public/platform/Platform.h"
66 #include "public/platform/WebBlobInfo.h"
67 #include "public/platform/WebCrypto.h"
68 #include "public/platform/WebCryptoKey.h"
69 #include "public/platform/WebCryptoKeyAlgorithm.h"
70 #include "wtf/ArrayBuffer.h"
71 #include "wtf/ArrayBufferContents.h"
72 #include "wtf/ArrayBufferView.h"
73 #include "wtf/Assertions.h"
74 #include "wtf/ByteOrder.h"
75 #include "wtf/Float32Array.h"
76 #include "wtf/Float64Array.h"
77 #include "wtf/Int16Array.h"
78 #include "wtf/Int32Array.h"
79 #include "wtf/Int8Array.h"
80 #include "wtf/RefCounted.h"
81 #include "wtf/Uint16Array.h"
82 #include "wtf/Uint32Array.h"
83 #include "wtf/Uint8Array.h"
84 #include "wtf/Uint8ClampedArray.h"
85 #include "wtf/Vector.h"
86 #include "wtf/text/StringBuffer.h"
87 #include "wtf/text/StringUTF8Adaptor.h"
89 // FIXME: consider crashing in debug mode on deserialization errors
90 // NOTE: be sure to change wireFormatVersion as necessary!
96 // This code implements the HTML5 Structured Clone algorithm:
97 // http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-passing-of-structured-data
99 // V8ObjectMap is a map from V8 objects to arbitrary values of type T.
100 // V8 objects (or handles to V8 objects) cannot be used as keys in ordinary wtf::HashMaps;
101 // this class should be used instead. GCObject must be a subtype of v8::Object.
103 // V8ObjectMap<v8::Object, int> map;
104 // v8::Handle<v8::Object> obj = ...;
106 template<typename GCObject, typename T>
109 bool contains(const v8::Handle<GCObject>& handle)
111 return m_map.contains(*handle);
114 bool tryGet(const v8::Handle<GCObject>& handle, T* valueOut)
116 typename HandleToT::iterator result = m_map.find(*handle);
117 if (result != m_map.end()) {
118 *valueOut = result->value;
124 void set(const v8::Handle<GCObject>& handle, const T& value)
126 m_map.set(*handle, value);
130 // This implementation uses GetIdentityHash(), which sets a hidden property on the object containing
131 // a random integer (or returns the one that had been previously set). This ensures that the table
132 // never needs to be rebuilt across garbage collections at the expense of doing additional allocation
133 // and making more round trips into V8. Note that since GetIdentityHash() is defined only on
134 // v8::Objects, this V8ObjectMap cannot be used to map v8::Strings to T (because the public V8 API
135 // considers a v8::String to be a v8::Primitive).
137 // If V8 exposes a way to get at the address of the object held by a handle, then we can produce
138 // an alternate implementation that does not need to do any V8-side allocation; however, it will
139 // need to rehash after every garbage collection because a key object may have been moved.
141 struct V8HandlePtrHash {
142 static v8::Handle<G> unsafeHandleFromRawValue(const G* value)
144 const v8::Handle<G>* handle = reinterpret_cast<const v8::Handle<G>*>(&value);
148 static unsigned hash(const G* key)
150 return static_cast<unsigned>(unsafeHandleFromRawValue(key)->GetIdentityHash());
152 static bool equal(const G* a, const G* b)
154 return unsafeHandleFromRawValue(a) == unsafeHandleFromRawValue(b);
157 static const bool safeToCompareToEmptyOrDeleted = false;
160 typedef WTF::HashMap<GCObject*, T, V8HandlePtrHash<GCObject> > HandleToT;
164 typedef UChar BufferValueType;
166 // Serialization format is a sequence of tags followed by zero or more data arguments.
167 // Tags always take exactly one byte. A serialized stream first begins with
168 // a complete VersionTag. If the stream does not begin with a VersionTag, we assume that
169 // the stream is in format 0.
171 // This format is private to the implementation of SerializedScriptValue. Do not rely on it
172 // externally. It is safe to persist a SerializedScriptValue as a binary blob, but this
173 // code should always be used to interpret it.
175 // WebCoreStrings are read as (length:uint32_t, string:UTF8[length]).
176 // RawStrings are read as (length:uint32_t, string:UTF8[length]).
177 // RawUCharStrings are read as (length:uint32_t, string:UChar[length/sizeof(UChar)]).
178 // RawFiles are read as (path:WebCoreString, url:WebCoreStrng, type:WebCoreString).
179 // There is a reference table that maps object references (uint32_t) to v8::Values.
180 // Tokens marked with (ref) are inserted into the reference table and given the next object reference ID after decoding.
181 // All tags except InvalidTag, PaddingTag, ReferenceCountTag, VersionTag, GenerateFreshObjectTag
182 // and GenerateFreshArrayTag push their results to the deserialization stack.
183 // There is also an 'open' stack that is used to resolve circular references. Objects or arrays may
184 // contain self-references. Before we begin to deserialize the contents of these values, they
185 // are first given object reference IDs (by GenerateFreshObjectTag/GenerateFreshArrayTag);
186 // these reference IDs are then used with ObjectReferenceTag to tie the recursive knot.
187 enum SerializationTag {
188 InvalidTag = '!', // Causes deserialization to fail.
189 PaddingTag = '\0', // Is ignored (but consumed).
190 UndefinedTag = '_', // -> <undefined>
191 NullTag = '0', // -> <null>
192 TrueTag = 'T', // -> <true>
193 FalseTag = 'F', // -> <false>
194 StringTag = 'S', // string:RawString -> string
195 StringUCharTag = 'c', // string:RawUCharString -> string
196 Int32Tag = 'I', // value:ZigZag-encoded int32 -> Integer
197 Uint32Tag = 'U', // value:uint32_t -> Integer
198 DateTag = 'D', // value:double -> Date (ref)
199 MessagePortTag = 'M', // index:int -> MessagePort. Fills the result with transferred MessagePort.
200 NumberTag = 'N', // value:double -> Number
201 BlobTag = 'b', // uuid:WebCoreString, type:WebCoreString, size:uint64_t -> Blob (ref)
202 BlobIndexTag = 'i', // index:int32_t -> Blob (ref)
203 FileTag = 'f', // file:RawFile -> File (ref)
204 FileIndexTag = 'e', // index:int32_t -> File (ref)
205 DOMFileSystemTag = 'd', // type:int32_t, name:WebCoreString, uuid:WebCoreString -> FileSystem (ref)
206 FileListTag = 'l', // length:uint32_t, files:RawFile[length] -> FileList (ref)
207 FileListIndexTag = 'L', // length:uint32_t, files:int32_t[length] -> FileList (ref)
208 ImageDataTag = '#', // width:uint32_t, height:uint32_t, pixelDataLength:uint32_t, data:byte[pixelDataLength] -> ImageData (ref)
209 ObjectTag = '{', // numProperties:uint32_t -> pops the last object from the open stack;
210 // fills it with the last numProperties name,value pairs pushed onto the deserialization stack
211 SparseArrayTag = '@', // numProperties:uint32_t, length:uint32_t -> pops the last object from the open stack;
212 // fills it with the last numProperties name,value pairs pushed onto the deserialization stack
213 DenseArrayTag = '$', // numProperties:uint32_t, length:uint32_t -> pops the last object from the open stack;
214 // fills it with the last length elements and numProperties name,value pairs pushed onto deserialization stack
215 RegExpTag = 'R', // pattern:RawString, flags:uint32_t -> RegExp (ref)
216 ArrayBufferTag = 'B', // byteLength:uint32_t, data:byte[byteLength] -> ArrayBuffer (ref)
217 ArrayBufferTransferTag = 't', // index:uint32_t -> ArrayBuffer. For ArrayBuffer transfer
218 ArrayBufferViewTag = 'V', // subtag:byte, byteOffset:uint32_t, byteLength:uint32_t -> ArrayBufferView (ref). Consumes an ArrayBuffer from the top of the deserialization stack.
219 CryptoKeyTag = 'K', // subtag:byte, props, usages:uint32_t, keyDataLength:uint32_t, keyData:byte[keyDataLength]
220 // If subtag=AesKeyTag:
221 // props = keyLengthBytes:uint32_t, algorithmId:uint32_t
222 // If subtag=HmacKeyTag:
223 // props = keyLengthBytes:uint32_t, hashId:uint32_t
224 // If subtag=RsaHashedKeyTag:
225 // props = algorithmId:uint32_t, type:uint32_t, modulusLengthBits:uint32_t, publicExponentLength:uint32_t, publicExponent:byte[publicExponentLength], hashId:uint32_t
226 ObjectReferenceTag = '^', // ref:uint32_t -> reference table[ref]
227 GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and pushed onto the open stack (ref)
228 GenerateFreshSparseArrayTag = 'a', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref)
229 GenerateFreshDenseArrayTag = 'A', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref)
230 ReferenceCountTag = '?', // refTableSize:uint32_t -> If the reference table is not refTableSize big, fails.
231 StringObjectTag = 's', // string:RawString -> new String(string) (ref)
232 NumberObjectTag = 'n', // value:double -> new Number(value) (ref)
233 TrueObjectTag = 'y', // new Boolean(true) (ref)
234 FalseObjectTag = 'x', // new Boolean(false) (ref)
235 VersionTag = 0xFF // version:uint32_t -> Uses this as the file version.
238 enum ArrayBufferViewSubTag {
240 UnsignedByteArrayTag = 'B',
241 UnsignedByteClampedArrayTag = 'C',
243 UnsignedShortArrayTag = 'W',
245 UnsignedIntArrayTag = 'D',
247 DoubleArrayTag = 'F',
251 enum CryptoKeySubTag {
254 // ID 3 was used by RsaKeyTag, while still behind experimental flag.
256 // Maximum allowed value is 255
259 enum AssymetricCryptoKeyType {
262 // Maximum allowed value is 2^32-1
265 enum CryptoKeyAlgorithmTag {
268 RsaSsaPkcs1v1_5Tag = 3,
269 // ID 4 was used by RsaEs, while still behind experimental flag.
278 // Maximum allowed value is 2^32-1
281 enum CryptoKeyUsage {
282 // Extractability is not a "usage" in the WebCryptoKeyUsages sense, however
283 // it fits conveniently into this bitfield.
284 ExtractableUsage = 1 << 0,
286 EncryptUsage = 1 << 1,
287 DecryptUsage = 1 << 2,
289 VerifyUsage = 1 << 4,
290 DeriveKeyUsage = 1 << 5,
291 WrapKeyUsage = 1 << 6,
292 UnwrapKeyUsage = 1 << 7,
293 DeriveBitsUsage = 1 << 8,
294 // Maximum allowed value is 1 << 31
297 static bool shouldCheckForCycles(int depth)
300 // Since we are not required to spot the cycle as soon as it
301 // happens we can check for cycles only when the current depth
302 // is a power of two.
303 return !(depth & (depth - 1));
306 static const int maxDepth = 20000;
308 // VarInt encoding constants.
309 static const int varIntShift = 7;
310 static const int varIntMask = (1 << varIntShift) - 1;
312 // ZigZag encoding helps VarInt encoding stay small for negative
313 // numbers with small absolute values.
316 static uint32_t encode(uint32_t value)
318 if (value & (1U << 31))
319 value = ((~value) << 1) + 1;
325 static uint32_t decode(uint32_t value)
328 value = ~(value >> 1);
338 // Writer is responsible for serializing primitive types and storing
339 // information used to reconstruct composite types.
341 WTF_MAKE_NONCOPYABLE(Writer);
348 // Write functions for primitive types.
350 void writeUndefined() { append(UndefinedTag); }
352 void writeNull() { append(NullTag); }
354 void writeTrue() { append(TrueTag); }
356 void writeFalse() { append(FalseTag); }
358 void writeBooleanObject(bool value)
360 append(value ? TrueObjectTag : FalseObjectTag);
363 void writeOneByteString(v8::Handle<v8::String>& string)
365 int stringLength = string->Length();
366 int utf8Length = string->Utf8Length();
367 ASSERT(stringLength >= 0 && utf8Length >= 0);
370 doWriteUint32(static_cast<uint32_t>(utf8Length));
371 ensureSpace(utf8Length);
374 if (stringLength == utf8Length)
375 string->WriteOneByte(byteAt(m_position), 0, utf8Length, v8StringWriteOptions());
377 char* buffer = reinterpret_cast<char*>(byteAt(m_position));
378 string->WriteUtf8(buffer, utf8Length, 0, v8StringWriteOptions());
380 m_position += utf8Length;
383 void writeUCharString(v8::Handle<v8::String>& string)
385 int length = string->Length();
388 int size = length * sizeof(UChar);
389 int bytes = bytesNeededToWireEncode(static_cast<uint32_t>(size));
390 if ((m_position + 1 + bytes) & 1)
393 append(StringUCharTag);
394 doWriteUint32(static_cast<uint32_t>(size));
397 ASSERT(!(m_position & 1));
398 uint16_t* buffer = reinterpret_cast<uint16_t*>(byteAt(m_position));
399 string->Write(buffer, 0, length, v8StringWriteOptions());
403 void writeStringObject(const char* data, int length)
406 append(StringObjectTag);
407 doWriteString(data, length);
410 void writeWebCoreString(const String& string)
412 // Uses UTF8 encoding so we can read it back as either V8 or
415 doWriteWebCoreString(string);
421 doWriteUint32(SerializedScriptValue::wireFormatVersion);
424 void writeInt32(int32_t value)
427 doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
430 void writeUint32(uint32_t value)
433 doWriteUint32(value);
436 void writeDate(double numberValue)
439 doWriteNumber(numberValue);
442 void writeNumber(double number)
445 doWriteNumber(number);
448 void writeNumberObject(double number)
450 append(NumberObjectTag);
451 doWriteNumber(number);
454 void writeBlob(const String& uuid, const String& type, unsigned long long size)
457 doWriteWebCoreString(uuid);
458 doWriteWebCoreString(type);
462 void writeBlobIndex(int blobIndex)
464 ASSERT(blobIndex >= 0);
465 append(BlobIndexTag);
466 doWriteUint32(blobIndex);
469 void writeDOMFileSystem(int type, const String& name, const String& url)
471 append(DOMFileSystemTag);
473 doWriteWebCoreString(name);
474 doWriteWebCoreString(url);
477 void writeFile(const File& file)
483 void writeFileIndex(int blobIndex)
485 append(FileIndexTag);
486 doWriteUint32(blobIndex);
489 void writeFileList(const FileList& fileList)
492 uint32_t length = fileList.length();
493 doWriteUint32(length);
494 for (unsigned i = 0; i < length; ++i)
495 doWriteFile(*fileList.item(i));
498 void writeFileListIndex(const Vector<int>& blobIndices)
500 append(FileListIndexTag);
501 uint32_t length = blobIndices.size();
502 doWriteUint32(length);
503 for (unsigned i = 0; i < length; ++i)
504 doWriteUint32(blobIndices[i]);
507 bool writeCryptoKey(const blink::WebCryptoKey& key)
509 append(static_cast<uint8_t>(CryptoKeyTag));
511 switch (key.algorithm().paramsType()) {
512 case blink::WebCryptoKeyAlgorithmParamsTypeAes:
515 case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
518 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
519 doWriteRsaHashedKey(key);
521 case blink::WebCryptoKeyAlgorithmParamsTypeNone:
522 ASSERT_NOT_REACHED();
526 doWriteKeyUsages(key.usages(), key.extractable());
528 blink::WebVector<uint8_t> keyData;
529 if (!blink::Platform::current()->crypto()->serializeKeyForClone(key, keyData))
532 doWriteUint32(keyData.size());
533 append(keyData.data(), keyData.size());
537 void writeArrayBuffer(const ArrayBuffer& arrayBuffer)
539 append(ArrayBufferTag);
540 doWriteArrayBuffer(arrayBuffer);
543 void writeArrayBufferView(const ArrayBufferView& arrayBufferView)
545 append(ArrayBufferViewTag);
547 const ArrayBuffer& arrayBuffer = *arrayBufferView.buffer();
548 ASSERT(static_cast<const uint8_t*>(arrayBuffer.data()) + arrayBufferView.byteOffset() ==
549 static_cast<const uint8_t*>(arrayBufferView.baseAddress()));
551 ArrayBufferView::ViewType type = arrayBufferView.type();
553 if (type == ArrayBufferView::TypeInt8)
554 append(ByteArrayTag);
555 else if (type == ArrayBufferView::TypeUint8Clamped)
556 append(UnsignedByteClampedArrayTag);
557 else if (type == ArrayBufferView::TypeUint8)
558 append(UnsignedByteArrayTag);
559 else if (type == ArrayBufferView::TypeInt16)
560 append(ShortArrayTag);
561 else if (type == ArrayBufferView::TypeUint16)
562 append(UnsignedShortArrayTag);
563 else if (type == ArrayBufferView::TypeInt32)
565 else if (type == ArrayBufferView::TypeUint32)
566 append(UnsignedIntArrayTag);
567 else if (type == ArrayBufferView::TypeFloat32)
568 append(FloatArrayTag);
569 else if (type == ArrayBufferView::TypeFloat64)
570 append(DoubleArrayTag);
571 else if (type == ArrayBufferView::TypeDataView)
574 ASSERT_NOT_REACHED();
575 doWriteUint32(arrayBufferView.byteOffset());
576 doWriteUint32(arrayBufferView.byteLength());
579 void writeImageData(uint32_t width, uint32_t height, const uint8_t* pixelData, uint32_t pixelDataLength)
581 append(ImageDataTag);
582 doWriteUint32(width);
583 doWriteUint32(height);
584 doWriteUint32(pixelDataLength);
585 append(pixelData, pixelDataLength);
588 void writeRegExp(v8::Local<v8::String> pattern, v8::RegExp::Flags flags)
591 v8::String::Utf8Value patternUtf8Value(pattern);
592 doWriteString(*patternUtf8Value, patternUtf8Value.length());
593 doWriteUint32(static_cast<uint32_t>(flags));
596 void writeTransferredMessagePort(uint32_t index)
598 append(MessagePortTag);
599 doWriteUint32(index);
602 void writeTransferredArrayBuffer(uint32_t index)
604 append(ArrayBufferTransferTag);
605 doWriteUint32(index);
608 void writeObjectReference(uint32_t reference)
610 append(ObjectReferenceTag);
611 doWriteUint32(reference);
614 void writeObject(uint32_t numProperties)
617 doWriteUint32(numProperties);
620 void writeSparseArray(uint32_t numProperties, uint32_t length)
622 append(SparseArrayTag);
623 doWriteUint32(numProperties);
624 doWriteUint32(length);
627 void writeDenseArray(uint32_t numProperties, uint32_t length)
629 append(DenseArrayTag);
630 doWriteUint32(numProperties);
631 doWriteUint32(length);
634 String takeWireString()
636 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
638 String data = String(m_buffer.data(), m_buffer.size());
639 data.impl()->truncateAssumingIsolated((m_position + 1) / sizeof(BufferValueType));
643 void writeReferenceCount(uint32_t numberOfReferences)
645 append(ReferenceCountTag);
646 doWriteUint32(numberOfReferences);
649 void writeGenerateFreshObject()
651 append(GenerateFreshObjectTag);
654 void writeGenerateFreshSparseArray(uint32_t length)
656 append(GenerateFreshSparseArrayTag);
657 doWriteUint32(length);
660 void writeGenerateFreshDenseArray(uint32_t length)
662 append(GenerateFreshDenseArrayTag);
663 doWriteUint32(length);
667 void doWriteFile(const File& file)
669 doWriteWebCoreString(file.hasBackingFile() ? file.path() : "");
670 doWriteWebCoreString(file.name());
671 doWriteWebCoreString(file.webkitRelativePath());
672 doWriteWebCoreString(file.uuid());
673 doWriteWebCoreString(file.type());
675 // FIXME don't use 4 bytes to encode a flag.
676 if (file.hasValidSnapshotMetadata()) {
677 doWriteUint32(static_cast<uint8_t>(1));
681 file.captureSnapshot(size, lastModified);
682 doWriteUint64(static_cast<uint64_t>(size));
683 doWriteNumber(lastModified);
685 append(static_cast<uint8_t>(0));
689 void doWriteArrayBuffer(const ArrayBuffer& arrayBuffer)
691 uint32_t byteLength = arrayBuffer.byteLength();
692 doWriteUint32(byteLength);
693 append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
696 void doWriteString(const char* data, int length)
698 doWriteUint32(static_cast<uint32_t>(length));
699 append(reinterpret_cast<const uint8_t*>(data), length);
702 void doWriteWebCoreString(const String& string)
704 StringUTF8Adaptor stringUTF8(string);
705 doWriteString(stringUTF8.data(), stringUTF8.length());
708 void doWriteHmacKey(const blink::WebCryptoKey& key)
710 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeHmac);
712 append(static_cast<uint8_t>(HmacKeyTag));
713 ASSERT(!(key.algorithm().hmacParams()->lengthBits() % 8));
714 doWriteUint32(key.algorithm().hmacParams()->lengthBits() / 8);
715 doWriteAlgorithmId(key.algorithm().hmacParams()->hash().id());
718 void doWriteAesKey(const blink::WebCryptoKey& key)
720 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeAes);
722 append(static_cast<uint8_t>(AesKeyTag));
723 doWriteAlgorithmId(key.algorithm().id());
724 // Converting the key length from bits to bytes is lossless and makes
726 ASSERT(!(key.algorithm().aesParams()->lengthBits() % 8));
727 doWriteUint32(key.algorithm().aesParams()->lengthBits() / 8);
730 void doWriteRsaHashedKey(const blink::WebCryptoKey& key)
732 ASSERT(key.algorithm().rsaHashedParams());
733 append(static_cast<uint8_t>(RsaHashedKeyTag));
735 doWriteAlgorithmId(key.algorithm().id());
737 switch (key.type()) {
738 case blink::WebCryptoKeyTypePublic:
739 doWriteUint32(PublicKeyType);
741 case blink::WebCryptoKeyTypePrivate:
742 doWriteUint32(PrivateKeyType);
744 case blink::WebCryptoKeyTypeSecret:
745 ASSERT_NOT_REACHED();
748 const blink::WebCryptoRsaHashedKeyAlgorithmParams* params = key.algorithm().rsaHashedParams();
749 doWriteUint32(params->modulusLengthBits());
750 doWriteUint32(params->publicExponent().size());
751 append(params->publicExponent().data(), params->publicExponent().size());
752 doWriteAlgorithmId(key.algorithm().rsaHashedParams()->hash().id());
755 void doWriteAlgorithmId(blink::WebCryptoAlgorithmId id)
758 case blink::WebCryptoAlgorithmIdAesCbc:
759 return doWriteUint32(AesCbcTag);
760 case blink::WebCryptoAlgorithmIdHmac:
761 return doWriteUint32(HmacTag);
762 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
763 return doWriteUint32(RsaSsaPkcs1v1_5Tag);
764 case blink::WebCryptoAlgorithmIdSha1:
765 return doWriteUint32(Sha1Tag);
766 case blink::WebCryptoAlgorithmIdSha256:
767 return doWriteUint32(Sha256Tag);
768 case blink::WebCryptoAlgorithmIdSha384:
769 return doWriteUint32(Sha384Tag);
770 case blink::WebCryptoAlgorithmIdSha512:
771 return doWriteUint32(Sha512Tag);
772 case blink::WebCryptoAlgorithmIdAesGcm:
773 return doWriteUint32(AesGcmTag);
774 case blink::WebCryptoAlgorithmIdRsaOaep:
775 return doWriteUint32(RsaOaepTag);
776 case blink::WebCryptoAlgorithmIdAesCtr:
777 return doWriteUint32(AesCtrTag);
778 case blink::WebCryptoAlgorithmIdAesKw:
779 return doWriteUint32(AesKwTag);
781 ASSERT_NOT_REACHED();
784 void doWriteKeyUsages(const blink::WebCryptoKeyUsageMask usages, bool extractable)
786 // Reminder to update this when adding new key usages.
787 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
792 value |= ExtractableUsage;
794 if (usages & blink::WebCryptoKeyUsageEncrypt)
795 value |= EncryptUsage;
796 if (usages & blink::WebCryptoKeyUsageDecrypt)
797 value |= DecryptUsage;
798 if (usages & blink::WebCryptoKeyUsageSign)
800 if (usages & blink::WebCryptoKeyUsageVerify)
801 value |= VerifyUsage;
802 if (usages & blink::WebCryptoKeyUsageDeriveKey)
803 value |= DeriveKeyUsage;
804 if (usages & blink::WebCryptoKeyUsageWrapKey)
805 value |= WrapKeyUsage;
806 if (usages & blink::WebCryptoKeyUsageUnwrapKey)
807 value |= UnwrapKeyUsage;
808 if (usages & blink::WebCryptoKeyUsageDeriveBits)
809 value |= DeriveBitsUsage;
811 doWriteUint32(value);
814 int bytesNeededToWireEncode(uint32_t value)
818 value >>= varIntShift;
828 void doWriteUintHelper(T value)
831 uint8_t b = (value & varIntMask);
832 value >>= varIntShift;
837 append(b | (1 << varIntShift));
841 void doWriteUint32(uint32_t value)
843 doWriteUintHelper(value);
846 void doWriteUint64(uint64_t value)
848 doWriteUintHelper(value);
851 void doWriteNumber(double number)
853 append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
856 void append(SerializationTag tag)
858 append(static_cast<uint8_t>(tag));
861 void append(uint8_t b)
864 *byteAt(m_position++) = b;
867 void append(const uint8_t* data, int length)
870 memcpy(byteAt(m_position), data, length);
871 m_position += length;
874 void ensureSpace(unsigned extra)
876 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
877 m_buffer.resize((m_position + extra + 1) / sizeof(BufferValueType)); // "+ 1" to round up.
882 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
883 // If the writer is at odd position in the buffer, then one of
884 // the bytes in the last UChar is not initialized.
886 *byteAt(m_position) = static_cast<uint8_t>(PaddingTag);
889 uint8_t* byteAt(int position)
891 return reinterpret_cast<uint8_t*>(m_buffer.data()) + position;
894 int v8StringWriteOptions()
896 return v8::String::NO_NULL_TERMINATION;
899 Vector<BufferValueType> m_buffer;
903 static v8::Handle<v8::Object> toV8Object(MessagePort* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
906 return v8::Handle<v8::Object>();
907 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
908 ASSERT(wrapper->IsObject());
909 return wrapper.As<v8::Object>();
912 static v8::Handle<v8::ArrayBuffer> toV8Object(ArrayBuffer* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
915 return v8::Handle<v8::ArrayBuffer>();
916 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
917 ASSERT(wrapper->IsArrayBuffer());
918 return wrapper.As<v8::ArrayBuffer>();
931 Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, v8::TryCatch& tryCatch, ScriptState* scriptState)
932 : m_scriptState(scriptState)
934 , m_tryCatch(tryCatch)
937 , m_nextObjectReference(0)
938 , m_blobInfo(blobInfo)
939 , m_blobDataHandles(blobDataHandles)
941 ASSERT(!tryCatch.HasCaught());
942 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
944 for (size_t i = 0; i < messagePorts->size(); i++)
945 m_transferredMessagePorts.set(toV8Object(messagePorts->at(i).get(), creationContext, isolate()), i);
948 for (size_t i = 0; i < arrayBuffers->size(); i++) {
949 v8::Handle<v8::Object> v8ArrayBuffer = toV8Object(arrayBuffers->at(i).get(), creationContext, isolate());
950 // Coalesce multiple occurences of the same buffer to the first index.
951 if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
952 m_transferredArrayBuffers.set(v8ArrayBuffer, i);
957 v8::Isolate* isolate() { return m_scriptState->isolate(); }
959 Status serialize(v8::Handle<v8::Value> value)
961 v8::HandleScope scope(isolate());
962 m_writer.writeVersion();
963 StateBase* state = doSerialize(value, 0);
965 state = state->advance(*this);
969 String errorMessage() { return m_errorMessage; }
971 // Functions used by serialization states.
972 StateBase* doSerialize(v8::Handle<v8::Value>, StateBase* next);
974 StateBase* doSerializeArrayBuffer(v8::Handle<v8::Value> arrayBuffer, StateBase* next)
976 return doSerialize(arrayBuffer, next);
979 StateBase* checkException(StateBase* state)
981 return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0;
984 StateBase* writeObject(uint32_t numProperties, StateBase* state)
986 m_writer.writeObject(numProperties);
990 StateBase* writeSparseArray(uint32_t numProperties, uint32_t length, StateBase* state)
992 m_writer.writeSparseArray(numProperties, length);
996 StateBase* writeDenseArray(uint32_t numProperties, uint32_t length, StateBase* state)
998 m_writer.writeDenseArray(numProperties, length);
1005 WTF_MAKE_NONCOPYABLE(StateBase);
1007 virtual ~StateBase() { }
1009 // Link to the next state to form a stack.
1010 StateBase* nextState() { return m_next; }
1012 // Composite object we're processing in this state.
1013 v8::Handle<v8::Value> composite() { return m_composite; }
1015 // Serializes (a part of) the current composite and returns
1016 // the next state to process or null when this is the final
1018 virtual StateBase* advance(Serializer&) = 0;
1021 StateBase(v8::Handle<v8::Value> composite, StateBase* next)
1022 : m_composite(composite)
1028 v8::Handle<v8::Value> m_composite;
1032 // Dummy state that is used to signal serialization errors.
1033 class ErrorState FINAL : public StateBase {
1036 : StateBase(v8Undefined(), 0)
1040 virtual StateBase* advance(Serializer&) OVERRIDE
1047 template <typename T>
1048 class State : public StateBase {
1050 v8::Handle<T> composite() { return v8::Handle<T>::Cast(StateBase::composite()); }
1053 State(v8::Handle<T> composite, StateBase* next)
1054 : StateBase(composite, next)
1059 class AbstractObjectState : public State<v8::Object> {
1061 AbstractObjectState(v8::Handle<v8::Object> object, StateBase* next)
1062 : State<v8::Object>(object, next)
1064 , m_numSerializedProperties(0)
1070 virtual StateBase* objectDone(unsigned numProperties, Serializer&) = 0;
1072 StateBase* serializeProperties(bool ignoreIndexed, Serializer& serializer)
1074 while (m_index < m_propertyNames->Length()) {
1076 v8::Local<v8::Value> propertyName = m_propertyNames->Get(m_index);
1077 if (StateBase* newState = serializer.checkException(this))
1079 if (propertyName.IsEmpty())
1080 return serializer.handleError(InputError, "Empty property names cannot be cloned.", this);
1081 bool hasStringProperty = propertyName->IsString() && composite()->HasRealNamedProperty(propertyName.As<v8::String>());
1082 if (StateBase* newState = serializer.checkException(this))
1084 bool hasIndexedProperty = !hasStringProperty && propertyName->IsUint32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value());
1085 if (StateBase* newState = serializer.checkException(this))
1087 if (hasStringProperty || (hasIndexedProperty && !ignoreIndexed))
1088 m_propertyName = propertyName;
1094 ASSERT(!m_propertyName.IsEmpty());
1097 if (StateBase* newState = serializer.doSerialize(m_propertyName, this))
1100 v8::Local<v8::Value> value = composite()->Get(m_propertyName);
1101 if (StateBase* newState = serializer.checkException(this))
1104 m_propertyName.Clear();
1106 ++m_numSerializedProperties;
1107 // If we return early here, it's either because we have pushed a new state onto the
1108 // serialization state stack or because we have encountered an error (and in both cases
1109 // we are unwinding the native stack).
1110 if (StateBase* newState = serializer.doSerialize(value, this))
1113 return objectDone(m_numSerializedProperties, serializer);
1116 v8::Local<v8::Array> m_propertyNames;
1119 v8::Local<v8::Value> m_propertyName;
1121 unsigned m_numSerializedProperties;
1125 class ObjectState FINAL : public AbstractObjectState {
1127 ObjectState(v8::Handle<v8::Object> object, StateBase* next)
1128 : AbstractObjectState(object, next)
1132 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1134 if (m_propertyNames.IsEmpty()) {
1135 m_propertyNames = composite()->GetPropertyNames();
1136 if (StateBase* newState = serializer.checkException(this))
1138 if (m_propertyNames.IsEmpty())
1139 return serializer.handleError(InputError, "Empty property names cannot be cloned.", nextState());
1141 return serializeProperties(false, serializer);
1145 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1147 return serializer.writeObject(numProperties, this);
1151 class DenseArrayState FINAL : public AbstractObjectState {
1153 DenseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
1154 : AbstractObjectState(array, next)
1156 , m_arrayLength(array->Length())
1158 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
1161 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1163 while (m_arrayIndex < m_arrayLength) {
1164 v8::Handle<v8::Value> value = composite().As<v8::Array>()->Get(m_arrayIndex);
1166 if (StateBase* newState = serializer.checkException(this))
1168 if (StateBase* newState = serializer.doSerialize(value, this))
1171 return serializeProperties(true, serializer);
1175 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1177 return serializer.writeDenseArray(numProperties, m_arrayLength, this);
1181 uint32_t m_arrayIndex;
1182 uint32_t m_arrayLength;
1185 class SparseArrayState FINAL : public AbstractObjectState {
1187 SparseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
1188 : AbstractObjectState(array, next)
1190 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
1193 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1195 return serializeProperties(false, serializer);
1199 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1201 return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this);
1205 StateBase* push(StateBase* state)
1209 return checkComposite(state) ? state : handleError(InputError, "Value being cloned is either cyclic or too deeply nested.", state);
1212 StateBase* pop(StateBase* state)
1216 StateBase* next = state->nextState();
1221 StateBase* handleError(Status errorStatus, const String& message, StateBase* state)
1223 ASSERT(errorStatus != Success);
1224 m_status = errorStatus;
1225 m_errorMessage = message;
1227 StateBase* tmp = state->nextState();
1231 return new ErrorState;
1234 bool checkComposite(StateBase* top)
1237 if (m_depth > maxDepth)
1239 if (!shouldCheckForCycles(m_depth))
1241 v8::Handle<v8::Value> composite = top->composite();
1242 for (StateBase* state = top->nextState(); state; state = state->nextState()) {
1243 if (state->composite() == composite)
1249 void writeString(v8::Handle<v8::Value> value)
1251 v8::Handle<v8::String> string = value.As<v8::String>();
1252 if (!string->Length() || string->IsOneByte())
1253 m_writer.writeOneByteString(string);
1255 m_writer.writeUCharString(string);
1258 void writeStringObject(v8::Handle<v8::Value> value)
1260 v8::Handle<v8::StringObject> stringObject = value.As<v8::StringObject>();
1261 v8::String::Utf8Value stringValue(stringObject->ValueOf());
1262 m_writer.writeStringObject(*stringValue, stringValue.length());
1265 void writeNumberObject(v8::Handle<v8::Value> value)
1267 v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
1268 m_writer.writeNumberObject(numberObject->ValueOf());
1271 void writeBooleanObject(v8::Handle<v8::Value> value)
1273 v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
1274 m_writer.writeBooleanObject(booleanObject->ValueOf());
1277 StateBase* writeBlob(v8::Handle<v8::Value> value, StateBase* next)
1279 Blob* blob = V8Blob::toNative(value.As<v8::Object>());
1282 if (blob->hasBeenClosed())
1283 return handleError(DataCloneError, "A Blob object has been closed, and could therefore not be cloned.", next);
1285 m_blobDataHandles.add(blob->uuid(), blob->blobDataHandle());
1286 if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex))
1287 m_writer.writeBlobIndex(blobIndex);
1289 m_writer.writeBlob(blob->uuid(), blob->type(), blob->size());
1293 StateBase* writeDOMFileSystem(v8::Handle<v8::Value> value, StateBase* next)
1295 DOMFileSystem* fs = V8DOMFileSystem::toNative(value.As<v8::Object>());
1298 if (!fs->clonable())
1299 return handleError(DataCloneError, "A FileSystem object could not be cloned.", next);
1300 m_writer.writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().string());
1304 StateBase* writeFile(v8::Handle<v8::Value> value, StateBase* next)
1306 File* file = V8File::toNative(value.As<v8::Object>());
1309 if (file->hasBeenClosed())
1310 return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
1312 m_blobDataHandles.add(file->uuid(), file->blobDataHandle());
1313 if (appendFileInfo(file, &blobIndex)) {
1314 ASSERT(blobIndex >= 0);
1315 m_writer.writeFileIndex(blobIndex);
1317 m_writer.writeFile(*file);
1322 StateBase* writeFileList(v8::Handle<v8::Value> value, StateBase* next)
1324 FileList* fileList = V8FileList::toNative(value.As<v8::Object>());
1327 unsigned length = fileList->length();
1328 Vector<int> blobIndices;
1329 for (unsigned i = 0; i < length; ++i) {
1331 const File* file = fileList->item(i);
1332 if (file->hasBeenClosed())
1333 return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
1334 m_blobDataHandles.add(file->uuid(), file->blobDataHandle());
1335 if (appendFileInfo(file, &blobIndex)) {
1336 ASSERT(!i || blobIndex > 0);
1337 ASSERT(blobIndex >= 0);
1338 blobIndices.append(blobIndex);
1341 if (!blobIndices.isEmpty())
1342 m_writer.writeFileListIndex(blobIndices);
1344 m_writer.writeFileList(*fileList);
1348 bool writeCryptoKey(v8::Handle<v8::Value> value)
1350 Key* key = V8Key::toNative(value.As<v8::Object>());
1353 return m_writer.writeCryptoKey(key->key());
1356 void writeImageData(v8::Handle<v8::Value> value)
1358 ImageData* imageData = V8ImageData::toNative(value.As<v8::Object>());
1361 Uint8ClampedArray* pixelArray = imageData->data();
1362 m_writer.writeImageData(imageData->width(), imageData->height(), pixelArray->data(), pixelArray->length());
1365 void writeRegExp(v8::Handle<v8::Value> value)
1367 v8::Handle<v8::RegExp> regExp = value.As<v8::RegExp>();
1368 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
1371 StateBase* writeAndGreyArrayBufferView(v8::Handle<v8::Object> object, StateBase* next)
1373 ASSERT(!object.IsEmpty());
1374 ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(object);
1375 if (!arrayBufferView)
1377 if (!arrayBufferView->buffer())
1378 return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
1379 v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer(), m_scriptState->context()->Global(), isolate());
1380 if (underlyingBuffer.IsEmpty())
1381 return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
1382 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
1385 m_writer.writeArrayBufferView(*arrayBufferView);
1386 // This should be safe: we serialize something that we know to be a wrapper (see
1387 // the toV8 call above), so the call to doSerializeArrayBuffer should neither
1388 // cause the system stack to overflow nor should it have potential to reach
1389 // this ArrayBufferView again.
1391 // We do need to grey the underlying buffer before we grey its view, however;
1392 // ArrayBuffers may be shared, so they need to be given reference IDs, and an
1393 // ArrayBufferView cannot be constructed without a corresponding ArrayBuffer
1394 // (or without an additional tag that would allow us to do two-stage construction
1395 // like we do for Objects and Arrays).
1400 StateBase* writeArrayBuffer(v8::Handle<v8::Value> value, StateBase* next)
1402 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>());
1405 if (arrayBuffer->isNeutered())
1406 return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
1407 ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>()));
1408 m_writer.writeArrayBuffer(*arrayBuffer);
1412 StateBase* writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t index, StateBase* next)
1414 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>());
1417 if (arrayBuffer->isNeutered())
1418 return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
1419 m_writer.writeTransferredArrayBuffer(index);
1423 static bool shouldSerializeDensely(uint32_t length, uint32_t propertyCount)
1425 // Let K be the cost of serializing all property values that are there
1426 // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32_t key)
1427 // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte for all properties that are not there)
1428 // so densely is better than sparsly whenever 6*propertyCount > length
1429 return 6 * propertyCount >= length;
1432 StateBase* startArrayState(v8::Handle<v8::Array> array, StateBase* next)
1434 v8::Handle<v8::Array> propertyNames = array->GetPropertyNames();
1435 if (StateBase* newState = checkException(next))
1437 uint32_t length = array->Length();
1439 if (shouldSerializeDensely(length, propertyNames->Length())) {
1440 m_writer.writeGenerateFreshDenseArray(length);
1441 return push(new DenseArrayState(array, propertyNames, next, isolate()));
1444 m_writer.writeGenerateFreshSparseArray(length);
1445 return push(new SparseArrayState(array, propertyNames, next, isolate()));
1448 StateBase* startObjectState(v8::Handle<v8::Object> object, StateBase* next)
1450 m_writer.writeGenerateFreshObject();
1451 // FIXME: check not a wrapper
1452 return push(new ObjectState(object, next));
1455 // Marks object as having been visited by the serializer and assigns it a unique object reference ID.
1456 // An object may only be greyed once.
1457 void greyObject(const v8::Handle<v8::Object>& object)
1459 ASSERT(!m_objectPool.contains(object));
1460 uint32_t objectReference = m_nextObjectReference++;
1461 m_objectPool.set(object, objectReference);
1464 bool appendBlobInfo(const String& uuid, const String& type, unsigned long long size, int* index)
1468 *index = m_blobInfo->size();
1469 m_blobInfo->append(blink::WebBlobInfo(uuid, type, size));
1473 bool appendFileInfo(const File* file, int* index)
1478 long long size = -1;
1479 double lastModified = invalidFileTime();
1480 file->captureSnapshot(size, lastModified);
1481 *index = m_blobInfo->size();
1482 m_blobInfo->append(blink::WebBlobInfo(file->uuid(), file->path(), file->name(), file->type(), lastModified, size));
1486 RefPtr<ScriptState> m_scriptState;
1488 v8::TryCatch& m_tryCatch;
1491 String m_errorMessage;
1492 typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool;
1493 ObjectPool m_objectPool;
1494 ObjectPool m_transferredMessagePorts;
1495 ObjectPool m_transferredArrayBuffers;
1496 uint32_t m_nextObjectReference;
1497 WebBlobInfoArray* m_blobInfo;
1498 BlobDataHandleMap& m_blobDataHandles;
1501 // Returns true if the provided object is to be considered a 'host object', as used in the
1502 // HTML5 structured clone algorithm.
1503 static bool isHostObject(v8::Handle<v8::Object> object)
1505 // If the object has any internal fields, then we won't be able to serialize or deserialize
1506 // them; conveniently, this is also a quick way to detect DOM wrapper objects, because
1507 // the mechanism for these relies on data stored in these fields. We should
1508 // catch external array data as a special case.
1509 return object->InternalFieldCount() || object->HasIndexedPropertiesInExternalArrayData();
1512 Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, StateBase* next)
1514 m_writer.writeReferenceCount(m_nextObjectReference);
1515 uint32_t objectReference;
1516 uint32_t arrayBufferIndex;
1517 if ((value->IsObject() || value->IsDate() || value->IsRegExp())
1518 && m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
1519 // Note that IsObject() also detects wrappers (eg, it will catch the things
1520 // that we grey and write below).
1521 ASSERT(!value->IsString());
1522 m_writer.writeObjectReference(objectReference);
1523 } else if (value.IsEmpty()) {
1524 return handleError(InputError, "The empty property name cannot be cloned.", next);
1525 } else if (value->IsUndefined())
1526 m_writer.writeUndefined();
1527 else if (value->IsNull())
1528 m_writer.writeNull();
1529 else if (value->IsTrue())
1530 m_writer.writeTrue();
1531 else if (value->IsFalse())
1532 m_writer.writeFalse();
1533 else if (value->IsInt32())
1534 m_writer.writeInt32(value->Int32Value());
1535 else if (value->IsUint32())
1536 m_writer.writeUint32(value->Uint32Value());
1537 else if (value->IsNumber())
1538 m_writer.writeNumber(value.As<v8::Number>()->Value());
1539 else if (V8ArrayBufferView::hasInstance(value, isolate()))
1540 return writeAndGreyArrayBufferView(value.As<v8::Object>(), next);
1541 else if (value->IsString())
1543 else if (V8MessagePort::hasInstance(value, isolate())) {
1544 uint32_t messagePortIndex;
1545 if (m_transferredMessagePorts.tryGet(value.As<v8::Object>(), &messagePortIndex))
1546 m_writer.writeTransferredMessagePort(messagePortIndex);
1548 return handleError(DataCloneError, "A MessagePort could not be cloned.", next);
1549 } else if (V8ArrayBuffer::hasInstance(value, isolate()) && m_transferredArrayBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex))
1550 return writeTransferredArrayBuffer(value, arrayBufferIndex, next);
1552 v8::Handle<v8::Object> jsObject = value.As<v8::Object>();
1553 if (jsObject.IsEmpty())
1554 return handleError(DataCloneError, "An object could not be cloned.", next);
1555 greyObject(jsObject);
1556 if (value->IsDate())
1557 m_writer.writeDate(value->NumberValue());
1558 else if (value->IsStringObject())
1559 writeStringObject(value);
1560 else if (value->IsNumberObject())
1561 writeNumberObject(value);
1562 else if (value->IsBooleanObject())
1563 writeBooleanObject(value);
1564 else if (value->IsArray()) {
1565 return startArrayState(value.As<v8::Array>(), next);
1566 } else if (V8File::hasInstance(value, isolate()))
1567 return writeFile(value, next);
1568 else if (V8Blob::hasInstance(value, isolate()))
1569 return writeBlob(value, next);
1570 else if (V8DOMFileSystem::hasInstance(value, isolate()))
1571 return writeDOMFileSystem(value, next);
1572 else if (V8FileList::hasInstance(value, isolate()))
1573 return writeFileList(value, next);
1574 else if (V8Key::hasInstance(value, isolate())) {
1575 if (!writeCryptoKey(value))
1576 return handleError(DataCloneError, "Couldn't serialize key data", next);
1577 } else if (V8ImageData::hasInstance(value, isolate()))
1578 writeImageData(value);
1579 else if (value->IsRegExp())
1581 else if (V8ArrayBuffer::hasInstance(value, isolate()))
1582 return writeArrayBuffer(value, next);
1583 else if (value->IsObject()) {
1584 if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
1585 return handleError(DataCloneError, "An object could not be cloned.", next);
1586 return startObjectState(jsObject, next);
1588 return handleError(DataCloneError, "A value could not be cloned.", next);
1593 // Interface used by Reader to create objects of composite types.
1594 class CompositeCreator {
1596 virtual ~CompositeCreator() { }
1598 virtual bool consumeTopOfStack(v8::Handle<v8::Value>*) = 0;
1599 virtual uint32_t objectReferenceCount() = 0;
1600 virtual void pushObjectReference(const v8::Handle<v8::Value>&) = 0;
1601 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>*) = 0;
1602 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>*) = 0;
1603 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>*) = 0;
1604 virtual bool newSparseArray(uint32_t length) = 0;
1605 virtual bool newDenseArray(uint32_t length) = 0;
1606 virtual bool newObject() = 0;
1607 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>*) = 0;
1608 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>*) = 0;
1609 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>*) = 0;
1612 // Reader is responsible for deserializing primitive types and
1613 // restoring information about saved objects of composite types.
1616 Reader(const uint8_t* buffer, int length, const WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, ScriptState* scriptState)
1617 : m_scriptState(scriptState)
1622 , m_blobInfo(blobInfo)
1623 , m_blobDataHandles(blobDataHandles)
1625 ASSERT(!(reinterpret_cast<size_t>(buffer) & 1));
1626 ASSERT(length >= 0);
1629 bool isEof() const { return m_position >= m_length; }
1631 ScriptState* scriptState() const { return m_scriptState.get(); }
1634 v8::Isolate* isolate() const { return m_scriptState->isolate(); }
1637 bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator)
1639 SerializationTag tag;
1643 case ReferenceCountTag: {
1646 uint32_t referenceTableSize;
1647 if (!doReadUint32(&referenceTableSize))
1649 // If this test fails, then the serializer and deserializer disagree about the assignment
1650 // of object reference IDs. On the deserialization side, this means there are too many or too few
1651 // calls to pushObjectReference.
1652 if (referenceTableSize != creator.objectReferenceCount())
1661 *value = v8::Undefined(isolate());
1664 *value = v8::Null(isolate());
1667 *value = v8Boolean(true, isolate());
1670 *value = v8Boolean(false, isolate());
1673 *value = v8::BooleanObject::New(true);
1674 creator.pushObjectReference(*value);
1676 case FalseObjectTag:
1677 *value = v8::BooleanObject::New(false);
1678 creator.pushObjectReference(*value);
1681 if (!readString(value))
1684 case StringUCharTag:
1685 if (!readUCharString(value))
1688 case StringObjectTag:
1689 if (!readStringObject(value))
1691 creator.pushObjectReference(*value);
1694 if (!readInt32(value))
1698 if (!readUint32(value))
1702 if (!readDate(value))
1704 creator.pushObjectReference(*value);
1707 if (!readNumber(value))
1710 case NumberObjectTag:
1711 if (!readNumberObject(value))
1713 creator.pushObjectReference(*value);
1717 if (!readBlob(value, tag == BlobIndexTag))
1719 creator.pushObjectReference(*value);
1723 if (!readFile(value, tag == FileIndexTag))
1725 creator.pushObjectReference(*value);
1727 case DOMFileSystemTag:
1728 if (!readDOMFileSystem(value))
1730 creator.pushObjectReference(*value);
1733 case FileListIndexTag:
1734 if (!readFileList(value, tag == FileListIndexTag))
1736 creator.pushObjectReference(*value);
1739 if (!readCryptoKey(value))
1741 creator.pushObjectReference(*value);
1744 if (!readImageData(value))
1746 creator.pushObjectReference(*value);
1750 if (!readRegExp(value))
1752 creator.pushObjectReference(*value);
1755 uint32_t numProperties;
1756 if (!doReadUint32(&numProperties))
1758 if (!creator.completeObject(numProperties, value))
1762 case SparseArrayTag: {
1763 uint32_t numProperties;
1765 if (!doReadUint32(&numProperties))
1767 if (!doReadUint32(&length))
1769 if (!creator.completeSparseArray(numProperties, length, value))
1773 case DenseArrayTag: {
1774 uint32_t numProperties;
1776 if (!doReadUint32(&numProperties))
1778 if (!doReadUint32(&length))
1780 if (!creator.completeDenseArray(numProperties, length, value))
1784 case ArrayBufferViewTag: {
1787 if (!readArrayBufferView(value, creator))
1789 creator.pushObjectReference(*value);
1792 case ArrayBufferTag: {
1795 if (!readArrayBuffer(value))
1797 creator.pushObjectReference(*value);
1800 case GenerateFreshObjectTag: {
1803 if (!creator.newObject())
1807 case GenerateFreshSparseArrayTag: {
1811 if (!doReadUint32(&length))
1813 if (!creator.newSparseArray(length))
1817 case GenerateFreshDenseArrayTag: {
1821 if (!doReadUint32(&length))
1823 if (!creator.newDenseArray(length))
1827 case MessagePortTag: {
1831 if (!doReadUint32(&index))
1833 if (!creator.tryGetTransferredMessagePort(index, value))
1837 case ArrayBufferTransferTag: {
1841 if (!doReadUint32(&index))
1843 if (!creator.tryGetTransferredArrayBuffer(index, value))
1847 case ObjectReferenceTag: {
1851 if (!doReadUint32(&reference))
1853 if (!creator.tryGetObjectFromObjectReference(reference, value))
1860 return !value->IsEmpty();
1863 bool readVersion(uint32_t& version)
1865 SerializationTag tag;
1866 if (!readTag(&tag)) {
1867 // This is a nullary buffer. We're still version 0.
1871 if (tag != VersionTag) {
1872 // Versions of the format past 0 start with the version tag.
1874 // Put back the tag.
1878 // Version-bearing messages are obligated to finish the version tag.
1879 return doReadUint32(&version);
1882 void setVersion(uint32_t version)
1884 m_version = version;
1888 bool readTag(SerializationTag* tag)
1890 if (m_position >= m_length)
1892 *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
1902 bool readArrayBufferViewSubTag(ArrayBufferViewSubTag* tag)
1904 if (m_position >= m_length)
1906 *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]);
1910 bool readString(v8::Handle<v8::Value>* value)
1913 if (!doReadUint32(&length))
1915 if (m_position + length > m_length)
1917 *value = v8::String::NewFromUtf8(isolate(), reinterpret_cast<const char*>(m_buffer + m_position), v8::String::kNormalString, length);
1918 m_position += length;
1922 bool readUCharString(v8::Handle<v8::Value>* value)
1925 if (!doReadUint32(&length) || (length & 1))
1927 if (m_position + length > m_length)
1929 ASSERT(!(m_position & 1));
1930 *value = v8::String::NewFromTwoByte(isolate(), reinterpret_cast<const uint16_t*>(m_buffer + m_position), v8::String::kNormalString, length / sizeof(UChar));
1931 m_position += length;
1935 bool readStringObject(v8::Handle<v8::Value>* value)
1937 v8::Handle<v8::Value> stringValue;
1938 if (!readString(&stringValue) || !stringValue->IsString())
1940 *value = v8::StringObject::New(stringValue.As<v8::String>());
1944 bool readWebCoreString(String* string)
1947 if (!doReadUint32(&length))
1949 if (m_position + length > m_length)
1951 *string = String::fromUTF8(reinterpret_cast<const char*>(m_buffer + m_position), length);
1952 m_position += length;
1956 bool readInt32(v8::Handle<v8::Value>* value)
1959 if (!doReadUint32(&rawValue))
1961 *value = v8::Integer::New(isolate(), static_cast<int32_t>(ZigZag::decode(rawValue)));
1965 bool readUint32(v8::Handle<v8::Value>* value)
1968 if (!doReadUint32(&rawValue))
1970 *value = v8::Integer::NewFromUnsigned(isolate(), rawValue);
1974 bool readDate(v8::Handle<v8::Value>* value)
1977 if (!doReadNumber(&numberValue))
1979 *value = v8DateOrNaN(numberValue, isolate());
1983 bool readNumber(v8::Handle<v8::Value>* value)
1986 if (!doReadNumber(&number))
1988 *value = v8::Number::New(isolate(), number);
1992 bool readNumberObject(v8::Handle<v8::Value>* value)
1995 if (!doReadNumber(&number))
1997 *value = v8::NumberObject::New(isolate(), number);
2001 bool readImageData(v8::Handle<v8::Value>* value)
2005 uint32_t pixelDataLength;
2006 if (!doReadUint32(&width))
2008 if (!doReadUint32(&height))
2010 if (!doReadUint32(&pixelDataLength))
2012 if (m_position + pixelDataLength > m_length)
2014 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(IntSize(width, height));
2015 Uint8ClampedArray* pixelArray = imageData->data();
2017 ASSERT(pixelArray->length() >= pixelDataLength);
2018 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
2019 m_position += pixelDataLength;
2020 *value = toV8(imageData.release(), m_scriptState->context()->Global(), isolate());
2024 PassRefPtr<ArrayBuffer> doReadArrayBuffer()
2026 uint32_t byteLength;
2027 if (!doReadUint32(&byteLength))
2029 if (m_position + byteLength > m_length)
2031 const void* bufferStart = m_buffer + m_position;
2032 RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(bufferStart, byteLength);
2033 arrayBuffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
2034 m_position += byteLength;
2035 return arrayBuffer.release();
2038 bool readArrayBuffer(v8::Handle<v8::Value>* value)
2040 RefPtr<ArrayBuffer> arrayBuffer = doReadArrayBuffer();
2043 *value = toV8(arrayBuffer.release(), m_scriptState->context()->Global(), isolate());
2047 bool readArrayBufferView(v8::Handle<v8::Value>* value, CompositeCreator& creator)
2049 ArrayBufferViewSubTag subTag;
2050 uint32_t byteOffset;
2051 uint32_t byteLength;
2052 RefPtr<ArrayBuffer> arrayBuffer;
2053 v8::Handle<v8::Value> arrayBufferV8Value;
2054 if (!readArrayBufferViewSubTag(&subTag))
2056 if (!doReadUint32(&byteOffset))
2058 if (!doReadUint32(&byteLength))
2060 if (!creator.consumeTopOfStack(&arrayBufferV8Value))
2062 if (arrayBufferV8Value.IsEmpty())
2064 arrayBuffer = V8ArrayBuffer::toNative(arrayBufferV8Value.As<v8::Object>());
2068 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
2071 *value = toV8(Int8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2073 case UnsignedByteArrayTag:
2074 *value = toV8(Uint8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2076 case UnsignedByteClampedArrayTag:
2077 *value = toV8(Uint8ClampedArray::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2079 case ShortArrayTag: {
2080 uint32_t shortLength = byteLength / sizeof(int16_t);
2081 if (shortLength * sizeof(int16_t) != byteLength)
2083 *value = toV8(Int16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
2086 case UnsignedShortArrayTag: {
2087 uint32_t shortLength = byteLength / sizeof(uint16_t);
2088 if (shortLength * sizeof(uint16_t) != byteLength)
2090 *value = toV8(Uint16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
2094 uint32_t intLength = byteLength / sizeof(int32_t);
2095 if (intLength * sizeof(int32_t) != byteLength)
2097 *value = toV8(Int32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
2100 case UnsignedIntArrayTag: {
2101 uint32_t intLength = byteLength / sizeof(uint32_t);
2102 if (intLength * sizeof(uint32_t) != byteLength)
2104 *value = toV8(Uint32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
2107 case FloatArrayTag: {
2108 uint32_t floatLength = byteLength / sizeof(float);
2109 if (floatLength * sizeof(float) != byteLength)
2111 *value = toV8(Float32Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
2114 case DoubleArrayTag: {
2115 uint32_t floatLength = byteLength / sizeof(double);
2116 if (floatLength * sizeof(double) != byteLength)
2118 *value = toV8(Float64Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
2122 *value = toV8(DataView::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2127 // The various *Array::create() methods will return null if the range the view expects is
2128 // mismatched with the range the buffer can provide or if the byte offset is not aligned
2129 // to the size of the element type.
2130 return !value->IsEmpty();
2133 bool readRegExp(v8::Handle<v8::Value>* value)
2135 v8::Handle<v8::Value> pattern;
2136 if (!readString(&pattern))
2139 if (!doReadUint32(&flags))
2141 *value = v8::RegExp::New(pattern.As<v8::String>(), static_cast<v8::RegExp::Flags>(flags));
2145 bool readBlob(v8::Handle<v8::Value>* value, bool isIndexed)
2149 RefPtrWillBeRawPtr<Blob> blob;
2155 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2157 const blink::WebBlobInfo& info = (*m_blobInfo)[index];
2158 blob = Blob::create(getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2160 ASSERT(!m_blobInfo);
2164 ASSERT(!m_blobInfo);
2165 if (!readWebCoreString(&uuid))
2167 if (!readWebCoreString(&type))
2169 if (!doReadUint64(&size))
2171 blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size));
2173 *value = toV8(blob.release(), m_scriptState->context()->Global(), isolate());
2177 bool readDOMFileSystem(v8::Handle<v8::Value>* value)
2182 if (!doReadUint32(&type))
2184 if (!readWebCoreString(&name))
2186 if (!readWebCoreString(&url))
2188 DOMFileSystem* fs = DOMFileSystem::create(m_scriptState->executionContext(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, url));
2189 *value = toV8(fs, m_scriptState->context()->Global(), isolate());
2193 bool readFile(v8::Handle<v8::Value>* value, bool isIndexed)
2195 RefPtrWillBeRawPtr<File> file;
2199 file = readFileIndexHelper();
2201 file = readFileHelper();
2205 *value = toV8(file.release(), m_scriptState->context()->Global(), isolate());
2209 bool readFileList(v8::Handle<v8::Value>* value, bool isIndexed)
2214 if (!doReadUint32(&length))
2216 RefPtrWillBeRawPtr<FileList> fileList = FileList::create();
2217 for (unsigned i = 0; i < length; ++i) {
2218 RefPtrWillBeRawPtr<File> file;
2222 file = readFileIndexHelper();
2224 file = readFileHelper();
2228 fileList->append(file.release());
2230 *value = toV8(fileList.release(), m_scriptState->context()->Global(), isolate());
2234 bool readCryptoKey(v8::Handle<v8::Value>* value)
2236 uint32_t rawKeyType;
2237 if (!doReadUint32(&rawKeyType))
2240 blink::WebCryptoKeyAlgorithm algorithm;
2241 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret;
2243 switch (static_cast<CryptoKeySubTag>(rawKeyType)) {
2245 if (!doReadAesKey(algorithm, type))
2249 if (!doReadHmacKey(algorithm, type))
2252 case RsaHashedKeyTag:
2253 if (!doReadRsaHashedKey(algorithm, type))
2260 blink::WebCryptoKeyUsageMask usages;
2262 if (!doReadKeyUsages(usages, extractable))
2265 uint32_t keyDataLength;
2266 if (!doReadUint32(&keyDataLength))
2269 if (m_position + keyDataLength > m_length)
2272 const uint8_t* keyData = m_buffer + m_position;
2273 m_position += keyDataLength;
2275 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2276 if (!blink::Platform::current()->crypto()->deserializeKeyForClone(
2277 algorithm, type, extractable, usages, keyData, keyDataLength, key)) {
2281 *value = toV8(Key::create(key), m_scriptState->context()->Global(), isolate());
2285 PassRefPtrWillBeRawPtr<File> readFileHelper()
2289 ASSERT(!m_blobInfo);
2292 String relativePath;
2295 uint32_t hasSnapshot = 0;
2297 double lastModified = 0;
2298 if (!readWebCoreString(&path))
2300 if (m_version >= 4 && !readWebCoreString(&name))
2302 if (m_version >= 4 && !readWebCoreString(&relativePath))
2304 if (!readWebCoreString(&uuid))
2306 if (!readWebCoreString(&type))
2308 if (m_version >= 4 && !doReadUint32(&hasSnapshot))
2311 if (!doReadUint64(&size))
2313 if (!doReadNumber(&lastModified))
2316 return File::create(path, name, relativePath, hasSnapshot > 0, size, lastModified, getOrCreateBlobDataHandle(uuid, type));
2319 PassRefPtrWillBeRawPtr<File> readFileIndexHelper()
2325 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2327 const blink::WebBlobInfo& info = (*m_blobInfo)[index];
2328 return File::create(info.filePath(), info.fileName(), info.size(), info.lastModified(), getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2332 bool doReadUintHelper(T* value)
2335 uint8_t currentByte;
2338 if (m_position >= m_length)
2340 currentByte = m_buffer[m_position++];
2341 *value |= ((currentByte & varIntMask) << shift);
2342 shift += varIntShift;
2343 } while (currentByte & (1 << varIntShift));
2347 bool doReadUint32(uint32_t* value)
2349 return doReadUintHelper(value);
2352 bool doReadUint64(uint64_t* value)
2354 return doReadUintHelper(value);
2357 bool doReadNumber(double* number)
2359 if (m_position + sizeof(double) > m_length)
2361 uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number);
2362 for (unsigned i = 0; i < sizeof(double); ++i)
2363 numberAsByteArray[i] = m_buffer[m_position++];
2367 PassRefPtr<BlobDataHandle> getOrCreateBlobDataHandle(const String& uuid, const String& type, long long size = -1)
2369 // The containing ssv may have a BDH for this uuid if this ssv is just being
2370 // passed from main to worker thread (for example). We use those values when creating
2371 // the new blob instead of cons'ing up a new BDH.
2373 // FIXME: Maybe we should require that it work that way where the ssv must have a BDH for any
2374 // blobs it comes across during deserialization. Would require callers to explicitly populate
2375 // the collection of BDH's for blobs to work, which would encourage lifetimes to be considered
2376 // when passing ssv's around cross process. At present, we get 'lucky' in some cases because
2377 // the blob in the src process happens to still exist at the time the dest process is deserializing.
2378 // For example in sharedWorker.postMessage(...).
2379 BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid);
2380 if (it != m_blobDataHandles.end()) {
2381 // make assertions about type and size?
2384 return BlobDataHandle::create(uuid, type, size);
2387 bool doReadHmacKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2389 uint32_t lengthBytes;
2390 if (!doReadUint32(&lengthBytes))
2392 blink::WebCryptoAlgorithmId hash;
2393 if (!doReadAlgorithmId(hash))
2395 algorithm = blink::WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes * 8);
2396 type = blink::WebCryptoKeyTypeSecret;
2397 return !algorithm.isNull();
2400 bool doReadAesKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2402 blink::WebCryptoAlgorithmId id;
2403 if (!doReadAlgorithmId(id))
2405 uint32_t lengthBytes;
2406 if (!doReadUint32(&lengthBytes))
2408 algorithm = blink::WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8);
2409 type = blink::WebCryptoKeyTypeSecret;
2410 return !algorithm.isNull();
2413 bool doReadRsaHashedKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2415 blink::WebCryptoAlgorithmId id;
2416 if (!doReadAlgorithmId(id))
2420 if (!doReadUint32(&rawType))
2423 switch (static_cast<AssymetricCryptoKeyType>(rawType)) {
2425 type = blink::WebCryptoKeyTypePublic;
2427 case PrivateKeyType:
2428 type = blink::WebCryptoKeyTypePrivate;
2434 uint32_t modulusLengthBits;
2435 if (!doReadUint32(&modulusLengthBits))
2438 uint32_t publicExponentSize;
2439 if (!doReadUint32(&publicExponentSize))
2442 if (m_position + publicExponentSize > m_length)
2445 const uint8_t* publicExponent = m_buffer + m_position;
2446 m_position += publicExponentSize;
2448 blink::WebCryptoAlgorithmId hash;
2449 if (!doReadAlgorithmId(hash))
2451 algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLengthBits, publicExponent, publicExponentSize, hash);
2453 return !algorithm.isNull();
2456 bool doReadAlgorithmId(blink::WebCryptoAlgorithmId& id)
2459 if (!doReadUint32(&rawId))
2462 switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) {
2464 id = blink::WebCryptoAlgorithmIdAesCbc;
2467 id = blink::WebCryptoAlgorithmIdHmac;
2469 case RsaSsaPkcs1v1_5Tag:
2470 id = blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
2473 id = blink::WebCryptoAlgorithmIdSha1;
2476 id = blink::WebCryptoAlgorithmIdSha256;
2479 id = blink::WebCryptoAlgorithmIdSha384;
2482 id = blink::WebCryptoAlgorithmIdSha512;
2485 id = blink::WebCryptoAlgorithmIdAesGcm;
2488 id = blink::WebCryptoAlgorithmIdRsaOaep;
2491 id = blink::WebCryptoAlgorithmIdAesCtr;
2494 id = blink::WebCryptoAlgorithmIdAesKw;
2501 bool doReadKeyUsages(blink::WebCryptoKeyUsageMask& usages, bool& extractable)
2503 // Reminder to update this when adding new key usages.
2504 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
2505 const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | DecryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyUsage | DeriveBitsUsage;
2508 if (!doReadUint32(&rawUsages))
2511 // Make sure it doesn't contain an unrecognized usage value.
2512 if (rawUsages & ~allPossibleUsages)
2517 extractable = rawUsages & ExtractableUsage;
2519 if (rawUsages & EncryptUsage)
2520 usages |= blink::WebCryptoKeyUsageEncrypt;
2521 if (rawUsages & DecryptUsage)
2522 usages |= blink::WebCryptoKeyUsageDecrypt;
2523 if (rawUsages & SignUsage)
2524 usages |= blink::WebCryptoKeyUsageSign;
2525 if (rawUsages & VerifyUsage)
2526 usages |= blink::WebCryptoKeyUsageVerify;
2527 if (rawUsages & DeriveKeyUsage)
2528 usages |= blink::WebCryptoKeyUsageDeriveKey;
2529 if (rawUsages & WrapKeyUsage)
2530 usages |= blink::WebCryptoKeyUsageWrapKey;
2531 if (rawUsages & UnwrapKeyUsage)
2532 usages |= blink::WebCryptoKeyUsageUnwrapKey;
2533 if (rawUsages & DeriveBitsUsage)
2534 usages |= blink::WebCryptoKeyUsageDeriveBits;
2539 RefPtr<ScriptState> m_scriptState;
2540 const uint8_t* m_buffer;
2541 const unsigned m_length;
2542 unsigned m_position;
2544 const WebBlobInfoArray* m_blobInfo;
2545 const BlobDataHandleMap& m_blobDataHandles;
2549 typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray;
2551 class Deserializer FINAL : public CompositeCreator {
2553 Deserializer(Reader& reader, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents)
2555 , m_transferredMessagePorts(messagePorts)
2556 , m_arrayBufferContents(arrayBufferContents)
2557 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
2562 v8::Handle<v8::Value> deserialize()
2564 v8::Isolate* isolate = m_reader.scriptState()->isolate();
2565 if (!m_reader.readVersion(m_version) || m_version > SerializedScriptValue::wireFormatVersion)
2566 return v8::Null(isolate);
2567 m_reader.setVersion(m_version);
2568 v8::EscapableHandleScope scope(isolate);
2569 while (!m_reader.isEof()) {
2570 if (!doDeserialize())
2571 return v8::Null(isolate);
2573 if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
2574 return v8::Null(isolate);
2575 v8::Handle<v8::Value> result = scope.Escape(element(0));
2579 virtual bool newSparseArray(uint32_t) OVERRIDE
2581 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), 0);
2582 openComposite(array);
2586 virtual bool newDenseArray(uint32_t length) OVERRIDE
2588 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), length);
2589 openComposite(array);
2593 virtual bool consumeTopOfStack(v8::Handle<v8::Value>* object) OVERRIDE
2595 if (stackDepth() < 1)
2597 *object = element(stackDepth() - 1);
2602 virtual bool newObject() OVERRIDE
2604 v8::Local<v8::Object> object = v8::Object::New(m_reader.scriptState()->isolate());
2605 if (object.IsEmpty())
2607 openComposite(object);
2611 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>* value) OVERRIDE
2613 v8::Local<v8::Object> object;
2614 if (m_version > 0) {
2615 v8::Local<v8::Value> composite;
2616 if (!closeComposite(&composite))
2618 object = composite.As<v8::Object>();
2620 object = v8::Object::New(m_reader.scriptState()->isolate());
2622 if (object.IsEmpty())
2624 return initializeObject(object, numProperties, value);
2627 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) OVERRIDE
2629 v8::Local<v8::Array> array;
2630 if (m_version > 0) {
2631 v8::Local<v8::Value> composite;
2632 if (!closeComposite(&composite))
2634 array = composite.As<v8::Array>();
2636 array = v8::Array::New(m_reader.scriptState()->isolate());
2638 if (array.IsEmpty())
2640 return initializeObject(array, numProperties, value);
2643 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) OVERRIDE
2645 v8::Local<v8::Array> array;
2646 if (m_version > 0) {
2647 v8::Local<v8::Value> composite;
2648 if (!closeComposite(&composite))
2650 array = composite.As<v8::Array>();
2652 if (array.IsEmpty())
2654 if (!initializeObject(array, numProperties, value))
2656 if (length > stackDepth())
2658 for (unsigned i = 0, stackPos = stackDepth() - length; i < length; i++, stackPos++) {
2659 v8::Local<v8::Value> elem = element(stackPos);
2660 if (!elem->IsUndefined())
2661 array->Set(i, elem);
2667 virtual void pushObjectReference(const v8::Handle<v8::Value>& object) OVERRIDE
2669 m_objectPool.append(object);
2672 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>* object) OVERRIDE
2674 if (!m_transferredMessagePorts)
2676 if (index >= m_transferredMessagePorts->size())
2678 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
2679 *object = toV8(m_transferredMessagePorts->at(index).get(), creationContext, m_reader.scriptState()->isolate());
2683 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>* object) OVERRIDE
2685 if (!m_arrayBufferContents)
2687 if (index >= m_arrayBuffers.size())
2689 v8::Handle<v8::Object> result = m_arrayBuffers.at(index);
2690 if (result.IsEmpty()) {
2691 RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(m_arrayBufferContents->at(index));
2692 buffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
2693 v8::Isolate* isolate = m_reader.scriptState()->isolate();
2694 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
2695 isolate->AdjustAmountOfExternalAllocatedMemory(buffer->byteLength());
2696 result = toV8Object(buffer.get(), creationContext, isolate);
2697 m_arrayBuffers[index] = result;
2703 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>* object) OVERRIDE
2705 if (reference >= m_objectPool.size())
2707 *object = m_objectPool[reference];
2711 virtual uint32_t objectReferenceCount() OVERRIDE
2713 return m_objectPool.size();
2717 bool initializeObject(v8::Handle<v8::Object> object, uint32_t numProperties, v8::Handle<v8::Value>* value)
2719 unsigned length = 2 * numProperties;
2720 if (length > stackDepth())
2722 for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) {
2723 v8::Local<v8::Value> propertyName = element(i);
2724 v8::Local<v8::Value> propertyValue = element(i + 1);
2725 object->Set(propertyName, propertyValue);
2732 bool doDeserialize()
2734 v8::Local<v8::Value> value;
2735 if (!m_reader.read(&value, *this))
2737 if (!value.IsEmpty())
2742 void push(v8::Local<v8::Value> value) { m_stack.append(value); }
2744 void pop(unsigned length)
2746 ASSERT(length <= m_stack.size());
2747 m_stack.shrink(m_stack.size() - length);
2750 unsigned stackDepth() const { return m_stack.size(); }
2752 v8::Local<v8::Value> element(unsigned index)
2754 ASSERT_WITH_SECURITY_IMPLICATION(index < m_stack.size());
2755 return m_stack[index];
2758 void openComposite(const v8::Local<v8::Value>& object)
2760 uint32_t newObjectReference = m_objectPool.size();
2761 m_openCompositeReferenceStack.append(newObjectReference);
2762 m_objectPool.append(object);
2765 bool closeComposite(v8::Handle<v8::Value>* object)
2767 if (!m_openCompositeReferenceStack.size())
2769 uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
2770 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1);
2771 if (objectReference >= m_objectPool.size())
2773 *object = m_objectPool[objectReference];
2778 Vector<v8::Local<v8::Value> > m_stack;
2779 Vector<v8::Handle<v8::Value> > m_objectPool;
2780 Vector<uint32_t> m_openCompositeReferenceStack;
2781 MessagePortArray* m_transferredMessagePorts;
2782 ArrayBufferContentsArray* m_arrayBufferContents;
2783 Vector<v8::Handle<v8::Object> > m_arrayBuffers;
2789 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
2791 return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, 0, exceptionState, isolate));
2794 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createAndSwallowExceptions(v8::Handle<v8::Value> value, v8::Isolate* isolate)
2796 TrackExceptionState exceptionState;
2797 return adoptRef(new SerializedScriptValue(value, 0, 0, 0, exceptionState, isolate));
2800 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const ScriptValue& value, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolate* isolate)
2802 ASSERT(isolate->InContext());
2803 return adoptRef(new SerializedScriptValue(value.v8Value(), 0, 0, blobInfo, exceptionState, isolate));
2806 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(const String& data)
2808 return adoptRef(new SerializedScriptValue(data));
2811 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWireBytes(const Vector<uint8_t>& data)
2813 // Decode wire data from big endian to host byte order.
2814 ASSERT(!(data.size() % sizeof(UChar)));
2815 size_t length = data.size() / sizeof(UChar);
2816 StringBuffer<UChar> buffer(length);
2817 const UChar* src = reinterpret_cast<const UChar*>(data.data());
2818 UChar* dst = buffer.characters();
2819 for (size_t i = 0; i < length; i++)
2820 dst[i] = ntohs(src[i]);
2822 return createFromWire(String::adopt(buffer));
2825 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& data)
2827 return create(data, v8::Isolate::GetCurrent());
2830 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& data, v8::Isolate* isolate)
2833 writer.writeWebCoreString(data);
2834 String wireData = writer.takeWireString();
2835 return adoptRef(new SerializedScriptValue(wireData));
2838 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
2840 return adoptRef(new SerializedScriptValue());
2843 PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
2847 String wireData = writer.takeWireString();
2848 return adoptRef(new SerializedScriptValue(wireData));
2851 // Convert serialized string to big endian wire data.
2852 void SerializedScriptValue::toWireBytes(Vector<char>& result) const
2854 ASSERT(result.isEmpty());
2855 size_t length = m_data.length();
2856 result.resize(length * sizeof(UChar));
2857 UChar* dst = reinterpret_cast<UChar*>(result.data());
2859 if (m_data.is8Bit()) {
2860 const LChar* src = m_data.characters8();
2861 for (size_t i = 0; i < length; i++)
2862 dst[i] = htons(static_cast<UChar>(src[i]));
2864 const UChar* src = m_data.characters16();
2865 for (size_t i = 0; i < length; i++)
2866 dst[i] = htons(src[i]);
2870 SerializedScriptValue::SerializedScriptValue()
2871 : m_externallyAllocatedMemory(0)
2875 static void neuterArrayBufferInAllWorlds(ArrayBuffer* object)
2877 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2878 if (isMainThread()) {
2879 Vector<RefPtr<DOMWrapperWorld> > worlds;
2880 DOMWrapperWorld::allWorldsInMainThread(worlds);
2881 for (size_t i = 0; i < worlds.size(); i++) {
2882 v8::Handle<v8::Object> wrapper = worlds[i]->domDataStore().get<V8ArrayBuffer>(object, isolate);
2883 if (!wrapper.IsEmpty()) {
2884 ASSERT(wrapper->IsArrayBuffer());
2885 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter();
2889 v8::Handle<v8::Object> wrapper = DOMWrapperWorld::current(isolate).domDataStore().get<V8ArrayBuffer>(object, isolate);
2890 if (!wrapper.IsEmpty()) {
2891 ASSERT(wrapper->IsArrayBuffer());
2892 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter();
2897 PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
2899 ASSERT(arrayBuffers.size());
2901 for (size_t i = 0; i < arrayBuffers.size(); i++) {
2902 if (arrayBuffers[i]->isNeutered()) {
2903 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is already neutered.");
2908 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
2910 HashSet<ArrayBuffer*> visited;
2911 for (size_t i = 0; i < arrayBuffers.size(); i++) {
2912 if (visited.contains(arrayBuffers[i].get()))
2914 visited.add(arrayBuffers[i].get());
2916 bool result = arrayBuffers[i]->transfer(contents->at(i));
2918 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " could not be transferred.");
2922 neuterArrayBufferInAllWorlds(arrayBuffers[i].get());
2924 return contents.release();
2927 SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolate* isolate)
2928 : m_externallyAllocatedMemory(0)
2931 Serializer::Status status;
2932 String errorMessage;
2934 v8::TryCatch tryCatch;
2935 Serializer serializer(writer, messagePorts, arrayBuffers, blobInfo, m_blobDataHandles, tryCatch, ScriptState::current(isolate));
2936 status = serializer.serialize(value);
2937 if (status == Serializer::JSException) {
2938 // If there was a JS exception thrown, re-throw it.
2939 exceptionState.rethrowV8Exception(tryCatch.Exception());
2942 errorMessage = serializer.errorMessage();
2945 case Serializer::InputError:
2946 case Serializer::DataCloneError:
2947 exceptionState.throwDOMException(DataCloneError, errorMessage);
2949 case Serializer::Success:
2950 m_data = writer.takeWireString();
2951 ASSERT(m_data.impl()->hasOneRef());
2952 if (arrayBuffers && arrayBuffers->size())
2953 m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, exceptionState, isolate);
2955 case Serializer::JSException:
2956 ASSERT_NOT_REACHED();
2959 ASSERT_NOT_REACHED();
2962 SerializedScriptValue::SerializedScriptValue(const String& wireData)
2963 : m_externallyAllocatedMemory(0)
2965 m_data = wireData.isolatedCopy();
2968 v8::Handle<v8::Value> SerializedScriptValue::deserialize(MessagePortArray* messagePorts)
2970 return deserialize(v8::Isolate::GetCurrent(), messagePorts, 0);
2973 v8::Handle<v8::Value> SerializedScriptValue::deserialize(v8::Isolate* isolate, MessagePortArray* messagePorts, const WebBlobInfoArray* blobInfo)
2976 return v8::Null(isolate);
2977 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
2978 m_data.ensure16Bit();
2979 // FIXME: SerializedScriptValue shouldn't use String for its underlying
2980 // storage. Instead, it should use SharedBuffer or Vector<uint8_t>. The
2981 // information stored in m_data isn't even encoded in UTF-16. Instead,
2982 // unicode characters are encoded as UTF-8 with two code units per UChar.
2983 Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters16()), 2 * m_data.length(), blobInfo, m_blobDataHandles, ScriptState::current(isolate));
2984 Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.get());
2986 // deserialize() can run arbitrary script (e.g., setters), which could result in |this| being destroyed.
2987 // Holding a RefPtr ensures we are alive (along with our internal data) throughout the operation.
2988 RefPtr<SerializedScriptValue> protect(this);
2989 return deserializer.deserialize();
2992 bool SerializedScriptValue::extractTransferables(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
2994 if (isUndefinedOrNull(value)) {
2996 arrayBuffers.resize(0);
3000 uint32_t length = 0;
3001 if (value->IsArray()) {
3002 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value);
3003 length = array->Length();
3004 } else if (toV8Sequence(value, length, isolate).IsEmpty()) {
3005 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex + 1));
3009 v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value);
3011 // Validate the passed array of transferrables.
3012 for (unsigned i = 0; i < length; ++i) {
3013 v8::Local<v8::Value> transferrable = transferrables->Get(i);
3014 // Validation of non-null objects, per HTML5 spec 10.3.3.
3015 if (isUndefinedOrNull(transferrable)) {
3016 exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " is an untransferable " + (transferrable->IsUndefined() ? "'undefined'" : "'null'") + " value.");
3019 // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
3020 if (V8MessagePort::hasInstance(transferrable, isolate)) {
3021 RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable));
3022 // Check for duplicate MessagePorts.
3023 if (ports.contains(port)) {
3024 exceptionState.throwDOMException(DataCloneError, "Message port at index " + String::number(i) + " is a duplicate of an earlier port.");
3027 ports.append(port.release());
3028 } else if (V8ArrayBuffer::hasInstance(transferrable, isolate)) {
3029 RefPtr<ArrayBuffer> arrayBuffer = V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable));
3030 if (arrayBuffers.contains(arrayBuffer)) {
3031 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is a duplicate of an earlier ArrayBuffer.");
3034 arrayBuffers.append(arrayBuffer.release());
3036 exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " does not have a transferable type.");
3043 void SerializedScriptValue::registerMemoryAllocatedWithCurrentScriptContext()
3045 if (m_externallyAllocatedMemory)
3047 m_externallyAllocatedMemory = static_cast<intptr_t>(m_data.length());
3048 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(m_externallyAllocatedMemory);
3051 SerializedScriptValue::~SerializedScriptValue()
3053 // If the allocated memory was not registered before, then this class is likely
3054 // used in a context other then Worker's onmessage environment and the presence of
3055 // current v8 context is not guaranteed. Avoid calling v8 then.
3056 if (m_externallyAllocatedMemory) {
3057 ASSERT(v8::Isolate::GetCurrent());
3058 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_externallyAllocatedMemory);
3062 } // namespace WebCore