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/core/v8/SerializedScriptValue.h"
34 #include "bindings/core/v8/ExceptionState.h"
35 #include "bindings/core/v8/V8Binding.h"
36 #include "bindings/core/v8/V8Blob.h"
37 #include "bindings/core/v8/V8File.h"
38 #include "bindings/core/v8/V8FileList.h"
39 #include "bindings/core/v8/V8ImageData.h"
40 #include "bindings/core/v8/V8MessagePort.h"
41 #include "bindings/core/v8/WorkerScriptController.h"
42 #include "bindings/core/v8/custom/V8ArrayBufferCustom.h"
43 #include "bindings/core/v8/custom/V8ArrayBufferViewCustom.h"
44 #include "bindings/core/v8/custom/V8DataViewCustom.h"
45 #include "bindings/core/v8/custom/V8Float32ArrayCustom.h"
46 #include "bindings/core/v8/custom/V8Float64ArrayCustom.h"
47 #include "bindings/core/v8/custom/V8Int16ArrayCustom.h"
48 #include "bindings/core/v8/custom/V8Int32ArrayCustom.h"
49 #include "bindings/core/v8/custom/V8Int8ArrayCustom.h"
50 #include "bindings/core/v8/custom/V8Uint16ArrayCustom.h"
51 #include "bindings/core/v8/custom/V8Uint32ArrayCustom.h"
52 #include "bindings/core/v8/custom/V8Uint8ArrayCustom.h"
53 #include "bindings/core/v8/custom/V8Uint8ClampedArrayCustom.h"
54 #include "bindings/modules/v8/V8CryptoKey.h"
55 #include "bindings/modules/v8/V8DOMFileSystem.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 1 byte 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 doWriteUint32(static_cast<uint8_t>(0));
688 doWriteUint32(static_cast<uint8_t>((file.userVisibility() == File::IsUserVisible) ? 1 : 0));
691 void doWriteArrayBuffer(const ArrayBuffer& arrayBuffer)
693 uint32_t byteLength = arrayBuffer.byteLength();
694 doWriteUint32(byteLength);
695 append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
698 void doWriteString(const char* data, int length)
700 doWriteUint32(static_cast<uint32_t>(length));
701 append(reinterpret_cast<const uint8_t*>(data), length);
704 void doWriteWebCoreString(const String& string)
706 StringUTF8Adaptor stringUTF8(string);
707 doWriteString(stringUTF8.data(), stringUTF8.length());
710 void doWriteHmacKey(const blink::WebCryptoKey& key)
712 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeHmac);
714 append(static_cast<uint8_t>(HmacKeyTag));
715 ASSERT(!(key.algorithm().hmacParams()->lengthBits() % 8));
716 doWriteUint32(key.algorithm().hmacParams()->lengthBits() / 8);
717 doWriteAlgorithmId(key.algorithm().hmacParams()->hash().id());
720 void doWriteAesKey(const blink::WebCryptoKey& key)
722 ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeAes);
724 append(static_cast<uint8_t>(AesKeyTag));
725 doWriteAlgorithmId(key.algorithm().id());
726 // Converting the key length from bits to bytes is lossless and makes
728 ASSERT(!(key.algorithm().aesParams()->lengthBits() % 8));
729 doWriteUint32(key.algorithm().aesParams()->lengthBits() / 8);
732 void doWriteRsaHashedKey(const blink::WebCryptoKey& key)
734 ASSERT(key.algorithm().rsaHashedParams());
735 append(static_cast<uint8_t>(RsaHashedKeyTag));
737 doWriteAlgorithmId(key.algorithm().id());
739 switch (key.type()) {
740 case blink::WebCryptoKeyTypePublic:
741 doWriteUint32(PublicKeyType);
743 case blink::WebCryptoKeyTypePrivate:
744 doWriteUint32(PrivateKeyType);
746 case blink::WebCryptoKeyTypeSecret:
747 ASSERT_NOT_REACHED();
750 const blink::WebCryptoRsaHashedKeyAlgorithmParams* params = key.algorithm().rsaHashedParams();
751 doWriteUint32(params->modulusLengthBits());
752 doWriteUint32(params->publicExponent().size());
753 append(params->publicExponent().data(), params->publicExponent().size());
754 doWriteAlgorithmId(key.algorithm().rsaHashedParams()->hash().id());
757 void doWriteAlgorithmId(blink::WebCryptoAlgorithmId id)
760 case blink::WebCryptoAlgorithmIdAesCbc:
761 return doWriteUint32(AesCbcTag);
762 case blink::WebCryptoAlgorithmIdHmac:
763 return doWriteUint32(HmacTag);
764 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
765 return doWriteUint32(RsaSsaPkcs1v1_5Tag);
766 case blink::WebCryptoAlgorithmIdSha1:
767 return doWriteUint32(Sha1Tag);
768 case blink::WebCryptoAlgorithmIdSha256:
769 return doWriteUint32(Sha256Tag);
770 case blink::WebCryptoAlgorithmIdSha384:
771 return doWriteUint32(Sha384Tag);
772 case blink::WebCryptoAlgorithmIdSha512:
773 return doWriteUint32(Sha512Tag);
774 case blink::WebCryptoAlgorithmIdAesGcm:
775 return doWriteUint32(AesGcmTag);
776 case blink::WebCryptoAlgorithmIdRsaOaep:
777 return doWriteUint32(RsaOaepTag);
778 case blink::WebCryptoAlgorithmIdAesCtr:
779 return doWriteUint32(AesCtrTag);
780 case blink::WebCryptoAlgorithmIdAesKw:
781 return doWriteUint32(AesKwTag);
783 ASSERT_NOT_REACHED();
786 void doWriteKeyUsages(const blink::WebCryptoKeyUsageMask usages, bool extractable)
788 // Reminder to update this when adding new key usages.
789 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
794 value |= ExtractableUsage;
796 if (usages & blink::WebCryptoKeyUsageEncrypt)
797 value |= EncryptUsage;
798 if (usages & blink::WebCryptoKeyUsageDecrypt)
799 value |= DecryptUsage;
800 if (usages & blink::WebCryptoKeyUsageSign)
802 if (usages & blink::WebCryptoKeyUsageVerify)
803 value |= VerifyUsage;
804 if (usages & blink::WebCryptoKeyUsageDeriveKey)
805 value |= DeriveKeyUsage;
806 if (usages & blink::WebCryptoKeyUsageWrapKey)
807 value |= WrapKeyUsage;
808 if (usages & blink::WebCryptoKeyUsageUnwrapKey)
809 value |= UnwrapKeyUsage;
810 if (usages & blink::WebCryptoKeyUsageDeriveBits)
811 value |= DeriveBitsUsage;
813 doWriteUint32(value);
816 int bytesNeededToWireEncode(uint32_t value)
820 value >>= varIntShift;
830 void doWriteUintHelper(T value)
833 uint8_t b = (value & varIntMask);
834 value >>= varIntShift;
839 append(b | (1 << varIntShift));
843 void doWriteUint32(uint32_t value)
845 doWriteUintHelper(value);
848 void doWriteUint64(uint64_t value)
850 doWriteUintHelper(value);
853 void doWriteNumber(double number)
855 append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
858 void append(SerializationTag tag)
860 append(static_cast<uint8_t>(tag));
863 void append(uint8_t b)
866 *byteAt(m_position++) = b;
869 void append(const uint8_t* data, int length)
872 memcpy(byteAt(m_position), data, length);
873 m_position += length;
876 void ensureSpace(unsigned extra)
878 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
879 m_buffer.resize((m_position + extra + 1) / sizeof(BufferValueType)); // "+ 1" to round up.
884 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
885 // If the writer is at odd position in the buffer, then one of
886 // the bytes in the last UChar is not initialized.
888 *byteAt(m_position) = static_cast<uint8_t>(PaddingTag);
891 uint8_t* byteAt(int position)
893 return reinterpret_cast<uint8_t*>(m_buffer.data()) + position;
896 int v8StringWriteOptions()
898 return v8::String::NO_NULL_TERMINATION;
901 Vector<BufferValueType> m_buffer;
905 static v8::Handle<v8::Object> toV8Object(MessagePort* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
908 return v8::Handle<v8::Object>();
909 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
910 ASSERT(wrapper->IsObject());
911 return wrapper.As<v8::Object>();
914 static v8::Handle<v8::ArrayBuffer> toV8Object(ArrayBuffer* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
917 return v8::Handle<v8::ArrayBuffer>();
918 v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
919 ASSERT(wrapper->IsArrayBuffer());
920 return wrapper.As<v8::ArrayBuffer>();
933 Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, v8::TryCatch& tryCatch, ScriptState* scriptState)
934 : m_scriptState(scriptState)
936 , m_tryCatch(tryCatch)
939 , m_nextObjectReference(0)
940 , m_blobInfo(blobInfo)
941 , m_blobDataHandles(blobDataHandles)
943 ASSERT(!tryCatch.HasCaught());
944 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
946 for (size_t i = 0; i < messagePorts->size(); i++)
947 m_transferredMessagePorts.set(toV8Object(messagePorts->at(i).get(), creationContext, isolate()), i);
950 for (size_t i = 0; i < arrayBuffers->size(); i++) {
951 v8::Handle<v8::Object> v8ArrayBuffer = toV8Object(arrayBuffers->at(i).get(), creationContext, isolate());
952 // Coalesce multiple occurences of the same buffer to the first index.
953 if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
954 m_transferredArrayBuffers.set(v8ArrayBuffer, i);
959 v8::Isolate* isolate() { return m_scriptState->isolate(); }
961 Status serialize(v8::Handle<v8::Value> value)
963 v8::HandleScope scope(isolate());
964 m_writer.writeVersion();
965 StateBase* state = doSerialize(value, 0);
967 state = state->advance(*this);
971 String errorMessage() { return m_errorMessage; }
973 // Functions used by serialization states.
974 StateBase* doSerialize(v8::Handle<v8::Value>, StateBase* next);
976 StateBase* doSerializeArrayBuffer(v8::Handle<v8::Value> arrayBuffer, StateBase* next)
978 return doSerialize(arrayBuffer, next);
981 StateBase* checkException(StateBase* state)
983 return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0;
986 StateBase* writeObject(uint32_t numProperties, StateBase* state)
988 m_writer.writeObject(numProperties);
992 StateBase* writeSparseArray(uint32_t numProperties, uint32_t length, StateBase* state)
994 m_writer.writeSparseArray(numProperties, length);
998 StateBase* writeDenseArray(uint32_t numProperties, uint32_t length, StateBase* state)
1000 m_writer.writeDenseArray(numProperties, length);
1007 WTF_MAKE_NONCOPYABLE(StateBase);
1009 virtual ~StateBase() { }
1011 // Link to the next state to form a stack.
1012 StateBase* nextState() { return m_next; }
1014 // Composite object we're processing in this state.
1015 v8::Handle<v8::Value> composite() { return m_composite; }
1017 // Serializes (a part of) the current composite and returns
1018 // the next state to process or null when this is the final
1020 virtual StateBase* advance(Serializer&) = 0;
1023 StateBase(v8::Handle<v8::Value> composite, StateBase* next)
1024 : m_composite(composite)
1030 v8::Handle<v8::Value> m_composite;
1034 // Dummy state that is used to signal serialization errors.
1035 class ErrorState FINAL : public StateBase {
1038 : StateBase(v8Undefined(), 0)
1042 virtual StateBase* advance(Serializer&) OVERRIDE
1049 template <typename T>
1050 class State : public StateBase {
1052 v8::Handle<T> composite() { return v8::Handle<T>::Cast(StateBase::composite()); }
1055 State(v8::Handle<T> composite, StateBase* next)
1056 : StateBase(composite, next)
1061 class AbstractObjectState : public State<v8::Object> {
1063 AbstractObjectState(v8::Handle<v8::Object> object, StateBase* next)
1064 : State<v8::Object>(object, next)
1066 , m_numSerializedProperties(0)
1072 virtual StateBase* objectDone(unsigned numProperties, Serializer&) = 0;
1074 StateBase* serializeProperties(bool ignoreIndexed, Serializer& serializer)
1076 while (m_index < m_propertyNames->Length()) {
1078 v8::Local<v8::Value> propertyName = m_propertyNames->Get(m_index);
1079 if (StateBase* newState = serializer.checkException(this))
1081 if (propertyName.IsEmpty())
1082 return serializer.handleError(InputError, "Empty property names cannot be cloned.", this);
1083 bool hasStringProperty = propertyName->IsString() && composite()->HasRealNamedProperty(propertyName.As<v8::String>());
1084 if (StateBase* newState = serializer.checkException(this))
1086 bool hasIndexedProperty = !hasStringProperty && propertyName->IsUint32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value());
1087 if (StateBase* newState = serializer.checkException(this))
1089 if (hasStringProperty || (hasIndexedProperty && !ignoreIndexed)) {
1090 m_propertyName = propertyName;
1096 ASSERT(!m_propertyName.IsEmpty());
1099 if (StateBase* newState = serializer.doSerialize(m_propertyName, this))
1102 v8::Local<v8::Value> value = composite()->Get(m_propertyName);
1103 if (StateBase* newState = serializer.checkException(this))
1106 m_propertyName.Clear();
1108 ++m_numSerializedProperties;
1109 // If we return early here, it's either because we have pushed a new state onto the
1110 // serialization state stack or because we have encountered an error (and in both cases
1111 // we are unwinding the native stack).
1112 if (StateBase* newState = serializer.doSerialize(value, this))
1115 return objectDone(m_numSerializedProperties, serializer);
1118 v8::Local<v8::Array> m_propertyNames;
1121 v8::Local<v8::Value> m_propertyName;
1123 unsigned m_numSerializedProperties;
1127 class ObjectState FINAL : public AbstractObjectState {
1129 ObjectState(v8::Handle<v8::Object> object, StateBase* next)
1130 : AbstractObjectState(object, next)
1134 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1136 if (m_propertyNames.IsEmpty()) {
1137 m_propertyNames = composite()->GetPropertyNames();
1138 if (StateBase* newState = serializer.checkException(this))
1140 if (m_propertyNames.IsEmpty())
1141 return serializer.handleError(InputError, "Empty property names cannot be cloned.", nextState());
1143 return serializeProperties(false, serializer);
1147 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1149 return serializer.writeObject(numProperties, this);
1153 class DenseArrayState FINAL : public AbstractObjectState {
1155 DenseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
1156 : AbstractObjectState(array, next)
1158 , m_arrayLength(array->Length())
1160 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
1163 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1165 while (m_arrayIndex < m_arrayLength) {
1166 v8::Handle<v8::Value> value = composite().As<v8::Array>()->Get(m_arrayIndex);
1168 if (StateBase* newState = serializer.checkException(this))
1170 if (StateBase* newState = serializer.doSerialize(value, this))
1173 return serializeProperties(true, serializer);
1177 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1179 return serializer.writeDenseArray(numProperties, m_arrayLength, this);
1183 uint32_t m_arrayIndex;
1184 uint32_t m_arrayLength;
1187 class SparseArrayState FINAL : public AbstractObjectState {
1189 SparseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
1190 : AbstractObjectState(array, next)
1192 m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
1195 virtual StateBase* advance(Serializer& serializer) OVERRIDE
1197 return serializeProperties(false, serializer);
1201 virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) OVERRIDE
1203 return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this);
1207 StateBase* push(StateBase* state)
1211 return checkComposite(state) ? state : handleError(InputError, "Value being cloned is either cyclic or too deeply nested.", state);
1214 StateBase* pop(StateBase* state)
1218 StateBase* next = state->nextState();
1223 StateBase* handleError(Status errorStatus, const String& message, StateBase* state)
1225 ASSERT(errorStatus != Success);
1226 m_status = errorStatus;
1227 m_errorMessage = message;
1229 StateBase* tmp = state->nextState();
1233 return new ErrorState;
1236 bool checkComposite(StateBase* top)
1239 if (m_depth > maxDepth)
1241 if (!shouldCheckForCycles(m_depth))
1243 v8::Handle<v8::Value> composite = top->composite();
1244 for (StateBase* state = top->nextState(); state; state = state->nextState()) {
1245 if (state->composite() == composite)
1251 void writeString(v8::Handle<v8::Value> value)
1253 v8::Handle<v8::String> string = value.As<v8::String>();
1254 if (!string->Length() || string->IsOneByte())
1255 m_writer.writeOneByteString(string);
1257 m_writer.writeUCharString(string);
1260 void writeStringObject(v8::Handle<v8::Value> value)
1262 v8::Handle<v8::StringObject> stringObject = value.As<v8::StringObject>();
1263 v8::String::Utf8Value stringValue(stringObject->ValueOf());
1264 m_writer.writeStringObject(*stringValue, stringValue.length());
1267 void writeNumberObject(v8::Handle<v8::Value> value)
1269 v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
1270 m_writer.writeNumberObject(numberObject->ValueOf());
1273 void writeBooleanObject(v8::Handle<v8::Value> value)
1275 v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
1276 m_writer.writeBooleanObject(booleanObject->ValueOf());
1279 StateBase* writeBlob(v8::Handle<v8::Value> value, StateBase* next)
1281 Blob* blob = V8Blob::toImpl(value.As<v8::Object>());
1284 if (blob->hasBeenClosed())
1285 return handleError(DataCloneError, "A Blob object has been closed, and could therefore not be cloned.", next);
1287 m_blobDataHandles.set(blob->uuid(), blob->blobDataHandle());
1288 if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex))
1289 m_writer.writeBlobIndex(blobIndex);
1291 m_writer.writeBlob(blob->uuid(), blob->type(), blob->size());
1295 StateBase* writeDOMFileSystem(v8::Handle<v8::Value> value, StateBase* next)
1297 DOMFileSystem* fs = V8DOMFileSystem::toImpl(value.As<v8::Object>());
1300 if (!fs->clonable())
1301 return handleError(DataCloneError, "A FileSystem object could not be cloned.", next);
1302 m_writer.writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().string());
1306 StateBase* writeFile(v8::Handle<v8::Value> value, StateBase* next)
1308 File* file = V8File::toImpl(value.As<v8::Object>());
1311 if (file->hasBeenClosed())
1312 return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
1314 m_blobDataHandles.set(file->uuid(), file->blobDataHandle());
1315 if (appendFileInfo(file, &blobIndex)) {
1316 ASSERT(blobIndex >= 0);
1317 m_writer.writeFileIndex(blobIndex);
1319 m_writer.writeFile(*file);
1324 StateBase* writeFileList(v8::Handle<v8::Value> value, StateBase* next)
1326 FileList* fileList = V8FileList::toImpl(value.As<v8::Object>());
1329 unsigned length = fileList->length();
1330 Vector<int> blobIndices;
1331 for (unsigned i = 0; i < length; ++i) {
1333 const File* file = fileList->item(i);
1334 if (file->hasBeenClosed())
1335 return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
1336 m_blobDataHandles.set(file->uuid(), file->blobDataHandle());
1337 if (appendFileInfo(file, &blobIndex)) {
1338 ASSERT(!i || blobIndex > 0);
1339 ASSERT(blobIndex >= 0);
1340 blobIndices.append(blobIndex);
1343 if (!blobIndices.isEmpty())
1344 m_writer.writeFileListIndex(blobIndices);
1346 m_writer.writeFileList(*fileList);
1350 bool writeCryptoKey(v8::Handle<v8::Value> value)
1352 CryptoKey* key = V8CryptoKey::toImpl(value.As<v8::Object>());
1355 return m_writer.writeCryptoKey(key->key());
1358 void writeImageData(v8::Handle<v8::Value> value)
1360 ImageData* imageData = V8ImageData::toImpl(value.As<v8::Object>());
1363 Uint8ClampedArray* pixelArray = imageData->data();
1364 m_writer.writeImageData(imageData->width(), imageData->height(), pixelArray->data(), pixelArray->length());
1367 void writeRegExp(v8::Handle<v8::Value> value)
1369 v8::Handle<v8::RegExp> regExp = value.As<v8::RegExp>();
1370 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
1373 StateBase* writeAndGreyArrayBufferView(v8::Handle<v8::Object> object, StateBase* next)
1375 ASSERT(!object.IsEmpty());
1376 ArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object);
1377 if (!arrayBufferView)
1379 if (!arrayBufferView->buffer())
1380 return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
1381 v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer(), m_scriptState->context()->Global(), isolate());
1382 if (underlyingBuffer.IsEmpty())
1383 return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
1384 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
1387 m_writer.writeArrayBufferView(*arrayBufferView);
1388 // This should be safe: we serialize something that we know to be a wrapper (see
1389 // the toV8 call above), so the call to doSerializeArrayBuffer should neither
1390 // cause the system stack to overflow nor should it have potential to reach
1391 // this ArrayBufferView again.
1393 // We do need to grey the underlying buffer before we grey its view, however;
1394 // ArrayBuffers may be shared, so they need to be given reference IDs, and an
1395 // ArrayBufferView cannot be constructed without a corresponding ArrayBuffer
1396 // (or without an additional tag that would allow us to do two-stage construction
1397 // like we do for Objects and Arrays).
1402 StateBase* writeArrayBuffer(v8::Handle<v8::Value> value, StateBase* next)
1404 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(value.As<v8::Object>());
1407 if (arrayBuffer->isNeutered())
1408 return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
1409 ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>()));
1410 m_writer.writeArrayBuffer(*arrayBuffer);
1414 StateBase* writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t index, StateBase* next)
1416 ArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(value.As<v8::Object>());
1419 if (arrayBuffer->isNeutered())
1420 return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
1421 m_writer.writeTransferredArrayBuffer(index);
1425 static bool shouldSerializeDensely(uint32_t length, uint32_t propertyCount)
1427 // Let K be the cost of serializing all property values that are there
1428 // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32_t key)
1429 // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte for all properties that are not there)
1430 // so densely is better than sparsly whenever 6*propertyCount > length
1431 return 6 * propertyCount >= length;
1434 StateBase* startArrayState(v8::Handle<v8::Array> array, StateBase* next)
1436 v8::Handle<v8::Array> propertyNames = array->GetPropertyNames();
1437 if (StateBase* newState = checkException(next))
1439 uint32_t length = array->Length();
1441 if (shouldSerializeDensely(length, propertyNames->Length())) {
1442 m_writer.writeGenerateFreshDenseArray(length);
1443 return push(new DenseArrayState(array, propertyNames, next, isolate()));
1446 m_writer.writeGenerateFreshSparseArray(length);
1447 return push(new SparseArrayState(array, propertyNames, next, isolate()));
1450 StateBase* startObjectState(v8::Handle<v8::Object> object, StateBase* next)
1452 m_writer.writeGenerateFreshObject();
1453 // FIXME: check not a wrapper
1454 return push(new ObjectState(object, next));
1457 // Marks object as having been visited by the serializer and assigns it a unique object reference ID.
1458 // An object may only be greyed once.
1459 void greyObject(const v8::Handle<v8::Object>& object)
1461 ASSERT(!m_objectPool.contains(object));
1462 uint32_t objectReference = m_nextObjectReference++;
1463 m_objectPool.set(object, objectReference);
1466 bool appendBlobInfo(const String& uuid, const String& type, unsigned long long size, int* index)
1470 *index = m_blobInfo->size();
1471 m_blobInfo->append(WebBlobInfo(uuid, type, size));
1475 bool appendFileInfo(const File* file, int* index)
1480 long long size = -1;
1481 double lastModified = invalidFileTime();
1482 file->captureSnapshot(size, lastModified);
1483 *index = m_blobInfo->size();
1484 m_blobInfo->append(WebBlobInfo(file->uuid(), file->path(), file->name(), file->type(), lastModified, size));
1488 RefPtr<ScriptState> m_scriptState;
1490 v8::TryCatch& m_tryCatch;
1493 String m_errorMessage;
1494 typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool;
1495 ObjectPool m_objectPool;
1496 ObjectPool m_transferredMessagePorts;
1497 ObjectPool m_transferredArrayBuffers;
1498 uint32_t m_nextObjectReference;
1499 WebBlobInfoArray* m_blobInfo;
1500 BlobDataHandleMap& m_blobDataHandles;
1503 // Returns true if the provided object is to be considered a 'host object', as used in the
1504 // HTML5 structured clone algorithm.
1505 static bool isHostObject(v8::Handle<v8::Object> object)
1507 // If the object has any internal fields, then we won't be able to serialize or deserialize
1508 // them; conveniently, this is also a quick way to detect DOM wrapper objects, because
1509 // the mechanism for these relies on data stored in these fields. We should
1510 // catch external array data as a special case.
1511 return object->InternalFieldCount() || object->HasIndexedPropertiesInExternalArrayData();
1514 Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, StateBase* next)
1516 m_writer.writeReferenceCount(m_nextObjectReference);
1517 uint32_t objectReference;
1518 uint32_t arrayBufferIndex;
1519 if ((value->IsObject() || value->IsDate() || value->IsRegExp())
1520 && m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
1521 // Note that IsObject() also detects wrappers (eg, it will catch the things
1522 // that we grey and write below).
1523 ASSERT(!value->IsString());
1524 m_writer.writeObjectReference(objectReference);
1525 } else if (value.IsEmpty()) {
1526 return handleError(InputError, "The empty property name cannot be cloned.", next);
1527 } else if (value->IsUndefined()) {
1528 m_writer.writeUndefined();
1529 } else if (value->IsNull()) {
1530 m_writer.writeNull();
1531 } else if (value->IsTrue()) {
1532 m_writer.writeTrue();
1533 } else if (value->IsFalse()) {
1534 m_writer.writeFalse();
1535 } else if (value->IsInt32()) {
1536 m_writer.writeInt32(value->Int32Value());
1537 } else if (value->IsUint32()) {
1538 m_writer.writeUint32(value->Uint32Value());
1539 } else if (value->IsNumber()) {
1540 m_writer.writeNumber(value.As<v8::Number>()->Value());
1541 } else if (V8ArrayBufferView::hasInstance(value, isolate())) {
1542 return writeAndGreyArrayBufferView(value.As<v8::Object>(), next);
1543 } else if (value->IsString()) {
1545 } else if (V8MessagePort::hasInstance(value, isolate())) {
1546 uint32_t messagePortIndex;
1547 if (m_transferredMessagePorts.tryGet(value.As<v8::Object>(), &messagePortIndex)) {
1548 m_writer.writeTransferredMessagePort(messagePortIndex);
1550 return handleError(DataCloneError, "A MessagePort could not be cloned.", next);
1552 } else if (V8ArrayBuffer::hasInstance(value, isolate()) && m_transferredArrayBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex)) {
1553 return writeTransferredArrayBuffer(value, arrayBufferIndex, next);
1555 v8::Handle<v8::Object> jsObject = value.As<v8::Object>();
1556 if (jsObject.IsEmpty())
1557 return handleError(DataCloneError, "An object could not be cloned.", next);
1558 greyObject(jsObject);
1559 if (value->IsDate()) {
1560 m_writer.writeDate(value->NumberValue());
1561 } else if (value->IsStringObject()) {
1562 writeStringObject(value);
1563 } else if (value->IsNumberObject()) {
1564 writeNumberObject(value);
1565 } else if (value->IsBooleanObject()) {
1566 writeBooleanObject(value);
1567 } else if (value->IsArray()) {
1568 return startArrayState(value.As<v8::Array>(), next);
1569 } else if (V8File::hasInstance(value, isolate())) {
1570 return writeFile(value, next);
1571 } else if (V8Blob::hasInstance(value, isolate())) {
1572 return writeBlob(value, next);
1573 } else if (V8DOMFileSystem::hasInstance(value, isolate())) {
1574 return writeDOMFileSystem(value, next);
1575 } else if (V8FileList::hasInstance(value, isolate())) {
1576 return writeFileList(value, next);
1577 } else if (V8CryptoKey::hasInstance(value, isolate())) {
1578 if (!writeCryptoKey(value))
1579 return handleError(DataCloneError, "Couldn't serialize key data", next);
1580 } else if (V8ImageData::hasInstance(value, isolate())) {
1581 writeImageData(value);
1582 } else if (value->IsRegExp()) {
1584 } else if (V8ArrayBuffer::hasInstance(value, isolate())) {
1585 return writeArrayBuffer(value, next);
1586 } else if (value->IsObject()) {
1587 if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
1588 return handleError(DataCloneError, "An object could not be cloned.", next);
1589 return startObjectState(jsObject, next);
1591 return handleError(DataCloneError, "A value could not be cloned.", next);
1597 // Interface used by Reader to create objects of composite types.
1598 class CompositeCreator {
1601 virtual ~CompositeCreator() { }
1603 virtual bool consumeTopOfStack(v8::Handle<v8::Value>*) = 0;
1604 virtual uint32_t objectReferenceCount() = 0;
1605 virtual void pushObjectReference(const v8::Handle<v8::Value>&) = 0;
1606 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>*) = 0;
1607 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>*) = 0;
1608 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>*) = 0;
1609 virtual bool newSparseArray(uint32_t length) = 0;
1610 virtual bool newDenseArray(uint32_t length) = 0;
1611 virtual bool newObject() = 0;
1612 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>*) = 0;
1613 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>*) = 0;
1614 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>*) = 0;
1617 // Reader is responsible for deserializing primitive types and
1618 // restoring information about saved objects of composite types.
1621 Reader(const uint8_t* buffer, int length, const WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, ScriptState* scriptState)
1622 : m_scriptState(scriptState)
1627 , m_blobInfo(blobInfo)
1628 , m_blobDataHandles(blobDataHandles)
1630 ASSERT(!(reinterpret_cast<size_t>(buffer) & 1));
1631 ASSERT(length >= 0);
1634 bool isEof() const { return m_position >= m_length; }
1636 ScriptState* scriptState() const { return m_scriptState.get(); }
1639 v8::Isolate* isolate() const { return m_scriptState->isolate(); }
1642 bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator)
1644 SerializationTag tag;
1648 case ReferenceCountTag: {
1651 uint32_t referenceTableSize;
1652 if (!doReadUint32(&referenceTableSize))
1654 // If this test fails, then the serializer and deserializer disagree about the assignment
1655 // of object reference IDs. On the deserialization side, this means there are too many or too few
1656 // calls to pushObjectReference.
1657 if (referenceTableSize != creator.objectReferenceCount())
1666 *value = v8::Undefined(isolate());
1669 *value = v8::Null(isolate());
1672 *value = v8Boolean(true, isolate());
1675 *value = v8Boolean(false, isolate());
1678 *value = v8::BooleanObject::New(true);
1679 creator.pushObjectReference(*value);
1681 case FalseObjectTag:
1682 *value = v8::BooleanObject::New(false);
1683 creator.pushObjectReference(*value);
1686 if (!readString(value))
1689 case StringUCharTag:
1690 if (!readUCharString(value))
1693 case StringObjectTag:
1694 if (!readStringObject(value))
1696 creator.pushObjectReference(*value);
1699 if (!readInt32(value))
1703 if (!readUint32(value))
1707 if (!readDate(value))
1709 creator.pushObjectReference(*value);
1712 if (!readNumber(value))
1715 case NumberObjectTag:
1716 if (!readNumberObject(value))
1718 creator.pushObjectReference(*value);
1722 if (!readBlob(value, tag == BlobIndexTag))
1724 creator.pushObjectReference(*value);
1728 if (!readFile(value, tag == FileIndexTag))
1730 creator.pushObjectReference(*value);
1732 case DOMFileSystemTag:
1733 if (!readDOMFileSystem(value))
1735 creator.pushObjectReference(*value);
1738 case FileListIndexTag:
1739 if (!readFileList(value, tag == FileListIndexTag))
1741 creator.pushObjectReference(*value);
1744 if (!readCryptoKey(value))
1746 creator.pushObjectReference(*value);
1749 if (!readImageData(value))
1751 creator.pushObjectReference(*value);
1755 if (!readRegExp(value))
1757 creator.pushObjectReference(*value);
1760 uint32_t numProperties;
1761 if (!doReadUint32(&numProperties))
1763 if (!creator.completeObject(numProperties, value))
1767 case SparseArrayTag: {
1768 uint32_t numProperties;
1770 if (!doReadUint32(&numProperties))
1772 if (!doReadUint32(&length))
1774 if (!creator.completeSparseArray(numProperties, length, value))
1778 case DenseArrayTag: {
1779 uint32_t numProperties;
1781 if (!doReadUint32(&numProperties))
1783 if (!doReadUint32(&length))
1785 if (!creator.completeDenseArray(numProperties, length, value))
1789 case ArrayBufferViewTag: {
1792 if (!readArrayBufferView(value, creator))
1794 creator.pushObjectReference(*value);
1797 case ArrayBufferTag: {
1800 if (!readArrayBuffer(value))
1802 creator.pushObjectReference(*value);
1805 case GenerateFreshObjectTag: {
1808 if (!creator.newObject())
1812 case GenerateFreshSparseArrayTag: {
1816 if (!doReadUint32(&length))
1818 if (!creator.newSparseArray(length))
1822 case GenerateFreshDenseArrayTag: {
1826 if (!doReadUint32(&length))
1828 if (!creator.newDenseArray(length))
1832 case MessagePortTag: {
1836 if (!doReadUint32(&index))
1838 if (!creator.tryGetTransferredMessagePort(index, value))
1842 case ArrayBufferTransferTag: {
1846 if (!doReadUint32(&index))
1848 if (!creator.tryGetTransferredArrayBuffer(index, value))
1852 case ObjectReferenceTag: {
1856 if (!doReadUint32(&reference))
1858 if (!creator.tryGetObjectFromObjectReference(reference, value))
1865 return !value->IsEmpty();
1868 bool readVersion(uint32_t& version)
1870 SerializationTag tag;
1871 if (!readTag(&tag)) {
1872 // This is a nullary buffer. We're still version 0.
1876 if (tag != VersionTag) {
1877 // Versions of the format past 0 start with the version tag.
1879 // Put back the tag.
1883 // Version-bearing messages are obligated to finish the version tag.
1884 return doReadUint32(&version);
1887 void setVersion(uint32_t version)
1889 m_version = version;
1893 bool readTag(SerializationTag* tag)
1895 if (m_position >= m_length)
1897 *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
1907 bool readArrayBufferViewSubTag(ArrayBufferViewSubTag* tag)
1909 if (m_position >= m_length)
1911 *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]);
1915 bool readString(v8::Handle<v8::Value>* value)
1918 if (!doReadUint32(&length))
1920 if (m_position + length > m_length)
1922 *value = v8::String::NewFromUtf8(isolate(), reinterpret_cast<const char*>(m_buffer + m_position), v8::String::kNormalString, length);
1923 m_position += length;
1927 bool readUCharString(v8::Handle<v8::Value>* value)
1930 if (!doReadUint32(&length) || (length & 1))
1932 if (m_position + length > m_length)
1934 ASSERT(!(m_position & 1));
1935 *value = v8::String::NewFromTwoByte(isolate(), reinterpret_cast<const uint16_t*>(m_buffer + m_position), v8::String::kNormalString, length / sizeof(UChar));
1936 m_position += length;
1940 bool readStringObject(v8::Handle<v8::Value>* value)
1942 v8::Handle<v8::Value> stringValue;
1943 if (!readString(&stringValue) || !stringValue->IsString())
1945 *value = v8::StringObject::New(stringValue.As<v8::String>());
1949 bool readWebCoreString(String* string)
1952 if (!doReadUint32(&length))
1954 if (m_position + length > m_length)
1956 *string = String::fromUTF8(reinterpret_cast<const char*>(m_buffer + m_position), length);
1957 m_position += length;
1961 bool readInt32(v8::Handle<v8::Value>* value)
1964 if (!doReadUint32(&rawValue))
1966 *value = v8::Integer::New(isolate(), static_cast<int32_t>(ZigZag::decode(rawValue)));
1970 bool readUint32(v8::Handle<v8::Value>* value)
1973 if (!doReadUint32(&rawValue))
1975 *value = v8::Integer::NewFromUnsigned(isolate(), rawValue);
1979 bool readDate(v8::Handle<v8::Value>* value)
1982 if (!doReadNumber(&numberValue))
1984 *value = v8DateOrNaN(numberValue, isolate());
1988 bool readNumber(v8::Handle<v8::Value>* value)
1991 if (!doReadNumber(&number))
1993 *value = v8::Number::New(isolate(), number);
1997 bool readNumberObject(v8::Handle<v8::Value>* value)
2000 if (!doReadNumber(&number))
2002 *value = v8::NumberObject::New(isolate(), number);
2006 bool readImageData(v8::Handle<v8::Value>* value)
2010 uint32_t pixelDataLength;
2011 if (!doReadUint32(&width))
2013 if (!doReadUint32(&height))
2015 if (!doReadUint32(&pixelDataLength))
2017 if (m_position + pixelDataLength > m_length)
2019 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(IntSize(width, height));
2020 Uint8ClampedArray* pixelArray = imageData->data();
2022 ASSERT(pixelArray->length() >= pixelDataLength);
2023 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
2024 m_position += pixelDataLength;
2025 *value = toV8(imageData.release(), m_scriptState->context()->Global(), isolate());
2029 PassRefPtr<ArrayBuffer> doReadArrayBuffer()
2031 uint32_t byteLength;
2032 if (!doReadUint32(&byteLength))
2034 if (m_position + byteLength > m_length)
2036 const void* bufferStart = m_buffer + m_position;
2037 RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(bufferStart, byteLength);
2038 arrayBuffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
2039 m_position += byteLength;
2040 return arrayBuffer.release();
2043 bool readArrayBuffer(v8::Handle<v8::Value>* value)
2045 RefPtr<ArrayBuffer> arrayBuffer = doReadArrayBuffer();
2048 *value = toV8(arrayBuffer.release(), m_scriptState->context()->Global(), isolate());
2052 bool readArrayBufferView(v8::Handle<v8::Value>* value, CompositeCreator& creator)
2054 ArrayBufferViewSubTag subTag;
2055 uint32_t byteOffset;
2056 uint32_t byteLength;
2057 RefPtr<ArrayBuffer> arrayBuffer;
2058 v8::Handle<v8::Value> arrayBufferV8Value;
2059 if (!readArrayBufferViewSubTag(&subTag))
2061 if (!doReadUint32(&byteOffset))
2063 if (!doReadUint32(&byteLength))
2065 if (!creator.consumeTopOfStack(&arrayBufferV8Value))
2067 if (arrayBufferV8Value.IsEmpty())
2069 arrayBuffer = V8ArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
2073 v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
2076 *value = toV8(Int8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2078 case UnsignedByteArrayTag:
2079 *value = toV8(Uint8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2081 case UnsignedByteClampedArrayTag:
2082 *value = toV8(Uint8ClampedArray::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2084 case ShortArrayTag: {
2085 uint32_t shortLength = byteLength / sizeof(int16_t);
2086 if (shortLength * sizeof(int16_t) != byteLength)
2088 *value = toV8(Int16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
2091 case UnsignedShortArrayTag: {
2092 uint32_t shortLength = byteLength / sizeof(uint16_t);
2093 if (shortLength * sizeof(uint16_t) != byteLength)
2095 *value = toV8(Uint16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
2099 uint32_t intLength = byteLength / sizeof(int32_t);
2100 if (intLength * sizeof(int32_t) != byteLength)
2102 *value = toV8(Int32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
2105 case UnsignedIntArrayTag: {
2106 uint32_t intLength = byteLength / sizeof(uint32_t);
2107 if (intLength * sizeof(uint32_t) != byteLength)
2109 *value = toV8(Uint32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
2112 case FloatArrayTag: {
2113 uint32_t floatLength = byteLength / sizeof(float);
2114 if (floatLength * sizeof(float) != byteLength)
2116 *value = toV8(Float32Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
2119 case DoubleArrayTag: {
2120 uint32_t floatLength = byteLength / sizeof(double);
2121 if (floatLength * sizeof(double) != byteLength)
2123 *value = toV8(Float64Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
2127 *value = toV8(DataView::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
2132 // The various *Array::create() methods will return null if the range the view expects is
2133 // mismatched with the range the buffer can provide or if the byte offset is not aligned
2134 // to the size of the element type.
2135 return !value->IsEmpty();
2138 bool readRegExp(v8::Handle<v8::Value>* value)
2140 v8::Handle<v8::Value> pattern;
2141 if (!readString(&pattern))
2144 if (!doReadUint32(&flags))
2146 *value = v8::RegExp::New(pattern.As<v8::String>(), static_cast<v8::RegExp::Flags>(flags));
2150 bool readBlob(v8::Handle<v8::Value>* value, bool isIndexed)
2154 RefPtrWillBeRawPtr<Blob> blob;
2160 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2162 const blink::WebBlobInfo& info = (*m_blobInfo)[index];
2163 blob = Blob::create(getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2165 ASSERT(!m_blobInfo);
2169 ASSERT(!m_blobInfo);
2170 if (!readWebCoreString(&uuid))
2172 if (!readWebCoreString(&type))
2174 if (!doReadUint64(&size))
2176 blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size));
2178 *value = toV8(blob.release(), m_scriptState->context()->Global(), isolate());
2182 bool readDOMFileSystem(v8::Handle<v8::Value>* value)
2187 if (!doReadUint32(&type))
2189 if (!readWebCoreString(&name))
2191 if (!readWebCoreString(&url))
2193 DOMFileSystem* fs = DOMFileSystem::create(m_scriptState->executionContext(), name, static_cast<blink::FileSystemType>(type), KURL(ParsedURLString, url));
2194 *value = toV8(fs, m_scriptState->context()->Global(), isolate());
2198 bool readFile(v8::Handle<v8::Value>* value, bool isIndexed)
2200 RefPtrWillBeRawPtr<File> file;
2204 file = readFileIndexHelper();
2206 file = readFileHelper();
2210 *value = toV8(file.release(), m_scriptState->context()->Global(), isolate());
2214 bool readFileList(v8::Handle<v8::Value>* value, bool isIndexed)
2219 if (!doReadUint32(&length))
2221 RefPtrWillBeRawPtr<FileList> fileList = FileList::create();
2222 for (unsigned i = 0; i < length; ++i) {
2223 RefPtrWillBeRawPtr<File> file;
2227 file = readFileIndexHelper();
2229 file = readFileHelper();
2233 fileList->append(file.release());
2235 *value = toV8(fileList.release(), m_scriptState->context()->Global(), isolate());
2239 bool readCryptoKey(v8::Handle<v8::Value>* value)
2241 uint32_t rawKeyType;
2242 if (!doReadUint32(&rawKeyType))
2245 blink::WebCryptoKeyAlgorithm algorithm;
2246 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret;
2248 switch (static_cast<CryptoKeySubTag>(rawKeyType)) {
2250 if (!doReadAesKey(algorithm, type))
2254 if (!doReadHmacKey(algorithm, type))
2257 case RsaHashedKeyTag:
2258 if (!doReadRsaHashedKey(algorithm, type))
2265 blink::WebCryptoKeyUsageMask usages;
2267 if (!doReadKeyUsages(usages, extractable))
2270 uint32_t keyDataLength;
2271 if (!doReadUint32(&keyDataLength))
2274 if (m_position + keyDataLength > m_length)
2277 const uint8_t* keyData = m_buffer + m_position;
2278 m_position += keyDataLength;
2280 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2281 if (!blink::Platform::current()->crypto()->deserializeKeyForClone(
2282 algorithm, type, extractable, usages, keyData, keyDataLength, key)) {
2286 *value = toV8(CryptoKey::create(key), m_scriptState->context()->Global(), isolate());
2290 PassRefPtrWillBeRawPtr<File> readFileHelper()
2294 ASSERT(!m_blobInfo);
2297 String relativePath;
2300 uint32_t hasSnapshot = 0;
2302 double lastModified = 0;
2303 if (!readWebCoreString(&path))
2305 if (m_version >= 4 && !readWebCoreString(&name))
2307 if (m_version >= 4 && !readWebCoreString(&relativePath))
2309 if (!readWebCoreString(&uuid))
2311 if (!readWebCoreString(&type))
2313 if (m_version >= 4 && !doReadUint32(&hasSnapshot))
2316 if (!doReadUint64(&size))
2318 if (!doReadNumber(&lastModified))
2321 uint32_t isUserVisible = 1;
2322 if (m_version >= 7 && !doReadUint32(&isUserVisible))
2324 const File::UserVisibility userVisibility = (isUserVisible > 0) ? File::IsUserVisible : File::IsNotUserVisible;
2325 return File::createFromSerialization(path, name, relativePath, userVisibility, hasSnapshot > 0, size, lastModified, getOrCreateBlobDataHandle(uuid, type));
2328 PassRefPtrWillBeRawPtr<File> readFileIndexHelper()
2334 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2336 const WebBlobInfo& info = (*m_blobInfo)[index];
2337 return File::createFromIndexedSerialization(info.filePath(), info.fileName(), info.size(), info.lastModified(), getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2341 bool doReadUintHelper(T* value)
2344 uint8_t currentByte;
2347 if (m_position >= m_length)
2349 currentByte = m_buffer[m_position++];
2350 *value |= ((currentByte & varIntMask) << shift);
2351 shift += varIntShift;
2352 } while (currentByte & (1 << varIntShift));
2356 bool doReadUint32(uint32_t* value)
2358 return doReadUintHelper(value);
2361 bool doReadUint64(uint64_t* value)
2363 return doReadUintHelper(value);
2366 bool doReadNumber(double* number)
2368 if (m_position + sizeof(double) > m_length)
2370 uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number);
2371 for (unsigned i = 0; i < sizeof(double); ++i)
2372 numberAsByteArray[i] = m_buffer[m_position++];
2376 PassRefPtr<BlobDataHandle> getOrCreateBlobDataHandle(const String& uuid, const String& type, long long size = -1)
2378 // The containing ssv may have a BDH for this uuid if this ssv is just being
2379 // passed from main to worker thread (for example). We use those values when creating
2380 // the new blob instead of cons'ing up a new BDH.
2382 // FIXME: Maybe we should require that it work that way where the ssv must have a BDH for any
2383 // blobs it comes across during deserialization. Would require callers to explicitly populate
2384 // the collection of BDH's for blobs to work, which would encourage lifetimes to be considered
2385 // when passing ssv's around cross process. At present, we get 'lucky' in some cases because
2386 // the blob in the src process happens to still exist at the time the dest process is deserializing.
2387 // For example in sharedWorker.postMessage(...).
2388 BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid);
2389 if (it != m_blobDataHandles.end()) {
2390 // make assertions about type and size?
2393 return BlobDataHandle::create(uuid, type, size);
2396 bool doReadHmacKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2398 uint32_t lengthBytes;
2399 if (!doReadUint32(&lengthBytes))
2401 blink::WebCryptoAlgorithmId hash;
2402 if (!doReadAlgorithmId(hash))
2404 algorithm = blink::WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes * 8);
2405 type = blink::WebCryptoKeyTypeSecret;
2406 return !algorithm.isNull();
2409 bool doReadAesKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2411 blink::WebCryptoAlgorithmId id;
2412 if (!doReadAlgorithmId(id))
2414 uint32_t lengthBytes;
2415 if (!doReadUint32(&lengthBytes))
2417 algorithm = blink::WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8);
2418 type = blink::WebCryptoKeyTypeSecret;
2419 return !algorithm.isNull();
2422 bool doReadRsaHashedKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type)
2424 blink::WebCryptoAlgorithmId id;
2425 if (!doReadAlgorithmId(id))
2429 if (!doReadUint32(&rawType))
2432 switch (static_cast<AssymetricCryptoKeyType>(rawType)) {
2434 type = blink::WebCryptoKeyTypePublic;
2436 case PrivateKeyType:
2437 type = blink::WebCryptoKeyTypePrivate;
2443 uint32_t modulusLengthBits;
2444 if (!doReadUint32(&modulusLengthBits))
2447 uint32_t publicExponentSize;
2448 if (!doReadUint32(&publicExponentSize))
2451 if (m_position + publicExponentSize > m_length)
2454 const uint8_t* publicExponent = m_buffer + m_position;
2455 m_position += publicExponentSize;
2457 blink::WebCryptoAlgorithmId hash;
2458 if (!doReadAlgorithmId(hash))
2460 algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLengthBits, publicExponent, publicExponentSize, hash);
2462 return !algorithm.isNull();
2465 bool doReadAlgorithmId(blink::WebCryptoAlgorithmId& id)
2468 if (!doReadUint32(&rawId))
2471 switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) {
2473 id = blink::WebCryptoAlgorithmIdAesCbc;
2476 id = blink::WebCryptoAlgorithmIdHmac;
2478 case RsaSsaPkcs1v1_5Tag:
2479 id = blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
2482 id = blink::WebCryptoAlgorithmIdSha1;
2485 id = blink::WebCryptoAlgorithmIdSha256;
2488 id = blink::WebCryptoAlgorithmIdSha384;
2491 id = blink::WebCryptoAlgorithmIdSha512;
2494 id = blink::WebCryptoAlgorithmIdAesGcm;
2497 id = blink::WebCryptoAlgorithmIdRsaOaep;
2500 id = blink::WebCryptoAlgorithmIdAesCtr;
2503 id = blink::WebCryptoAlgorithmIdAesKw;
2510 bool doReadKeyUsages(blink::WebCryptoKeyUsageMask& usages, bool& extractable)
2512 // Reminder to update this when adding new key usages.
2513 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
2514 const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | DecryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyUsage | DeriveBitsUsage;
2517 if (!doReadUint32(&rawUsages))
2520 // Make sure it doesn't contain an unrecognized usage value.
2521 if (rawUsages & ~allPossibleUsages)
2526 extractable = rawUsages & ExtractableUsage;
2528 if (rawUsages & EncryptUsage)
2529 usages |= blink::WebCryptoKeyUsageEncrypt;
2530 if (rawUsages & DecryptUsage)
2531 usages |= blink::WebCryptoKeyUsageDecrypt;
2532 if (rawUsages & SignUsage)
2533 usages |= blink::WebCryptoKeyUsageSign;
2534 if (rawUsages & VerifyUsage)
2535 usages |= blink::WebCryptoKeyUsageVerify;
2536 if (rawUsages & DeriveKeyUsage)
2537 usages |= blink::WebCryptoKeyUsageDeriveKey;
2538 if (rawUsages & WrapKeyUsage)
2539 usages |= blink::WebCryptoKeyUsageWrapKey;
2540 if (rawUsages & UnwrapKeyUsage)
2541 usages |= blink::WebCryptoKeyUsageUnwrapKey;
2542 if (rawUsages & DeriveBitsUsage)
2543 usages |= blink::WebCryptoKeyUsageDeriveBits;
2548 RefPtr<ScriptState> m_scriptState;
2549 const uint8_t* m_buffer;
2550 const unsigned m_length;
2551 unsigned m_position;
2553 const WebBlobInfoArray* m_blobInfo;
2554 const BlobDataHandleMap& m_blobDataHandles;
2558 typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray;
2560 class Deserializer FINAL : public CompositeCreator {
2562 Deserializer(Reader& reader, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents)
2564 , m_transferredMessagePorts(messagePorts)
2565 , m_arrayBufferContents(arrayBufferContents)
2566 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
2571 v8::Handle<v8::Value> deserialize()
2573 v8::Isolate* isolate = m_reader.scriptState()->isolate();
2574 if (!m_reader.readVersion(m_version) || m_version > SerializedScriptValue::wireFormatVersion)
2575 return v8::Null(isolate);
2576 m_reader.setVersion(m_version);
2577 v8::EscapableHandleScope scope(isolate);
2578 while (!m_reader.isEof()) {
2579 if (!doDeserialize())
2580 return v8::Null(isolate);
2582 if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
2583 return v8::Null(isolate);
2584 v8::Handle<v8::Value> result = scope.Escape(element(0));
2588 virtual bool newSparseArray(uint32_t) OVERRIDE
2590 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), 0);
2591 openComposite(array);
2595 virtual bool newDenseArray(uint32_t length) OVERRIDE
2597 v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), length);
2598 openComposite(array);
2602 virtual bool consumeTopOfStack(v8::Handle<v8::Value>* object) OVERRIDE
2604 if (stackDepth() < 1)
2606 *object = element(stackDepth() - 1);
2611 virtual bool newObject() OVERRIDE
2613 v8::Local<v8::Object> object = v8::Object::New(m_reader.scriptState()->isolate());
2614 if (object.IsEmpty())
2616 openComposite(object);
2620 virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>* value) OVERRIDE
2622 v8::Local<v8::Object> object;
2623 if (m_version > 0) {
2624 v8::Local<v8::Value> composite;
2625 if (!closeComposite(&composite))
2627 object = composite.As<v8::Object>();
2629 object = v8::Object::New(m_reader.scriptState()->isolate());
2631 if (object.IsEmpty())
2633 return initializeObject(object, numProperties, value);
2636 virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) OVERRIDE
2638 v8::Local<v8::Array> array;
2639 if (m_version > 0) {
2640 v8::Local<v8::Value> composite;
2641 if (!closeComposite(&composite))
2643 array = composite.As<v8::Array>();
2645 array = v8::Array::New(m_reader.scriptState()->isolate());
2647 if (array.IsEmpty())
2649 return initializeObject(array, numProperties, value);
2652 virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) OVERRIDE
2654 v8::Local<v8::Array> array;
2655 if (m_version > 0) {
2656 v8::Local<v8::Value> composite;
2657 if (!closeComposite(&composite))
2659 array = composite.As<v8::Array>();
2661 if (array.IsEmpty())
2663 if (!initializeObject(array, numProperties, value))
2665 if (length > stackDepth())
2667 for (unsigned i = 0, stackPos = stackDepth() - length; i < length; i++, stackPos++) {
2668 v8::Local<v8::Value> elem = element(stackPos);
2669 if (!elem->IsUndefined())
2670 array->Set(i, elem);
2676 virtual void pushObjectReference(const v8::Handle<v8::Value>& object) OVERRIDE
2678 m_objectPool.append(object);
2681 virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>* object) OVERRIDE
2683 if (!m_transferredMessagePorts)
2685 if (index >= m_transferredMessagePorts->size())
2687 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
2688 *object = toV8(m_transferredMessagePorts->at(index).get(), creationContext, m_reader.scriptState()->isolate());
2692 virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>* object) OVERRIDE
2694 if (!m_arrayBufferContents)
2696 if (index >= m_arrayBuffers.size())
2698 v8::Handle<v8::Object> result = m_arrayBuffers.at(index);
2699 if (result.IsEmpty()) {
2700 RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(m_arrayBufferContents->at(index));
2701 buffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
2702 v8::Isolate* isolate = m_reader.scriptState()->isolate();
2703 v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
2704 isolate->AdjustAmountOfExternalAllocatedMemory(buffer->byteLength());
2705 result = toV8Object(buffer.get(), creationContext, isolate);
2706 m_arrayBuffers[index] = result;
2712 virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>* object) OVERRIDE
2714 if (reference >= m_objectPool.size())
2716 *object = m_objectPool[reference];
2720 virtual uint32_t objectReferenceCount() OVERRIDE
2722 return m_objectPool.size();
2726 bool initializeObject(v8::Handle<v8::Object> object, uint32_t numProperties, v8::Handle<v8::Value>* value)
2728 unsigned length = 2 * numProperties;
2729 if (length > stackDepth())
2731 for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) {
2732 v8::Local<v8::Value> propertyName = element(i);
2733 v8::Local<v8::Value> propertyValue = element(i + 1);
2734 object->Set(propertyName, propertyValue);
2741 bool doDeserialize()
2743 v8::Local<v8::Value> value;
2744 if (!m_reader.read(&value, *this))
2746 if (!value.IsEmpty())
2751 void push(v8::Local<v8::Value> value) { m_stack.append(value); }
2753 void pop(unsigned length)
2755 ASSERT(length <= m_stack.size());
2756 m_stack.shrink(m_stack.size() - length);
2759 unsigned stackDepth() const { return m_stack.size(); }
2761 v8::Local<v8::Value> element(unsigned index)
2763 ASSERT_WITH_SECURITY_IMPLICATION(index < m_stack.size());
2764 return m_stack[index];
2767 void openComposite(const v8::Local<v8::Value>& object)
2769 uint32_t newObjectReference = m_objectPool.size();
2770 m_openCompositeReferenceStack.append(newObjectReference);
2771 m_objectPool.append(object);
2774 bool closeComposite(v8::Handle<v8::Value>* object)
2776 if (!m_openCompositeReferenceStack.size())
2778 uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
2779 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1);
2780 if (objectReference >= m_objectPool.size())
2782 *object = m_objectPool[objectReference];
2787 Vector<v8::Local<v8::Value> > m_stack;
2788 Vector<v8::Handle<v8::Value> > m_objectPool;
2789 Vector<uint32_t> m_openCompositeReferenceStack;
2790 RawPtrWillBeMember<MessagePortArray> m_transferredMessagePorts;
2791 ArrayBufferContentsArray* m_arrayBufferContents;
2792 Vector<v8::Handle<v8::Object> > m_arrayBuffers;
2798 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
2800 return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, 0, exceptionState, isolate));
2803 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createAndSwallowExceptions(v8::Handle<v8::Value> value, v8::Isolate* isolate)
2805 TrackExceptionState exceptionState;
2806 return adoptRef(new SerializedScriptValue(value, 0, 0, 0, exceptionState, isolate));
2809 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const ScriptValue& value, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolate* isolate)
2811 ASSERT(isolate->InContext());
2812 return adoptRef(new SerializedScriptValue(value.v8Value(), 0, 0, blobInfo, exceptionState, isolate));
2815 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(const String& data)
2817 return adoptRef(new SerializedScriptValue(data));
2820 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWireBytes(const Vector<uint8_t>& data)
2822 // Decode wire data from big endian to host byte order.
2823 ASSERT(!(data.size() % sizeof(UChar)));
2824 size_t length = data.size() / sizeof(UChar);
2825 StringBuffer<UChar> buffer(length);
2826 const UChar* src = reinterpret_cast<const UChar*>(data.data());
2827 UChar* dst = buffer.characters();
2828 for (size_t i = 0; i < length; i++)
2829 dst[i] = ntohs(src[i]);
2831 return createFromWire(String::adopt(buffer));
2834 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& data)
2836 return create(data, v8::Isolate::GetCurrent());
2839 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& data, v8::Isolate* isolate)
2842 writer.writeWebCoreString(data);
2843 String wireData = writer.takeWireString();
2844 return adoptRef(new SerializedScriptValue(wireData));
2847 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
2849 return adoptRef(new SerializedScriptValue());
2852 PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
2856 String wireData = writer.takeWireString();
2857 return adoptRef(new SerializedScriptValue(wireData));
2860 // Convert serialized string to big endian wire data.
2861 void SerializedScriptValue::toWireBytes(Vector<char>& result) const
2863 ASSERT(result.isEmpty());
2864 size_t length = m_data.length();
2865 result.resize(length * sizeof(UChar));
2866 UChar* dst = reinterpret_cast<UChar*>(result.data());
2868 if (m_data.is8Bit()) {
2869 const LChar* src = m_data.characters8();
2870 for (size_t i = 0; i < length; i++)
2871 dst[i] = htons(static_cast<UChar>(src[i]));
2873 const UChar* src = m_data.characters16();
2874 for (size_t i = 0; i < length; i++)
2875 dst[i] = htons(src[i]);
2879 SerializedScriptValue::SerializedScriptValue()
2880 : m_externallyAllocatedMemory(0)
2884 static void neuterArrayBufferInAllWorlds(ArrayBuffer* object)
2886 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2887 if (isMainThread()) {
2888 Vector<RefPtr<DOMWrapperWorld> > worlds;
2889 DOMWrapperWorld::allWorldsInMainThread(worlds);
2890 for (size_t i = 0; i < worlds.size(); i++) {
2891 v8::Handle<v8::Object> wrapper = worlds[i]->domDataStore().get<V8ArrayBuffer>(object, isolate);
2892 if (!wrapper.IsEmpty()) {
2893 ASSERT(wrapper->IsArrayBuffer());
2894 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter();
2898 v8::Handle<v8::Object> wrapper = DOMWrapperWorld::current(isolate).domDataStore().get<V8ArrayBuffer>(object, isolate);
2899 if (!wrapper.IsEmpty()) {
2900 ASSERT(wrapper->IsArrayBuffer());
2901 v8::Handle<v8::ArrayBuffer>::Cast(wrapper)->Neuter();
2906 PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
2908 ASSERT(arrayBuffers.size());
2910 for (size_t i = 0; i < arrayBuffers.size(); i++) {
2911 if (arrayBuffers[i]->isNeutered()) {
2912 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is already neutered.");
2917 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
2919 HashSet<ArrayBuffer*> visited;
2920 for (size_t i = 0; i < arrayBuffers.size(); i++) {
2921 if (visited.contains(arrayBuffers[i].get()))
2923 visited.add(arrayBuffers[i].get());
2925 bool result = arrayBuffers[i]->transfer(contents->at(i));
2927 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " could not be transferred.");
2931 neuterArrayBufferInAllWorlds(arrayBuffers[i].get());
2933 return contents.release();
2936 SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolate* isolate)
2937 : m_externallyAllocatedMemory(0)
2940 Serializer::Status status;
2941 String errorMessage;
2943 v8::TryCatch tryCatch;
2944 Serializer serializer(writer, messagePorts, arrayBuffers, blobInfo, m_blobDataHandles, tryCatch, ScriptState::current(isolate));
2945 status = serializer.serialize(value);
2946 if (status == Serializer::JSException) {
2947 // If there was a JS exception thrown, re-throw it.
2948 exceptionState.rethrowV8Exception(tryCatch.Exception());
2951 errorMessage = serializer.errorMessage();
2954 case Serializer::InputError:
2955 case Serializer::DataCloneError:
2956 exceptionState.throwDOMException(DataCloneError, errorMessage);
2958 case Serializer::Success:
2959 m_data = writer.takeWireString();
2960 ASSERT(m_data.impl()->hasOneRef());
2961 if (arrayBuffers && arrayBuffers->size())
2962 m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, exceptionState, isolate);
2964 case Serializer::JSException:
2965 ASSERT_NOT_REACHED();
2968 ASSERT_NOT_REACHED();
2971 SerializedScriptValue::SerializedScriptValue(const String& wireData)
2972 : m_externallyAllocatedMemory(0)
2974 m_data = wireData.isolatedCopy();
2977 v8::Handle<v8::Value> SerializedScriptValue::deserialize(MessagePortArray* messagePorts)
2979 return deserialize(v8::Isolate::GetCurrent(), messagePorts, 0);
2982 v8::Handle<v8::Value> SerializedScriptValue::deserialize(v8::Isolate* isolate, MessagePortArray* messagePorts, const WebBlobInfoArray* blobInfo)
2985 return v8::Null(isolate);
2986 COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
2987 m_data.ensure16Bit();
2988 // FIXME: SerializedScriptValue shouldn't use String for its underlying
2989 // storage. Instead, it should use SharedBuffer or Vector<uint8_t>. The
2990 // information stored in m_data isn't even encoded in UTF-16. Instead,
2991 // unicode characters are encoded as UTF-8 with two code units per UChar.
2992 Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters16()), 2 * m_data.length(), blobInfo, m_blobDataHandles, ScriptState::current(isolate));
2993 Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.get());
2995 // deserialize() can run arbitrary script (e.g., setters), which could result in |this| being destroyed.
2996 // Holding a RefPtr ensures we are alive (along with our internal data) throughout the operation.
2997 RefPtr<SerializedScriptValue> protect(this);
2998 return deserializer.deserialize();
3001 bool SerializedScriptValue::extractTransferables(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
3003 if (isUndefinedOrNull(value)) {
3005 arrayBuffers.resize(0);
3009 uint32_t length = 0;
3010 if (value->IsArray()) {
3011 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value);
3012 length = array->Length();
3013 } else if (!toV8Sequence(value, length, isolate, exceptionState)) {
3014 if (!exceptionState.hadException())
3015 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex + 1));
3019 v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value);
3021 // Validate the passed array of transferrables.
3022 for (unsigned i = 0; i < length; ++i) {
3023 v8::Local<v8::Value> transferrable = transferrables->Get(i);
3024 // Validation of non-null objects, per HTML5 spec 10.3.3.
3025 if (isUndefinedOrNull(transferrable)) {
3026 exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " is an untransferable " + (transferrable->IsUndefined() ? "'undefined'" : "'null'") + " value.");
3029 // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
3030 if (V8MessagePort::hasInstance(transferrable, isolate)) {
3031 RefPtrWillBeRawPtr<MessagePort> port = V8MessagePort::toImpl(v8::Handle<v8::Object>::Cast(transferrable));
3032 // Check for duplicate MessagePorts.
3033 if (ports.contains(port)) {
3034 exceptionState.throwDOMException(DataCloneError, "Message port at index " + String::number(i) + " is a duplicate of an earlier port.");
3037 ports.append(port.release());
3038 } else if (V8ArrayBuffer::hasInstance(transferrable, isolate)) {
3039 RefPtr<ArrayBuffer> arrayBuffer = V8ArrayBuffer::toImpl(v8::Handle<v8::Object>::Cast(transferrable));
3040 if (arrayBuffers.contains(arrayBuffer)) {
3041 exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is a duplicate of an earlier ArrayBuffer.");
3044 arrayBuffers.append(arrayBuffer.release());
3046 exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " does not have a transferable type.");
3053 void SerializedScriptValue::registerMemoryAllocatedWithCurrentScriptContext()
3055 if (m_externallyAllocatedMemory)
3057 m_externallyAllocatedMemory = static_cast<intptr_t>(m_data.length());
3058 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(m_externallyAllocatedMemory);
3061 SerializedScriptValue::~SerializedScriptValue()
3063 // If the allocated memory was not registered before, then this class is likely
3064 // used in a context other then Worker's onmessage environment and the presence of
3065 // current v8 context is not guaranteed. Avoid calling v8 then.
3066 if (m_externallyAllocatedMemory) {
3067 ASSERT(v8::Isolate::GetCurrent());
3068 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_externallyAllocatedMemory);
3072 } // namespace blink