Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp

Issue 2686113002: Remove ScriptValueSerializer. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "bindings/core/v8/ScriptValueSerializer.h"
6
7 #include "bindings/core/v8/Transferables.h"
8 #include "bindings/core/v8/V8ArrayBuffer.h"
9 #include "bindings/core/v8/V8ArrayBufferView.h"
10 #include "bindings/core/v8/V8Blob.h"
11 #include "bindings/core/v8/V8CompositorProxy.h"
12 #include "bindings/core/v8/V8File.h"
13 #include "bindings/core/v8/V8FileList.h"
14 #include "bindings/core/v8/V8ImageBitmap.h"
15 #include "bindings/core/v8/V8ImageData.h"
16 #include "bindings/core/v8/V8MessagePort.h"
17 #include "bindings/core/v8/V8OffscreenCanvas.h"
18 #include "bindings/core/v8/V8SharedArrayBuffer.h"
19 #include "core/dom/CompositorProxy.h"
20 #include "core/dom/DOMDataView.h"
21 #include "core/dom/DOMSharedArrayBuffer.h"
22 #include "core/dom/DOMTypedArray.h"
23 #include "core/fileapi/Blob.h"
24 #include "core/fileapi/File.h"
25 #include "core/fileapi/FileList.h"
26 #include "platform/RuntimeEnabledFeatures.h"
27 #include "public/platform/Platform.h"
28 #include "public/platform/WebBlobInfo.h"
29 #include "wtf/DateMath.h"
30 #include "wtf/text/StringHash.h"
31 #include "wtf/text/StringUTF8Adaptor.h"
32 #include <memory>
33
34 // FIXME: consider crashing in debug mode on deserialization errors
35 // NOTE: be sure to change wireFormatVersion as necessary!
36
37 namespace blink {
38
39 namespace {
40
41 // This code implements the HTML5 Structured Clone algorithm:
42 // http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-pa ssing-of-structured-data
43
44 // ZigZag encoding helps VarInt encoding stay small for negative
45 // numbers with small absolute values.
46 class ZigZag {
47 public:
48 static uint32_t encode(uint32_t value) {
49 if (value & (1U << 31))
50 value = ((~value) << 1) + 1;
51 else
52 value <<= 1;
53 return value;
54 }
55
56 static uint32_t decode(uint32_t value) {
57 if (value & 1)
58 value = ~(value >> 1);
59 else
60 value >>= 1;
61 return value;
62 }
63
64 private:
65 ZigZag();
66 };
67
68 const int maxDepth = 20000;
69
70 bool shouldCheckForCycles(int depth) {
71 ASSERT(depth >= 0);
72 // Since we are not required to spot the cycle as soon as it
73 // happens we can check for cycles only when the current depth
74 // is a power of two.
75 return !(depth & (depth - 1));
76 }
77
78 // Returns true if the provided object is to be considered a 'host object', as
79 // used in the HTML5 structured clone algorithm.
80 bool isHostObject(v8::Local<v8::Object> object) {
81 // If the object has any internal fields, then we won't be able to serialize
82 // or deserialize them; conveniently, this is also a quick way to detect DOM
83 // wrapper objects, because the mechanism for these relies on data stored in
84 // these fields. We should catch external array data as a special case.
85 return object->InternalFieldCount();
86 }
87
88 } // namespace
89
90 void SerializedScriptValueWriter::writeUndefined() {
91 append(UndefinedTag);
92 }
93
94 void SerializedScriptValueWriter::writeNull() {
95 append(NullTag);
96 }
97
98 void SerializedScriptValueWriter::writeTrue() {
99 append(TrueTag);
100 }
101
102 void SerializedScriptValueWriter::writeFalse() {
103 append(FalseTag);
104 }
105
106 void SerializedScriptValueWriter::writeBooleanObject(bool value) {
107 append(value ? TrueObjectTag : FalseObjectTag);
108 }
109
110 void SerializedScriptValueWriter::writeRawStringBytes(
111 v8::Local<v8::String>& string) {
112 int rawLength = string->Length();
113 string->WriteOneByte(byteAt(m_position), 0, rawLength,
114 v8StringWriteOptions());
115 m_position += rawLength;
116 }
117
118 void SerializedScriptValueWriter::writeUtf8String(
119 v8::Local<v8::String>& string) {
120 int utf8Length = string->Utf8Length();
121 char* buffer = reinterpret_cast<char*>(byteAt(m_position));
122 string->WriteUtf8(buffer, utf8Length, 0, v8StringWriteOptions());
123 m_position += utf8Length;
124 }
125
126 void SerializedScriptValueWriter::writeOneByteString(
127 v8::Local<v8::String>& string) {
128 int stringLength = string->Length();
129 int utf8Length = string->Utf8Length();
130 ASSERT(stringLength >= 0 && utf8Length >= 0);
131
132 append(StringTag);
133 doWriteUint32(static_cast<uint32_t>(utf8Length));
134 ensureSpace(utf8Length);
135
136 // ASCII fast path.
137 if (stringLength == utf8Length) {
138 writeRawStringBytes(string);
139 } else {
140 writeUtf8String(string);
141 }
142 }
143
144 void SerializedScriptValueWriter::writeUCharString(
145 v8::Local<v8::String>& string) {
146 int length = string->Length();
147 ASSERT(length >= 0);
148
149 int size = length * sizeof(UChar);
150 int bytes = bytesNeededToWireEncode(static_cast<uint32_t>(size));
151 if ((m_position + 1 + bytes) & 1)
152 append(PaddingTag);
153
154 append(StringUCharTag);
155 doWriteUint32(static_cast<uint32_t>(size));
156 ensureSpace(size);
157
158 ASSERT(!(m_position & 1));
159 uint16_t* buffer = reinterpret_cast<uint16_t*>(byteAt(m_position));
160 string->Write(buffer, 0, length, v8StringWriteOptions());
161 m_position += size;
162 }
163
164 void SerializedScriptValueWriter::writeStringObject(const char* data,
165 int length) {
166 ASSERT(length >= 0);
167 append(StringObjectTag);
168 doWriteString(data, length);
169 }
170
171 void SerializedScriptValueWriter::writeWebCoreString(const String& string) {
172 // Uses UTF8 encoding so we can read it back as either V8 or
173 // WebCore string.
174 append(StringTag);
175 doWriteWebCoreString(string);
176 }
177
178 void SerializedScriptValueWriter::writeVersion() {
179 append(VersionTag);
180 doWriteUint32(SerializedScriptValue::wireFormatVersion);
181 }
182
183 void SerializedScriptValueWriter::writeInt32(int32_t value) {
184 append(Int32Tag);
185 doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
186 }
187
188 void SerializedScriptValueWriter::writeUint32(uint32_t value) {
189 append(Uint32Tag);
190 doWriteUint32(value);
191 }
192
193 void SerializedScriptValueWriter::writeDate(double numberValue) {
194 append(DateTag);
195 doWriteNumber(numberValue);
196 }
197
198 void SerializedScriptValueWriter::writeNumber(double number) {
199 append(NumberTag);
200 doWriteNumber(number);
201 }
202
203 void SerializedScriptValueWriter::writeNumberObject(double number) {
204 append(NumberObjectTag);
205 doWriteNumber(number);
206 }
207
208 void SerializedScriptValueWriter::writeBlob(const String& uuid,
209 const String& type,
210 unsigned long long size) {
211 append(BlobTag);
212 doWriteWebCoreString(uuid);
213 doWriteWebCoreString(type);
214 doWriteUint64(size);
215 }
216
217 void SerializedScriptValueWriter::writeBlobIndex(int blobIndex) {
218 ASSERT(blobIndex >= 0);
219 append(BlobIndexTag);
220 doWriteUint32(blobIndex);
221 }
222
223 void SerializedScriptValueWriter::writeCompositorProxy(
224 const CompositorProxy& compositorProxy) {
225 append(CompositorProxyTag);
226 doWriteUint64(compositorProxy.elementId());
227 doWriteUint32(compositorProxy.compositorMutableProperties());
228 }
229
230 void SerializedScriptValueWriter::writeFile(const File& file) {
231 append(FileTag);
232 doWriteFile(file);
233 }
234
235 void SerializedScriptValueWriter::writeFileIndex(int blobIndex) {
236 append(FileIndexTag);
237 doWriteUint32(blobIndex);
238 }
239
240 void SerializedScriptValueWriter::writeFileList(const FileList& fileList) {
241 append(FileListTag);
242 uint32_t length = fileList.length();
243 doWriteUint32(length);
244 for (unsigned i = 0; i < length; ++i)
245 doWriteFile(*fileList.item(i));
246 }
247
248 void SerializedScriptValueWriter::writeFileListIndex(
249 const Vector<int>& blobIndices) {
250 append(FileListIndexTag);
251 uint32_t length = blobIndices.size();
252 doWriteUint32(length);
253 for (unsigned i = 0; i < length; ++i)
254 doWriteUint32(blobIndices[i]);
255 }
256
257 void SerializedScriptValueWriter::writeArrayBuffer(
258 const DOMArrayBuffer& arrayBuffer) {
259 append(ArrayBufferTag);
260 doWriteArrayBuffer(arrayBuffer);
261 }
262
263 void SerializedScriptValueWriter::writeArrayBufferView(
264 const DOMArrayBufferView& arrayBufferView) {
265 append(ArrayBufferViewTag);
266 #if DCHECK_IS_ON()
267 ASSERT(static_cast<const uint8_t*>(arrayBufferView.bufferBase()->data()) +
268 arrayBufferView.byteOffset() ==
269 static_cast<const uint8_t*>(arrayBufferView.baseAddress()));
270 #endif
271 DOMArrayBufferView::ViewType type = arrayBufferView.type();
272
273 switch (type) {
274 case DOMArrayBufferView::TypeInt8:
275 append(ByteArrayTag);
276 break;
277 case DOMArrayBufferView::TypeUint8Clamped:
278 append(UnsignedByteClampedArrayTag);
279 break;
280 case DOMArrayBufferView::TypeUint8:
281 append(UnsignedByteArrayTag);
282 break;
283 case DOMArrayBufferView::TypeInt16:
284 append(ShortArrayTag);
285 break;
286 case DOMArrayBufferView::TypeUint16:
287 append(UnsignedShortArrayTag);
288 break;
289 case DOMArrayBufferView::TypeInt32:
290 append(IntArrayTag);
291 break;
292 case DOMArrayBufferView::TypeUint32:
293 append(UnsignedIntArrayTag);
294 break;
295 case DOMArrayBufferView::TypeFloat32:
296 append(FloatArrayTag);
297 break;
298 case DOMArrayBufferView::TypeFloat64:
299 append(DoubleArrayTag);
300 break;
301 case DOMArrayBufferView::TypeDataView:
302 append(DataViewTag);
303 break;
304 default:
305 ASSERT_NOT_REACHED();
306 }
307 doWriteUint32(arrayBufferView.byteOffset());
308 doWriteUint32(arrayBufferView.byteLength());
309 }
310
311 // Helper function shared by writeImageData and writeImageBitmap
312 void SerializedScriptValueWriter::doWriteImageData(uint32_t width,
313 uint32_t height,
314 const uint8_t* pixelData,
315 uint32_t pixelDataLength) {
316 doWriteUint32(width);
317 doWriteUint32(height);
318 doWriteUint32(pixelDataLength);
319 append(pixelData, pixelDataLength);
320 }
321
322 void SerializedScriptValueWriter::writeImageData(uint32_t width,
323 uint32_t height,
324 const uint8_t* pixelData,
325 uint32_t pixelDataLength) {
326 append(ImageDataTag);
327 doWriteImageData(width, height, pixelData, pixelDataLength);
328 }
329
330 void SerializedScriptValueWriter::writeImageBitmap(uint32_t width,
331 uint32_t height,
332 uint32_t isOriginClean,
333 uint32_t isPremultiplied,
334 const uint8_t* pixelData,
335 uint32_t pixelDataLength) {
336 append(ImageBitmapTag);
337 append(isOriginClean);
338 append(isPremultiplied);
339 doWriteImageData(width, height, pixelData, pixelDataLength);
340 }
341
342 void SerializedScriptValueWriter::writeRegExp(v8::Local<v8::String> pattern,
343 v8::RegExp::Flags flags) {
344 append(RegExpTag);
345 v8::String::Utf8Value patternUtf8Value(pattern);
346 doWriteString(*patternUtf8Value, patternUtf8Value.length());
347 doWriteUint32(static_cast<uint32_t>(flags));
348 }
349
350 void SerializedScriptValueWriter::writeTransferredMessagePort(uint32_t index) {
351 append(MessagePortTag);
352 doWriteUint32(index);
353 }
354
355 void SerializedScriptValueWriter::writeTransferredArrayBuffer(uint32_t index) {
356 append(ArrayBufferTransferTag);
357 doWriteUint32(index);
358 }
359
360 void SerializedScriptValueWriter::writeTransferredImageBitmap(uint32_t index) {
361 append(ImageBitmapTransferTag);
362 doWriteUint32(index);
363 }
364
365 void SerializedScriptValueWriter::writeTransferredOffscreenCanvas(
366 uint32_t width,
367 uint32_t height,
368 uint32_t canvasId,
369 uint32_t clientId,
370 uint32_t sinkId) {
371 append(OffscreenCanvasTransferTag);
372 doWriteUint32(width);
373 doWriteUint32(height);
374 doWriteUint32(canvasId);
375 doWriteUint32(clientId);
376 doWriteUint32(sinkId);
377 }
378
379 void SerializedScriptValueWriter::writeTransferredSharedArrayBuffer(
380 uint32_t index) {
381 ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
382 append(SharedArrayBufferTransferTag);
383 doWriteUint32(index);
384 }
385
386 void SerializedScriptValueWriter::writeObjectReference(uint32_t reference) {
387 append(ObjectReferenceTag);
388 doWriteUint32(reference);
389 }
390
391 void SerializedScriptValueWriter::writeObject(uint32_t numProperties) {
392 append(ObjectTag);
393 doWriteUint32(numProperties);
394 }
395
396 void SerializedScriptValueWriter::writeSparseArray(uint32_t numProperties,
397 uint32_t length) {
398 append(SparseArrayTag);
399 doWriteUint32(numProperties);
400 doWriteUint32(length);
401 }
402
403 void SerializedScriptValueWriter::writeDenseArray(uint32_t numProperties,
404 uint32_t length) {
405 append(DenseArrayTag);
406 doWriteUint32(numProperties);
407 doWriteUint32(length);
408 }
409
410 String SerializedScriptValueWriter::takeWireString() {
411 static_assert(sizeof(BufferValueType) == 2,
412 "BufferValueType should be 2 bytes");
413 fillHole();
414 ASSERT((m_position + 1) / sizeof(BufferValueType) <= m_buffer.size());
415 return String(m_buffer.data(), (m_position + 1) / sizeof(BufferValueType));
416 }
417
418 void SerializedScriptValueWriter::writeReferenceCount(
419 uint32_t numberOfReferences) {
420 append(ReferenceCountTag);
421 doWriteUint32(numberOfReferences);
422 }
423
424 void SerializedScriptValueWriter::writeGenerateFreshObject() {
425 append(GenerateFreshObjectTag);
426 }
427
428 void SerializedScriptValueWriter::writeGenerateFreshSparseArray(
429 uint32_t length) {
430 append(GenerateFreshSparseArrayTag);
431 doWriteUint32(length);
432 }
433
434 void SerializedScriptValueWriter::writeGenerateFreshDenseArray(
435 uint32_t length) {
436 append(GenerateFreshDenseArrayTag);
437 doWriteUint32(length);
438 }
439
440 void SerializedScriptValueWriter::writeGenerateFreshMap() {
441 append(GenerateFreshMapTag);
442 }
443
444 void SerializedScriptValueWriter::writeGenerateFreshSet() {
445 append(GenerateFreshSetTag);
446 }
447
448 void SerializedScriptValueWriter::writeMap(uint32_t length) {
449 append(MapTag);
450 doWriteUint32(length);
451 }
452
453 void SerializedScriptValueWriter::writeSet(uint32_t length) {
454 append(SetTag);
455 doWriteUint32(length);
456 }
457
458 void SerializedScriptValueWriter::doWriteFile(const File& file) {
459 doWriteWebCoreString(file.hasBackingFile() ? file.path() : "");
460 doWriteWebCoreString(file.name());
461 doWriteWebCoreString(file.webkitRelativePath());
462 doWriteWebCoreString(file.uuid());
463 doWriteWebCoreString(file.type());
464
465 // FIXME don't use 1 byte to encode a flag.
466 if (file.hasValidSnapshotMetadata()) {
467 doWriteUint32(static_cast<uint8_t>(1));
468
469 long long size;
470 double lastModifiedMS;
471 file.captureSnapshot(size, lastModifiedMS);
472 doWriteUint64(static_cast<uint64_t>(size));
473 doWriteNumber(lastModifiedMS);
474 } else {
475 doWriteUint32(static_cast<uint8_t>(0));
476 }
477
478 doWriteUint32(static_cast<uint8_t>(
479 (file.getUserVisibility() == File::IsUserVisible) ? 1 : 0));
480 }
481
482 void SerializedScriptValueWriter::doWriteArrayBuffer(
483 const DOMArrayBuffer& arrayBuffer) {
484 uint32_t byteLength = arrayBuffer.byteLength();
485 doWriteUint32(byteLength);
486 append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
487 }
488
489 void SerializedScriptValueWriter::doWriteString(const char* data, int length) {
490 doWriteUint32(static_cast<uint32_t>(length));
491 append(reinterpret_cast<const uint8_t*>(data), length);
492 }
493
494 void SerializedScriptValueWriter::doWriteWebCoreString(const String& string) {
495 StringUTF8Adaptor stringUTF8(string);
496 doWriteString(stringUTF8.data(), stringUTF8.length());
497 }
498
499 int SerializedScriptValueWriter::bytesNeededToWireEncode(uint32_t value) {
500 int bytes = 1;
501 while (true) {
502 value >>= SerializedScriptValue::varIntShift;
503 if (!value)
504 break;
505 ++bytes;
506 }
507
508 return bytes;
509 }
510
511 void SerializedScriptValueWriter::doWriteUint32(uint32_t value) {
512 doWriteUintHelper(value);
513 }
514
515 void SerializedScriptValueWriter::doWriteUint64(uint64_t value) {
516 doWriteUintHelper(value);
517 }
518
519 void SerializedScriptValueWriter::doWriteNumber(double number) {
520 append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
521 }
522
523 void SerializedScriptValueWriter::append(SerializationTag tag) {
524 append(static_cast<uint8_t>(tag));
525 }
526
527 void SerializedScriptValueWriter::append(uint8_t b) {
528 ensureSpace(1);
529 *byteAt(m_position++) = b;
530 }
531
532 void SerializedScriptValueWriter::append(const uint8_t* data, int length) {
533 ensureSpace(length);
534 memcpy(byteAt(m_position), data, length);
535 m_position += length;
536 }
537
538 void SerializedScriptValueWriter::ensureSpace(unsigned extra) {
539 static_assert(sizeof(BufferValueType) == 2,
540 "BufferValueType should be 2 bytes");
541 m_buffer.resize((m_position + extra + 1) /
542 sizeof(BufferValueType)); // "+ 1" to round up.
543 }
544
545 void SerializedScriptValueWriter::fillHole() {
546 static_assert(sizeof(BufferValueType) == 2,
547 "BufferValueType should be 2 bytes");
548 // If the writer is at odd position in the buffer, then one of
549 // the bytes in the last UChar is not initialized.
550 if (m_position % 2)
551 *byteAt(m_position) = static_cast<uint8_t>(PaddingTag);
552 }
553
554 uint8_t* SerializedScriptValueWriter::byteAt(int position) {
555 return reinterpret_cast<uint8_t*>(m_buffer.data()) + position;
556 }
557
558 int SerializedScriptValueWriter::v8StringWriteOptions() {
559 return v8::String::NO_NULL_TERMINATION;
560 }
561
562 ScriptValueSerializer::StateBase*
563 ScriptValueSerializer::AbstractObjectState::serializeProperties(
564 ScriptValueSerializer& serializer) {
565 while (m_index < m_propertyNames->Length()) {
566 v8::Local<v8::Value> propertyName;
567 if (!m_propertyNames->Get(serializer.context(), m_index)
568 .ToLocal(&propertyName))
569 return serializer.handleError(
570 Status::JSException,
571 "Failed to get a property while cloning an object.", this);
572
573 bool hasProperty = false;
574 if (propertyName->IsString()) {
575 hasProperty = v8CallBoolean(composite()->HasRealNamedProperty(
576 serializer.context(), propertyName.As<v8::String>()));
577 } else if (propertyName->IsUint32()) {
578 hasProperty = v8CallBoolean(composite()->HasRealIndexedProperty(
579 serializer.context(), propertyName.As<v8::Uint32>()->Value()));
580 }
581 if (StateBase* newState = serializer.checkException(this))
582 return newState;
583 if (!hasProperty) {
584 ++m_index;
585 continue;
586 }
587
588 // |propertyName| is v8::String or v8::Uint32, so its serialization cannot
589 // be recursive.
590 serializer.doSerialize(propertyName, nullptr);
591
592 v8::Local<v8::Value> value;
593 if (!composite()->Get(serializer.context(), propertyName).ToLocal(&value))
594 return serializer.handleError(
595 Status::JSException,
596 "Failed to get a property while cloning an object.", this);
597 ++m_index;
598 ++m_numSerializedProperties;
599 // If we return early here, it's either because we have pushed a new state
600 // onto the serialization state stack or because we have encountered an
601 // error (and in both cases we are unwinding the native stack).
602 if (StateBase* newState = serializer.doSerialize(value, this))
603 return newState;
604 }
605 return objectDone(m_numSerializedProperties, serializer);
606 }
607
608 ScriptValueSerializer::StateBase* ScriptValueSerializer::ObjectState::advance(
609 ScriptValueSerializer& serializer) {
610 if (m_propertyNames.IsEmpty()) {
611 if (!composite()
612 ->GetOwnPropertyNames(serializer.context())
613 .ToLocal(&m_propertyNames))
614 return serializer.checkException(this);
615 }
616 return serializeProperties(serializer);
617 }
618
619 ScriptValueSerializer::StateBase*
620 ScriptValueSerializer::ObjectState::objectDone(
621 unsigned numProperties,
622 ScriptValueSerializer& serializer) {
623 return serializer.writeObject(numProperties, this);
624 }
625
626 ScriptValueSerializer::StateBase*
627 ScriptValueSerializer::DenseArrayState::advance(
628 ScriptValueSerializer& serializer) {
629 while (m_arrayIndex < m_arrayLength) {
630 v8::Local<v8::Value> value;
631 if (!composite()
632 .As<v8::Array>()
633 ->Get(serializer.context(), m_arrayIndex)
634 .ToLocal(&value))
635 return serializer.handleError(
636 Status::JSException,
637 "Failed to get an element while cloning an array.", this);
638 m_arrayIndex++;
639 if (StateBase* newState = serializer.checkException(this))
640 return newState;
641 if (StateBase* newState = serializer.doSerialize(value, this))
642 return newState;
643 }
644 return serializeProperties(serializer);
645 }
646
647 ScriptValueSerializer::StateBase*
648 ScriptValueSerializer::DenseArrayState::objectDone(
649 unsigned numProperties,
650 ScriptValueSerializer& serializer) {
651 return serializer.writeDenseArray(numProperties, m_arrayLength, this);
652 }
653
654 ScriptValueSerializer::StateBase*
655 ScriptValueSerializer::SparseArrayState::advance(
656 ScriptValueSerializer& serializer) {
657 return serializeProperties(serializer);
658 }
659
660 ScriptValueSerializer::StateBase*
661 ScriptValueSerializer::SparseArrayState::objectDone(
662 unsigned numProperties,
663 ScriptValueSerializer& serializer) {
664 return serializer.writeSparseArray(
665 numProperties, composite().As<v8::Array>()->Length(), this);
666 }
667
668 template <typename T>
669 ScriptValueSerializer::StateBase*
670 ScriptValueSerializer::CollectionState<T>::advance(
671 ScriptValueSerializer& serializer) {
672 while (m_index < m_length) {
673 v8::Local<v8::Value> value;
674 if (!m_entries->Get(serializer.context(), m_index).ToLocal(&value))
675 return serializer.handleError(
676 Status::JSException,
677 "Failed to get an element while cloning a collection.", this);
678 m_index++;
679 if (StateBase* newState = serializer.checkException(this))
680 return newState;
681 if (StateBase* newState = serializer.doSerialize(value, this))
682 return newState;
683 }
684 return serializer.writeCollection<T>(m_length, this);
685 }
686
687 ScriptValueSerializer::ScriptValueSerializer(
688 SerializedScriptValueWriter& writer,
689 WebBlobInfoArray* blobInfo,
690 ScriptState* scriptState)
691 : m_scriptState(scriptState),
692 m_writer(writer),
693 m_tryCatch(scriptState->isolate()),
694 m_depth(0),
695 m_status(Status::Success),
696 m_nextObjectReference(0),
697 m_blobInfo(blobInfo),
698 m_blobDataHandles(nullptr) {
699 DCHECK(!m_tryCatch.HasCaught());
700 }
701
702 void ScriptValueSerializer::copyTransferables(
703 const Transferables& transferables) {
704 v8::Local<v8::Object> creationContext = m_scriptState->context()->Global();
705
706 // Also kept in separate ObjectPools, iterate and copy the contents
707 // of each kind of transferable vector.
708
709 const auto& messagePorts = transferables.messagePorts;
710 for (size_t i = 0; i < messagePorts.size(); ++i) {
711 v8::Local<v8::Object> v8MessagePort =
712 ToV8(messagePorts[i].get(), creationContext, isolate())
713 .As<v8::Object>();
714 m_transferredMessagePorts.set(v8MessagePort, i);
715 }
716
717 const auto& arrayBuffers = transferables.arrayBuffers;
718 for (size_t i = 0; i < arrayBuffers.size(); ++i) {
719 v8::Local<v8::Object> v8ArrayBuffer =
720 ToV8(arrayBuffers[i].get(), creationContext, isolate())
721 .As<v8::Object>();
722 // Coalesce multiple occurences of the same buffer to the first index.
723 if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
724 m_transferredArrayBuffers.set(v8ArrayBuffer, i);
725 }
726
727 const auto& imageBitmaps = transferables.imageBitmaps;
728 for (size_t i = 0; i < imageBitmaps.size(); ++i) {
729 v8::Local<v8::Object> v8ImageBitmap =
730 ToV8(imageBitmaps[i].get(), creationContext, isolate())
731 .As<v8::Object>();
732 if (!m_transferredImageBitmaps.contains(v8ImageBitmap))
733 m_transferredImageBitmaps.set(v8ImageBitmap, i);
734 }
735
736 const auto& offscreenCanvases = transferables.offscreenCanvases;
737 for (size_t i = 0; i < offscreenCanvases.size(); ++i) {
738 v8::Local<v8::Object> v8OffscreenCanvas =
739 ToV8(offscreenCanvases[i].get(), creationContext, isolate())
740 .As<v8::Object>();
741 if (!m_transferredOffscreenCanvas.contains(v8OffscreenCanvas))
742 m_transferredOffscreenCanvas.set(v8OffscreenCanvas, i);
743 }
744 }
745
746 PassRefPtr<SerializedScriptValue> ScriptValueSerializer::serialize(
747 v8::Local<v8::Value> value,
748 Transferables* transferables,
749 ExceptionState& exceptionState) {
750 DCHECK(!m_blobDataHandles);
751
752 RefPtr<SerializedScriptValue> serializedValue =
753 SerializedScriptValue::create();
754
755 m_blobDataHandles = &serializedValue->blobDataHandles();
756 if (transferables)
757 copyTransferables(*transferables);
758
759 v8::HandleScope scope(isolate());
760 writer().writeVersion();
761 StateBase* state = doSerialize(value, nullptr);
762 while (state)
763 state = state->advance(*this);
764
765 switch (m_status) {
766 case Status::Success:
767 transferData(transferables, exceptionState, serializedValue.get());
768 break;
769 case Status::InputError:
770 case Status::DataCloneError:
771 exceptionState.throwDOMException(blink::DataCloneError, m_errorMessage);
772 break;
773 case Status::JSException:
774 exceptionState.rethrowV8Exception(m_tryCatch.Exception());
775 break;
776 default:
777 NOTREACHED();
778 }
779
780 return serializedValue.release();
781 }
782
783 void ScriptValueSerializer::transferData(
784 Transferables* transferables,
785 ExceptionState& exceptionState,
786 SerializedScriptValue* serializedValue) {
787 serializedValue->setData(m_writer.takeWireString());
788 DCHECK(serializedValue->dataHasOneRef());
789 if (!transferables)
790 return;
791
792 serializedValue->transferImageBitmaps(isolate(), transferables->imageBitmaps,
793 exceptionState);
794 if (exceptionState.hadException())
795 return;
796 serializedValue->transferArrayBuffers(isolate(), transferables->arrayBuffers,
797 exceptionState);
798 if (exceptionState.hadException())
799 return;
800 serializedValue->transferOffscreenCanvas(
801 isolate(), transferables->offscreenCanvases, exceptionState);
802 }
803
804 ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerialize(
805 v8::Local<v8::Value> value,
806 StateBase* next) {
807 m_writer.writeReferenceCount(m_nextObjectReference);
808
809 if (value.IsEmpty())
810 return handleError(Status::InputError,
811 "The empty property cannot be cloned.", next);
812
813 uint32_t objectReference;
814 if ((value->IsObject() || value->IsDate() || value->IsRegExp()) &&
815 m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
816 // Note that IsObject() also detects wrappers (eg, it will catch the things
817 // that we grey and write below).
818 ASSERT(!value->IsString());
819 m_writer.writeObjectReference(objectReference);
820 return nullptr;
821 }
822 if (value->IsObject())
823 return doSerializeObject(value.As<v8::Object>(), next);
824
825 if (value->IsUndefined()) {
826 m_writer.writeUndefined();
827 } else if (value->IsNull()) {
828 m_writer.writeNull();
829 } else if (value->IsTrue()) {
830 m_writer.writeTrue();
831 } else if (value->IsFalse()) {
832 m_writer.writeFalse();
833 } else if (value->IsInt32()) {
834 m_writer.writeInt32(value.As<v8::Int32>()->Value());
835 } else if (value->IsUint32()) {
836 m_writer.writeUint32(value.As<v8::Uint32>()->Value());
837 } else if (value->IsNumber()) {
838 m_writer.writeNumber(value.As<v8::Number>()->Value());
839 } else if (value->IsString()) {
840 writeString(value);
841 } else {
842 return handleError(Status::DataCloneError, "A value could not be cloned.",
843 next);
844 }
845 return nullptr;
846 }
847
848 ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerializeObject(
849 v8::Local<v8::Object> object,
850 StateBase* next) {
851 DCHECK(!object.IsEmpty());
852
853 if (object->IsArrayBufferView()) {
854 return writeAndGreyArrayBufferView(object, next);
855 }
856 if (object->IsArrayBuffer()) {
857 return writeAndGreyArrayBuffer(object, next);
858 }
859 if (object->IsSharedArrayBuffer()) {
860 uint32_t index;
861 if (!m_transferredArrayBuffers.tryGet(object, &index)) {
862 return handleError(Status::DataCloneError,
863 "A SharedArrayBuffer could not be cloned.", next);
864 }
865 return writeTransferredSharedArrayBuffer(object, index, next);
866 }
867
868 if (object->IsWebAssemblyCompiledModule())
869 return writeWasmCompiledModule(object, next);
870
871 // Transferable only objects
872 if (V8MessagePort::hasInstance(object, isolate())) {
873 uint32_t index;
874 if (!m_transferredMessagePorts.tryGet(object, &index)) {
875 return handleError(Status::DataCloneError,
876 "A MessagePort could not be cloned.", next);
877 }
878 m_writer.writeTransferredMessagePort(index);
879 return nullptr;
880 }
881 if (V8OffscreenCanvas::hasInstance(object, isolate())) {
882 uint32_t index;
883 if (!m_transferredOffscreenCanvas.tryGet(object, &index)) {
884 return handleError(Status::DataCloneError,
885 "A OffscreenCanvas could not be cloned.", next);
886 }
887 return writeTransferredOffscreenCanvas(object, next);
888 }
889 if (V8ImageBitmap::hasInstance(object, isolate())) {
890 return writeAndGreyImageBitmap(object, next);
891 }
892
893 greyObject(object);
894
895 if (object->IsDate()) {
896 m_writer.writeDate(object.As<v8::Date>()->ValueOf());
897 return nullptr;
898 }
899 if (object->IsStringObject()) {
900 writeStringObject(object);
901 return nullptr;
902 }
903 if (object->IsNumberObject()) {
904 writeNumberObject(object);
905 return nullptr;
906 }
907 if (object->IsBooleanObject()) {
908 writeBooleanObject(object);
909 return nullptr;
910 }
911 if (object->IsArray()) {
912 return startArrayState(object.As<v8::Array>(), next);
913 }
914 if (object->IsMap()) {
915 return startMapState(object.As<v8::Map>(), next);
916 }
917 if (object->IsSet()) {
918 return startSetState(object.As<v8::Set>(), next);
919 }
920
921 if (V8File::hasInstance(object, isolate())) {
922 return writeFile(object, next);
923 }
924 if (V8Blob::hasInstance(object, isolate())) {
925 return writeBlob(object, next);
926 }
927 if (V8FileList::hasInstance(object, isolate())) {
928 return writeFileList(object, next);
929 }
930 if (V8ImageData::hasInstance(object, isolate())) {
931 writeImageData(object);
932 return nullptr;
933 }
934 if (object->IsRegExp()) {
935 writeRegExp(object);
936 return nullptr;
937 }
938 if (V8CompositorProxy::hasInstance(object, isolate())) {
939 return writeCompositorProxy(object, next);
940 }
941
942 // Since IsNativeError is expensive, this check should always be the last
943 // check.
944 if (isHostObject(object) || object->IsCallable() || object->IsNativeError()) {
945 return handleError(Status::DataCloneError, "An object could not be cloned.",
946 next);
947 }
948
949 return startObjectState(object, next);
950 }
951
952 ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerializeArrayBuffer(
953 v8::Local<v8::Value> arrayBuffer,
954 StateBase* next) {
955 return doSerialize(arrayBuffer, next);
956 }
957
958 ScriptValueSerializer::StateBase* ScriptValueSerializer::checkException(
959 StateBase* state) {
960 return m_tryCatch.HasCaught() ? handleError(Status::JSException, "", state)
961 : nullptr;
962 }
963
964 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeObject(
965 uint32_t numProperties,
966 StateBase* state) {
967 m_writer.writeObject(numProperties);
968 return pop(state);
969 }
970
971 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeSparseArray(
972 uint32_t numProperties,
973 uint32_t length,
974 StateBase* state) {
975 m_writer.writeSparseArray(numProperties, length);
976 return pop(state);
977 }
978
979 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeDenseArray(
980 uint32_t numProperties,
981 uint32_t length,
982 StateBase* state) {
983 m_writer.writeDenseArray(numProperties, length);
984 return pop(state);
985 }
986
987 template <>
988 ScriptValueSerializer::StateBase*
989 ScriptValueSerializer::writeCollection<v8::Map>(uint32_t length,
990 StateBase* state) {
991 m_writer.writeMap(length);
992 return pop(state);
993 }
994
995 template <>
996 ScriptValueSerializer::StateBase*
997 ScriptValueSerializer::writeCollection<v8::Set>(uint32_t length,
998 StateBase* state) {
999 m_writer.writeSet(length);
1000 return pop(state);
1001 }
1002
1003 ScriptValueSerializer::StateBase* ScriptValueSerializer::handleError(
1004 ScriptValueSerializer::Status errorStatus,
1005 const String& message,
1006 StateBase* state) {
1007 DCHECK(errorStatus != Status::Success);
1008 m_status = errorStatus;
1009 m_errorMessage = message;
1010 while (state) {
1011 state = pop(state);
1012 }
1013 return new ErrorState;
1014 }
1015
1016 bool ScriptValueSerializer::checkComposite(StateBase* top) {
1017 ASSERT(top);
1018 if (m_depth > maxDepth)
1019 return false;
1020 if (!shouldCheckForCycles(m_depth))
1021 return true;
1022 v8::Local<v8::Value> composite = top->composite();
1023 for (StateBase* state = top->nextState(); state; state = state->nextState()) {
1024 if (state->composite() == composite)
1025 return false;
1026 }
1027 return true;
1028 }
1029
1030 void ScriptValueSerializer::writeString(v8::Local<v8::Value> value) {
1031 v8::Local<v8::String> string = value.As<v8::String>();
1032 if (!string->Length() || string->IsOneByte())
1033 m_writer.writeOneByteString(string);
1034 else
1035 m_writer.writeUCharString(string);
1036 }
1037
1038 void ScriptValueSerializer::writeStringObject(v8::Local<v8::Value> value) {
1039 v8::Local<v8::StringObject> stringObject = value.As<v8::StringObject>();
1040 v8::String::Utf8Value stringValue(stringObject->ValueOf());
1041 m_writer.writeStringObject(*stringValue, stringValue.length());
1042 }
1043
1044 void ScriptValueSerializer::writeNumberObject(v8::Local<v8::Value> value) {
1045 v8::Local<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
1046 m_writer.writeNumberObject(numberObject->ValueOf());
1047 }
1048
1049 void ScriptValueSerializer::writeBooleanObject(v8::Local<v8::Value> value) {
1050 v8::Local<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
1051 m_writer.writeBooleanObject(booleanObject->ValueOf());
1052 }
1053
1054 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeBlob(
1055 v8::Local<v8::Value> value,
1056 StateBase* next) {
1057 Blob* blob = V8Blob::toImpl(value.As<v8::Object>());
1058 if (!blob)
1059 return nullptr;
1060 if (blob->isClosed())
1061 return handleError(
1062 Status::DataCloneError,
1063 "A Blob object has been closed, and could therefore not be cloned.",
1064 next);
1065 int blobIndex = -1;
1066 m_blobDataHandles->set(blob->uuid(), blob->blobDataHandle());
1067 if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex))
1068 m_writer.writeBlobIndex(blobIndex);
1069 else
1070 m_writer.writeBlob(blob->uuid(), blob->type(), blob->size());
1071 return nullptr;
1072 }
1073
1074 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeCompositorProxy(
1075 v8::Local<v8::Value> value,
1076 StateBase* next) {
1077 CompositorProxy* compositorProxy =
1078 V8CompositorProxy::toImpl(value.As<v8::Object>());
1079 if (!compositorProxy)
1080 return nullptr;
1081 if (!compositorProxy->connected())
1082 return handleError(Status::DataCloneError,
1083 "A CompositorProxy object has been disconnected, and "
1084 "could therefore not be cloned.",
1085 next);
1086 m_writer.writeCompositorProxy(*compositorProxy);
1087 return nullptr;
1088 }
1089
1090 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeFile(
1091 v8::Local<v8::Value> value,
1092 StateBase* next) {
1093 File* file = V8File::toImpl(value.As<v8::Object>());
1094 if (!file)
1095 return nullptr;
1096 if (file->isClosed())
1097 return handleError(
1098 Status::DataCloneError,
1099 "A File object has been closed, and could therefore not be cloned.",
1100 next);
1101 int blobIndex = -1;
1102 m_blobDataHandles->set(file->uuid(), file->blobDataHandle());
1103 if (appendFileInfo(file, &blobIndex)) {
1104 ASSERT(blobIndex >= 0);
1105 m_writer.writeFileIndex(blobIndex);
1106 } else {
1107 m_writer.writeFile(*file);
1108 }
1109 return nullptr;
1110 }
1111
1112 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeFileList(
1113 v8::Local<v8::Value> value,
1114 StateBase* next) {
1115 FileList* fileList = V8FileList::toImpl(value.As<v8::Object>());
1116 if (!fileList)
1117 return nullptr;
1118 unsigned length = fileList->length();
1119 Vector<int> blobIndices;
1120 for (unsigned i = 0; i < length; ++i) {
1121 int blobIndex = -1;
1122 const File* file = fileList->item(i);
1123 if (file->isClosed())
1124 return handleError(
1125 Status::DataCloneError,
1126 "A File object has been closed, and could therefore not be cloned.",
1127 next);
1128 m_blobDataHandles->set(file->uuid(), file->blobDataHandle());
1129 if (appendFileInfo(file, &blobIndex)) {
1130 ASSERT(!i || blobIndex > 0);
1131 ASSERT(blobIndex >= 0);
1132 blobIndices.push_back(blobIndex);
1133 }
1134 }
1135 if (!blobIndices.isEmpty())
1136 m_writer.writeFileListIndex(blobIndices);
1137 else
1138 m_writer.writeFileList(*fileList);
1139 return nullptr;
1140 }
1141
1142 void ScriptValueSerializer::writeImageData(v8::Local<v8::Value> value) {
1143 ImageData* imageData = V8ImageData::toImpl(value.As<v8::Object>());
1144 if (!imageData)
1145 return;
1146 DOMUint8ClampedArray* pixelArray = imageData->data();
1147 m_writer.writeImageData(imageData->width(), imageData->height(),
1148 pixelArray->data(), pixelArray->length());
1149 }
1150
1151 ScriptValueSerializer::StateBase*
1152 ScriptValueSerializer::writeAndGreyImageBitmap(v8::Local<v8::Object> object,
1153 StateBase* next) {
1154 ImageBitmap* imageBitmap = V8ImageBitmap::toImpl(object);
1155 if (!imageBitmap)
1156 return nullptr;
1157 if (imageBitmap->isNeutered())
1158 return handleError(Status::DataCloneError,
1159 "An ImageBitmap is detached and could not be cloned.",
1160 next);
1161
1162 uint32_t index;
1163 if (m_transferredImageBitmaps.tryGet(object, &index)) {
1164 m_writer.writeTransferredImageBitmap(index);
1165 } else {
1166 greyObject(object);
1167 RefPtr<Uint8Array> pixelData = imageBitmap->copyBitmapData(
1168 imageBitmap->isPremultiplied() ? PremultiplyAlpha
1169 : DontPremultiplyAlpha,
1170 N32ColorType);
1171 m_writer.writeImageBitmap(
1172 imageBitmap->width(), imageBitmap->height(),
1173 static_cast<uint32_t>(imageBitmap->originClean()),
1174 static_cast<uint32_t>(imageBitmap->isPremultiplied()),
1175 pixelData->data(), imageBitmap->width() * imageBitmap->height() * 4);
1176 }
1177 return nullptr;
1178 }
1179
1180 void ScriptValueSerializer::writeRegExp(v8::Local<v8::Value> value) {
1181 v8::Local<v8::RegExp> regExp = value.As<v8::RegExp>();
1182 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
1183 }
1184
1185 ScriptValueSerializer::StateBase*
1186 ScriptValueSerializer::writeAndGreyArrayBufferView(v8::Local<v8::Object> object,
1187 StateBase* next) {
1188 ASSERT(!object.IsEmpty());
1189 DOMArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object);
1190 if (!arrayBufferView)
1191 return nullptr;
1192 if (!arrayBufferView->bufferBase())
1193 return handleError(Status::DataCloneError,
1194 "An ArrayBuffer could not be cloned.", next);
1195 v8::Local<v8::Value> underlyingBuffer =
1196 ToV8(arrayBufferView->bufferBase(), m_scriptState->context()->Global(),
1197 isolate());
1198 if (underlyingBuffer.IsEmpty())
1199 return handleError(Status::DataCloneError,
1200 "An ArrayBuffer could not be cloned.", next);
1201 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
1202 if (stateOut)
1203 return stateOut;
1204 m_writer.writeArrayBufferView(*arrayBufferView);
1205 // This should be safe: we serialize something that we know to be a wrapper
1206 // (see the toV8 call above), so the call to doSerializeArrayBuffer should
1207 // neither cause the system stack to overflow nor should it have potential to
1208 // reach this ArrayBufferView again.
1209 //
1210 // We do need to grey the underlying buffer before we grey its view, however;
1211 // ArrayBuffers may be shared, so they need to be given reference IDs, and an
1212 // ArrayBufferView cannot be constructed without a corresponding ArrayBuffer
1213 // (or without an additional tag that would allow us to do two-stage
1214 // construction like we do for Objects and Arrays).
1215 greyObject(object);
1216 return nullptr;
1217 }
1218
1219 ScriptValueSerializer::StateBase*
1220 ScriptValueSerializer::writeWasmCompiledModule(v8::Local<v8::Object> object,
1221 StateBase* next) {
1222 CHECK(RuntimeEnabledFeatures::webAssemblySerializationEnabled());
1223 // TODO (mtrofin): explore mechanism avoiding data copying / buffer resizing.
1224 v8::Local<v8::WasmCompiledModule> wasmModule =
1225 object.As<v8::WasmCompiledModule>();
1226 v8::Local<v8::String> wireBytes = wasmModule->GetWasmWireBytes();
1227 DCHECK(wireBytes->IsOneByte());
1228
1229 v8::WasmCompiledModule::SerializedModule data = wasmModule->Serialize();
1230 m_writer.append(WasmModuleTag);
1231 uint32_t wireBytesLength = static_cast<uint32_t>(wireBytes->Length());
1232 // We place a tag so we may evolve the format in which we store the
1233 // wire bytes. We plan to move them to a blob.
1234 // We want to control how we write the string, though, so we explicitly
1235 // call writeRawStringBytes.
1236 m_writer.append(RawBytesTag);
1237 m_writer.doWriteUint32(wireBytesLength);
1238 m_writer.ensureSpace(wireBytesLength);
1239 m_writer.writeRawStringBytes(wireBytes);
1240 m_writer.doWriteUint32(static_cast<uint32_t>(data.second));
1241 m_writer.append(data.first.get(), static_cast<int>(data.second));
1242 return nullptr;
1243 }
1244
1245 ScriptValueSerializer::StateBase*
1246 ScriptValueSerializer::writeAndGreyArrayBuffer(v8::Local<v8::Object> object,
1247 StateBase* next) {
1248 DOMArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(object);
1249 if (!arrayBuffer)
1250 return nullptr;
1251 if (arrayBuffer->isNeutered())
1252 return handleError(Status::DataCloneError,
1253 "An ArrayBuffer is neutered and could not be cloned.",
1254 next);
1255
1256 uint32_t index;
1257 if (m_transferredArrayBuffers.tryGet(object, &index)) {
1258 m_writer.writeTransferredArrayBuffer(index);
1259 } else {
1260 greyObject(object);
1261 m_writer.writeArrayBuffer(*arrayBuffer);
1262 }
1263 return nullptr;
1264 }
1265
1266 ScriptValueSerializer::StateBase*
1267 ScriptValueSerializer::writeTransferredOffscreenCanvas(
1268 v8::Local<v8::Value> value,
1269 StateBase* next) {
1270 OffscreenCanvas* offscreenCanvas =
1271 V8OffscreenCanvas::toImpl(value.As<v8::Object>());
1272 if (!offscreenCanvas)
1273 return nullptr;
1274 if (offscreenCanvas->isNeutered())
1275 return handleError(
1276 Status::DataCloneError,
1277 "An OffscreenCanvas is detached and could not be cloned.", next);
1278 if (offscreenCanvas->renderingContext())
1279 return handleError(Status::DataCloneError,
1280 "An OffscreenCanvas with a context could not be cloned.",
1281 next);
1282 m_writer.writeTransferredOffscreenCanvas(
1283 offscreenCanvas->width(), offscreenCanvas->height(),
1284 offscreenCanvas->placeholderCanvasId(), offscreenCanvas->clientId(),
1285 offscreenCanvas->sinkId());
1286 return nullptr;
1287 }
1288
1289 ScriptValueSerializer::StateBase*
1290 ScriptValueSerializer::writeTransferredSharedArrayBuffer(
1291 v8::Local<v8::Value> value,
1292 uint32_t index,
1293 StateBase* next) {
1294 ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
1295 DOMSharedArrayBuffer* sharedArrayBuffer =
1296 V8SharedArrayBuffer::toImpl(value.As<v8::Object>());
1297 if (!sharedArrayBuffer)
1298 return 0;
1299 m_writer.writeTransferredSharedArrayBuffer(index);
1300 return nullptr;
1301 }
1302
1303 bool ScriptValueSerializer::shouldSerializeDensely(uint32_t length,
1304 uint32_t propertyCount) {
1305 // Let K be the cost of serializing all property values that are there
1306 // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32_t
1307 // key)
1308 // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte for all
1309 // properties that are not there)
1310 // so densely is better than sparsly whenever 6*propertyCount > length
1311 return 6 * propertyCount >= length;
1312 }
1313
1314 ScriptValueSerializer::StateBase* ScriptValueSerializer::startArrayState(
1315 v8::Local<v8::Array> array,
1316 StateBase* next) {
1317 v8::Local<v8::Array> propertyNames;
1318 if (!array->GetOwnPropertyNames(context()).ToLocal(&propertyNames))
1319 return checkException(next);
1320 uint32_t length = array->Length();
1321
1322 if (shouldSerializeDensely(length, propertyNames->Length())) {
1323 // In serializing a dense array, indexed properties are ignored, so we get
1324 // non indexed own property names here.
1325 if (!array
1326 ->GetPropertyNames(context(),
1327 v8::KeyCollectionMode::kIncludePrototypes,
1328 static_cast<v8::PropertyFilter>(
1329 v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS),
1330 v8::IndexFilter::kSkipIndices)
1331 .ToLocal(&propertyNames))
1332 return checkException(next);
1333
1334 m_writer.writeGenerateFreshDenseArray(length);
1335 return push(new DenseArrayState(array, propertyNames, next, isolate()));
1336 }
1337
1338 m_writer.writeGenerateFreshSparseArray(length);
1339 return push(new SparseArrayState(array, propertyNames, next, isolate()));
1340 }
1341
1342 ScriptValueSerializer::StateBase* ScriptValueSerializer::startMapState(
1343 v8::Local<v8::Map> map,
1344 StateBase* next) {
1345 m_writer.writeGenerateFreshMap();
1346 return push(new MapState(map, next));
1347 }
1348
1349 ScriptValueSerializer::StateBase* ScriptValueSerializer::startSetState(
1350 v8::Local<v8::Set> set,
1351 StateBase* next) {
1352 m_writer.writeGenerateFreshSet();
1353 return push(new SetState(set, next));
1354 }
1355
1356 ScriptValueSerializer::StateBase* ScriptValueSerializer::startObjectState(
1357 v8::Local<v8::Object> object,
1358 StateBase* next) {
1359 m_writer.writeGenerateFreshObject();
1360 // FIXME: check not a wrapper
1361 return push(new ObjectState(object, next));
1362 }
1363
1364 // Marks object as having been visited by the serializer and assigns it a unique
1365 // object reference ID. An object may only be greyed once.
1366 void ScriptValueSerializer::greyObject(const v8::Local<v8::Object>& object) {
1367 ASSERT(!m_objectPool.contains(object));
1368 uint32_t objectReference = m_nextObjectReference++;
1369 m_objectPool.set(object, objectReference);
1370 }
1371
1372 bool ScriptValueSerializer::appendBlobInfo(const String& uuid,
1373 const String& type,
1374 unsigned long long size,
1375 int* index) {
1376 if (!m_blobInfo)
1377 return false;
1378 *index = m_blobInfo->size();
1379 m_blobInfo->push_back(WebBlobInfo(uuid, type, size));
1380 return true;
1381 }
1382
1383 bool ScriptValueSerializer::appendFileInfo(const File* file, int* index) {
1384 if (!m_blobInfo)
1385 return false;
1386
1387 long long size = -1;
1388 double lastModifiedMS = invalidFileTime();
1389 file->captureSnapshot(size, lastModifiedMS);
1390 *index = m_blobInfo->size();
1391 // FIXME: transition WebBlobInfo.lastModified to be milliseconds-based also.
1392 double lastModified = lastModifiedMS / msPerSecond;
1393 m_blobInfo->push_back(WebBlobInfo(file->uuid(), file->path(), file->name(),
1394 file->type(), lastModified, size));
1395 return true;
1396 }
1397
1398 bool SerializedScriptValueReader::read(v8::Local<v8::Value>* value,
1399 ScriptValueDeserializer& deserializer) {
1400 SerializationTag tag;
1401 if (!readTag(&tag))
1402 return false;
1403 return readWithTag(tag, value, deserializer);
1404 }
1405
1406 bool SerializedScriptValueReader::readWithTag(
1407 SerializationTag tag,
1408 v8::Local<v8::Value>* value,
1409 ScriptValueDeserializer& deserializer) {
1410 switch (tag) {
1411 case ReferenceCountTag: {
1412 if (!m_version)
1413 return false;
1414 uint32_t referenceTableSize;
1415 if (!doReadUint32(&referenceTableSize))
1416 return false;
1417 // If this test fails, then the serializer and deserializer disagree about
1418 // the assignment of object reference IDs. On the deserialization side,
1419 // this means there are too many or too few calls to pushObjectReference.
1420 if (referenceTableSize != deserializer.objectReferenceCount())
1421 return false;
1422 return true;
1423 }
1424 case InvalidTag:
1425 return false;
1426 case PaddingTag:
1427 return true;
1428 case UndefinedTag:
1429 *value = v8::Undefined(isolate());
1430 break;
1431 case NullTag:
1432 *value = v8::Null(isolate());
1433 break;
1434 case TrueTag:
1435 *value = v8Boolean(true, isolate());
1436 break;
1437 case FalseTag:
1438 *value = v8Boolean(false, isolate());
1439 break;
1440 case TrueObjectTag:
1441 *value = v8::BooleanObject::New(isolate(), true);
1442 deserializer.pushObjectReference(*value);
1443 break;
1444 case FalseObjectTag:
1445 *value = v8::BooleanObject::New(isolate(), false);
1446 deserializer.pushObjectReference(*value);
1447 break;
1448 case StringTag:
1449 if (!readString(value))
1450 return false;
1451 break;
1452 case StringUCharTag:
1453 if (!readUCharString(value))
1454 return false;
1455 break;
1456 case StringObjectTag:
1457 if (!readStringObject(value))
1458 return false;
1459 deserializer.pushObjectReference(*value);
1460 break;
1461 case Int32Tag:
1462 if (!readInt32(value))
1463 return false;
1464 break;
1465 case Uint32Tag:
1466 if (!readUint32(value))
1467 return false;
1468 break;
1469 case DateTag:
1470 if (!readDate(value))
1471 return false;
1472 deserializer.pushObjectReference(*value);
1473 break;
1474 case NumberTag:
1475 if (!readNumber(value))
1476 return false;
1477 break;
1478 case NumberObjectTag:
1479 if (!readNumberObject(value))
1480 return false;
1481 deserializer.pushObjectReference(*value);
1482 break;
1483 case BlobTag:
1484 case BlobIndexTag:
1485 if (!readBlob(value, tag == BlobIndexTag))
1486 return false;
1487 deserializer.pushObjectReference(*value);
1488 break;
1489 case FileTag:
1490 case FileIndexTag:
1491 if (!readFile(value, tag == FileIndexTag))
1492 return false;
1493 deserializer.pushObjectReference(*value);
1494 break;
1495 case FileListTag:
1496 case FileListIndexTag:
1497 if (!readFileList(value, tag == FileListIndexTag))
1498 return false;
1499 deserializer.pushObjectReference(*value);
1500 break;
1501 case CompositorProxyTag:
1502 if (!readCompositorProxy(value))
1503 return false;
1504 deserializer.pushObjectReference(*value);
1505 break;
1506
1507 case ImageDataTag:
1508 if (!readImageData(value))
1509 return false;
1510 deserializer.pushObjectReference(*value);
1511 break;
1512 case ImageBitmapTag:
1513 if (!readImageBitmap(value))
1514 return false;
1515 deserializer.pushObjectReference(*value);
1516 break;
1517
1518 case RegExpTag:
1519 if (!readRegExp(value))
1520 return false;
1521 deserializer.pushObjectReference(*value);
1522 break;
1523 case ObjectTag: {
1524 uint32_t numProperties;
1525 if (!doReadUint32(&numProperties))
1526 return false;
1527 if (!deserializer.completeObject(numProperties, value))
1528 return false;
1529 break;
1530 }
1531 case SparseArrayTag: {
1532 uint32_t numProperties;
1533 uint32_t length;
1534 if (!doReadUint32(&numProperties))
1535 return false;
1536 if (!doReadUint32(&length))
1537 return false;
1538 if (!deserializer.completeSparseArray(numProperties, length, value))
1539 return false;
1540 break;
1541 }
1542 case DenseArrayTag: {
1543 uint32_t numProperties;
1544 uint32_t length;
1545 if (!doReadUint32(&numProperties))
1546 return false;
1547 if (!doReadUint32(&length))
1548 return false;
1549 if (!deserializer.completeDenseArray(numProperties, length, value))
1550 return false;
1551 break;
1552 }
1553 case MapTag: {
1554 uint32_t length;
1555 if (!doReadUint32(&length))
1556 return false;
1557 if (!deserializer.completeMap(length, value))
1558 return false;
1559 break;
1560 }
1561 case SetTag: {
1562 uint32_t length;
1563 if (!doReadUint32(&length))
1564 return false;
1565 if (!deserializer.completeSet(length, value))
1566 return false;
1567 break;
1568 }
1569 case ArrayBufferViewTag: {
1570 if (!m_version)
1571 return false;
1572 if (!readArrayBufferView(value, deserializer))
1573 return false;
1574 deserializer.pushObjectReference(*value);
1575 break;
1576 }
1577 case WasmModuleTag: {
1578 if (!readWasmCompiledModule(value))
1579 return false;
1580 deserializer.pushObjectReference(*value);
1581 break;
1582 }
1583 case ArrayBufferTag: {
1584 if (!m_version)
1585 return false;
1586 if (!readArrayBuffer(value))
1587 return false;
1588 deserializer.pushObjectReference(*value);
1589 break;
1590 }
1591 case GenerateFreshObjectTag: {
1592 if (!m_version)
1593 return false;
1594 if (!deserializer.newObject())
1595 return false;
1596 return true;
1597 }
1598 case GenerateFreshSparseArrayTag: {
1599 if (!m_version)
1600 return false;
1601 uint32_t length;
1602 if (!doReadUint32(&length))
1603 return false;
1604 if (!deserializer.newSparseArray(length))
1605 return false;
1606 return true;
1607 }
1608 case GenerateFreshDenseArrayTag: {
1609 if (!m_version)
1610 return false;
1611 uint32_t length;
1612 if (!doReadUint32(&length))
1613 return false;
1614 if (!deserializer.newDenseArray(length))
1615 return false;
1616 return true;
1617 }
1618 case GenerateFreshMapTag: {
1619 if (!m_version)
1620 return false;
1621 if (!deserializer.newMap())
1622 return false;
1623 return true;
1624 }
1625 case GenerateFreshSetTag: {
1626 if (!m_version)
1627 return false;
1628 if (!deserializer.newSet())
1629 return false;
1630 return true;
1631 }
1632 case MessagePortTag: {
1633 if (!m_version)
1634 return false;
1635 uint32_t index;
1636 if (!doReadUint32(&index))
1637 return false;
1638 if (!deserializer.tryGetTransferredMessagePort(index, value))
1639 return false;
1640 break;
1641 }
1642 case ArrayBufferTransferTag: {
1643 if (!m_version)
1644 return false;
1645 uint32_t index;
1646 if (!doReadUint32(&index))
1647 return false;
1648 if (!deserializer.tryGetTransferredArrayBuffer(index, value))
1649 return false;
1650 break;
1651 }
1652 case ImageBitmapTransferTag: {
1653 if (!m_version)
1654 return false;
1655 uint32_t index;
1656 if (!doReadUint32(&index))
1657 return false;
1658 if (!deserializer.tryGetTransferredImageBitmap(index, value))
1659 return false;
1660 break;
1661 }
1662 case OffscreenCanvasTransferTag: {
1663 if (!m_version)
1664 return false;
1665 uint32_t width, height, canvasId, clientId, sinkId;
1666 if (!doReadUint32(&width))
1667 return false;
1668 if (!doReadUint32(&height))
1669 return false;
1670 if (!doReadUint32(&canvasId))
1671 return false;
1672 if (!doReadUint32(&clientId))
1673 return false;
1674 if (!doReadUint32(&sinkId))
1675 return false;
1676 if (!deserializer.tryGetTransferredOffscreenCanvas(
1677 width, height, canvasId, clientId, sinkId, value))
1678 return false;
1679 break;
1680 }
1681 case SharedArrayBufferTransferTag: {
1682 if (!m_version)
1683 return false;
1684 uint32_t index;
1685 if (!doReadUint32(&index))
1686 return false;
1687 if (!deserializer.tryGetTransferredSharedArrayBuffer(index, value))
1688 return false;
1689 break;
1690 }
1691 case ObjectReferenceTag: {
1692 if (!m_version)
1693 return false;
1694 uint32_t reference;
1695 if (!doReadUint32(&reference))
1696 return false;
1697 if (!deserializer.tryGetObjectFromObjectReference(reference, value))
1698 return false;
1699 break;
1700 }
1701 case DOMFileSystemTag:
1702 case CryptoKeyTag:
1703 ASSERT_NOT_REACHED();
1704 default:
1705 return false;
1706 }
1707 return !value->IsEmpty();
1708 }
1709
1710 bool SerializedScriptValueReader::readVersion(uint32_t& version) {
1711 SerializationTag tag;
1712 if (!readTag(&tag)) {
1713 // This is a nullary buffer. We're still version 0.
1714 version = 0;
1715 return true;
1716 }
1717 if (tag != VersionTag) {
1718 // Versions of the format past 0 start with the version tag.
1719 version = 0;
1720 // Put back the tag.
1721 undoReadTag();
1722 return true;
1723 }
1724 // Version-bearing messages are obligated to finish the version tag.
1725 return doReadUint32(&version);
1726 }
1727
1728 void SerializedScriptValueReader::setVersion(uint32_t version) {
1729 m_version = version;
1730 }
1731
1732 bool SerializedScriptValueReader::readTag(SerializationTag* tag) {
1733 if (m_position >= m_length)
1734 return false;
1735 *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
1736 return true;
1737 }
1738
1739 void SerializedScriptValueReader::undoReadTag() {
1740 if (m_position > 0)
1741 --m_position;
1742 }
1743
1744 bool SerializedScriptValueReader::readArrayBufferViewSubTag(
1745 ArrayBufferViewSubTag* tag) {
1746 if (m_position >= m_length)
1747 return false;
1748 *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]);
1749 return true;
1750 }
1751
1752 bool SerializedScriptValueReader::readString(v8::Local<v8::Value>* value) {
1753 uint32_t length;
1754 if (!doReadUint32(&length))
1755 return false;
1756 if (m_position + length > m_length)
1757 return false;
1758 *value = v8StringFromUtf8(
1759 isolate(), reinterpret_cast<const char*>(m_buffer + m_position), length);
1760 m_position += length;
1761 return true;
1762 }
1763
1764 bool SerializedScriptValueReader::readUCharString(v8::Local<v8::Value>* value) {
1765 uint32_t length;
1766 if (!doReadUint32(&length) || (length & 1))
1767 return false;
1768 if (m_position + length > m_length)
1769 return false;
1770 ASSERT(!(m_position & 1));
1771 if (!v8::String::NewFromTwoByte(
1772 isolate(), reinterpret_cast<const uint16_t*>(m_buffer + m_position),
1773 v8::NewStringType::kNormal, length / sizeof(UChar))
1774 .ToLocal(value))
1775 return false;
1776 m_position += length;
1777 return true;
1778 }
1779
1780 bool SerializedScriptValueReader::readStringObject(
1781 v8::Local<v8::Value>* value) {
1782 v8::Local<v8::Value> stringValue;
1783 if (!readString(&stringValue) || !stringValue->IsString())
1784 return false;
1785 *value = v8::StringObject::New(stringValue.As<v8::String>());
1786 return true;
1787 }
1788
1789 bool SerializedScriptValueReader::readWebCoreString(String* string) {
1790 uint32_t length;
1791 if (!doReadUint32(&length))
1792 return false;
1793 if (m_position + length > m_length)
1794 return false;
1795 *string = String::fromUTF8(
1796 reinterpret_cast<const char*>(m_buffer + m_position), length);
1797 m_position += length;
1798 return true;
1799 }
1800
1801 bool SerializedScriptValueReader::readInt32(v8::Local<v8::Value>* value) {
1802 uint32_t rawValue;
1803 if (!doReadUint32(&rawValue))
1804 return false;
1805 *value = v8::Integer::New(isolate(),
1806 static_cast<int32_t>(ZigZag::decode(rawValue)));
1807 return true;
1808 }
1809
1810 bool SerializedScriptValueReader::readUint32(v8::Local<v8::Value>* value) {
1811 uint32_t rawValue;
1812 if (!doReadUint32(&rawValue))
1813 return false;
1814 *value = v8::Integer::NewFromUnsigned(isolate(), rawValue);
1815 return true;
1816 }
1817
1818 bool SerializedScriptValueReader::readDate(v8::Local<v8::Value>* value) {
1819 double numberValue;
1820 if (!doReadNumber(&numberValue))
1821 return false;
1822 if (!v8DateOrNaN(isolate(), numberValue).ToLocal(value))
1823 return false;
1824 return true;
1825 }
1826
1827 bool SerializedScriptValueReader::readNumber(v8::Local<v8::Value>* value) {
1828 double number;
1829 if (!doReadNumber(&number))
1830 return false;
1831 *value = v8::Number::New(isolate(), number);
1832 return true;
1833 }
1834
1835 bool SerializedScriptValueReader::readNumberObject(
1836 v8::Local<v8::Value>* value) {
1837 double number;
1838 if (!doReadNumber(&number))
1839 return false;
1840 *value = v8::NumberObject::New(isolate(), number);
1841 return true;
1842 }
1843
1844 // Helper function used by readImageData and readImageBitmap.
1845 bool SerializedScriptValueReader::doReadImageDataProperties(
1846 uint32_t* width,
1847 uint32_t* height,
1848 uint32_t* pixelDataLength) {
1849 if (!doReadUint32(width))
1850 return false;
1851 if (!doReadUint32(height))
1852 return false;
1853 if (!doReadUint32(pixelDataLength))
1854 return false;
1855 if (m_length - m_position < *pixelDataLength)
1856 return false;
1857 return true;
1858 }
1859
1860 bool SerializedScriptValueReader::readImageData(v8::Local<v8::Value>* value) {
1861 uint32_t width;
1862 uint32_t height;
1863 uint32_t pixelDataLength;
1864 if (!doReadImageDataProperties(&width, &height, &pixelDataLength))
1865 return false;
1866 ImageData* imageData = ImageData::create(IntSize(width, height));
1867 DOMUint8ClampedArray* pixelArray = imageData->data();
1868 ASSERT(pixelArray);
1869 ASSERT(pixelArray->length() >= pixelDataLength);
1870 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
1871 m_position += pixelDataLength;
1872 if (!imageData)
1873 return false;
1874 *value = ToV8(imageData, m_scriptState->context()->Global(), isolate());
1875 return !value->IsEmpty();
1876 }
1877
1878 bool SerializedScriptValueReader::readImageBitmap(v8::Local<v8::Value>* value) {
1879 uint32_t isOriginClean;
1880 if (!doReadUint32(&isOriginClean))
1881 return false;
1882 uint32_t isPremultiplied;
1883 if (!doReadUint32(&isPremultiplied))
1884 return false;
1885 uint32_t width;
1886 uint32_t height;
1887 uint32_t pixelDataLength;
1888 if (!doReadImageDataProperties(&width, &height, &pixelDataLength))
1889 return false;
1890 const void* pixelData = m_buffer + m_position;
1891 m_position += pixelDataLength;
1892 ImageBitmap* imageBitmap = ImageBitmap::create(
1893 pixelData, width, height, isPremultiplied, isOriginClean);
1894 if (!imageBitmap)
1895 return false;
1896 *value = ToV8(imageBitmap, m_scriptState->context()->Global(), isolate());
1897 return !value->IsEmpty();
1898 }
1899
1900 bool SerializedScriptValueReader::readCompositorProxy(
1901 v8::Local<v8::Value>* value) {
1902 uint32_t attributes;
1903 uint64_t element;
1904 if (!doReadUint64(&element))
1905 return false;
1906 if (!doReadUint32(&attributes))
1907 return false;
1908
1909 CompositorProxy* compositorProxy = CompositorProxy::create(
1910 m_scriptState->getExecutionContext(), element, attributes);
1911 *value = ToV8(compositorProxy, m_scriptState->context()->Global(), isolate());
1912 return !value->IsEmpty();
1913 }
1914
1915 DOMArrayBuffer* SerializedScriptValueReader::doReadArrayBuffer() {
1916 uint32_t byteLength;
1917 if (!doReadUint32(&byteLength))
1918 return nullptr;
1919 if (m_position + byteLength > m_length)
1920 return nullptr;
1921 const void* bufferStart = m_buffer + m_position;
1922 m_position += byteLength;
1923 return DOMArrayBuffer::create(bufferStart, byteLength);
1924 }
1925
1926 bool SerializedScriptValueReader::readWasmCompiledModule(
1927 v8::Local<v8::Value>* value) {
1928 CHECK(RuntimeEnabledFeatures::webAssemblySerializationEnabled());
1929 // First, read the tag of the wire bytes.
1930 SerializationTag wireBytesFormat = InvalidTag;
1931 if (!readTag(&wireBytesFormat))
1932 return false;
1933 DCHECK(wireBytesFormat == RawBytesTag);
1934 // Just like when writing, we don't rely on the default string serialization
1935 // mechanics for the wire bytes. We don't even want a string, because
1936 // that would lead to a memory copying API implementation on the V8 side.
1937 uint32_t wireBytesSize = 0;
1938 uint32_t compiledBytesSize = 0;
1939 if (!doReadUint32(&wireBytesSize))
1940 return false;
1941 if (m_position + wireBytesSize > m_length)
1942 return false;
1943 const uint8_t* wireBytesStart = m_buffer + m_position;
1944 m_position += wireBytesSize;
1945
1946 if (!doReadUint32(&compiledBytesSize))
1947 return false;
1948 if (m_position + compiledBytesSize > m_length)
1949 return false;
1950 const uint8_t* compiledBytesStart = m_buffer + m_position;
1951 m_position += compiledBytesSize;
1952
1953 v8::WasmCompiledModule::CallerOwnedBuffer wireBytes = {
1954 wireBytesStart, static_cast<size_t>(wireBytesSize)};
1955
1956 v8::WasmCompiledModule::CallerOwnedBuffer compiledBytes = {
1957 compiledBytesStart, static_cast<size_t>(compiledBytesSize)};
1958
1959 v8::MaybeLocal<v8::WasmCompiledModule> retval =
1960 v8::WasmCompiledModule::DeserializeOrCompile(isolate(), compiledBytes,
1961 wireBytes);
1962
1963 return retval.ToLocal(value);
1964 }
1965
1966 bool SerializedScriptValueReader::readArrayBuffer(v8::Local<v8::Value>* value) {
1967 DOMArrayBuffer* arrayBuffer = doReadArrayBuffer();
1968 if (!arrayBuffer)
1969 return false;
1970 *value = ToV8(arrayBuffer, m_scriptState->context()->Global(), isolate());
1971 return !value->IsEmpty();
1972 }
1973
1974 bool SerializedScriptValueReader::readArrayBufferView(
1975 v8::Local<v8::Value>* value,
1976 ScriptValueDeserializer& deserializer) {
1977 ArrayBufferViewSubTag subTag;
1978 uint32_t byteOffset;
1979 uint32_t byteLength;
1980 DOMArrayBufferBase* arrayBuffer = nullptr;
1981 v8::Local<v8::Value> arrayBufferV8Value;
1982 if (!readArrayBufferViewSubTag(&subTag))
1983 return false;
1984 if (!doReadUint32(&byteOffset))
1985 return false;
1986 if (!doReadUint32(&byteLength))
1987 return false;
1988 if (!deserializer.consumeTopOfStack(&arrayBufferV8Value))
1989 return false;
1990 if (arrayBufferV8Value.IsEmpty())
1991 return false;
1992 if (arrayBufferV8Value->IsArrayBuffer()) {
1993 arrayBuffer = V8ArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
1994 if (!arrayBuffer)
1995 return false;
1996 } else if (arrayBufferV8Value->IsSharedArrayBuffer()) {
1997 arrayBuffer =
1998 V8SharedArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
1999 if (!arrayBuffer)
2000 return false;
2001 } else {
2002 ASSERT_NOT_REACHED();
2003 }
2004
2005 // Check the offset, length and alignment.
2006 int elementByteSize;
2007 switch (subTag) {
2008 case ByteArrayTag:
2009 elementByteSize = sizeof(DOMInt8Array::ValueType);
2010 break;
2011 case UnsignedByteArrayTag:
2012 elementByteSize = sizeof(DOMUint8Array::ValueType);
2013 break;
2014 case UnsignedByteClampedArrayTag:
2015 elementByteSize = sizeof(DOMUint8ClampedArray::ValueType);
2016 break;
2017 case ShortArrayTag:
2018 elementByteSize = sizeof(DOMInt16Array::ValueType);
2019 break;
2020 case UnsignedShortArrayTag:
2021 elementByteSize = sizeof(DOMUint16Array::ValueType);
2022 break;
2023 case IntArrayTag:
2024 elementByteSize = sizeof(DOMInt32Array::ValueType);
2025 break;
2026 case UnsignedIntArrayTag:
2027 elementByteSize = sizeof(DOMUint32Array::ValueType);
2028 break;
2029 case FloatArrayTag:
2030 elementByteSize = sizeof(DOMFloat32Array::ValueType);
2031 break;
2032 case DoubleArrayTag:
2033 elementByteSize = sizeof(DOMFloat64Array::ValueType);
2034 break;
2035 case DataViewTag:
2036 elementByteSize = sizeof(DOMDataView::ValueType);
2037 break;
2038 default:
2039 return false;
2040 }
2041 const unsigned numElements = byteLength / elementByteSize;
2042 const unsigned remainingElements =
2043 (arrayBuffer->byteLength() - byteOffset) / elementByteSize;
2044 if (byteOffset % elementByteSize || byteOffset > arrayBuffer->byteLength() ||
2045 numElements > remainingElements)
2046 return false;
2047
2048 v8::Local<v8::Object> creationContext = m_scriptState->context()->Global();
2049 switch (subTag) {
2050 case ByteArrayTag:
2051 *value = ToV8(DOMInt8Array::create(arrayBuffer, byteOffset, numElements),
2052 creationContext, isolate());
2053 break;
2054 case UnsignedByteArrayTag:
2055 *value = ToV8(DOMUint8Array::create(arrayBuffer, byteOffset, numElements),
2056 creationContext, isolate());
2057 break;
2058 case UnsignedByteClampedArrayTag:
2059 *value = ToV8(
2060 DOMUint8ClampedArray::create(arrayBuffer, byteOffset, numElements),
2061 creationContext, isolate());
2062 break;
2063 case ShortArrayTag:
2064 *value = ToV8(DOMInt16Array::create(arrayBuffer, byteOffset, numElements),
2065 creationContext, isolate());
2066 break;
2067 case UnsignedShortArrayTag:
2068 *value =
2069 ToV8(DOMUint16Array::create(arrayBuffer, byteOffset, numElements),
2070 creationContext, isolate());
2071 break;
2072 case IntArrayTag:
2073 *value = ToV8(DOMInt32Array::create(arrayBuffer, byteOffset, numElements),
2074 creationContext, isolate());
2075 break;
2076 case UnsignedIntArrayTag:
2077 *value =
2078 ToV8(DOMUint32Array::create(arrayBuffer, byteOffset, numElements),
2079 creationContext, isolate());
2080 break;
2081 case FloatArrayTag:
2082 *value =
2083 ToV8(DOMFloat32Array::create(arrayBuffer, byteOffset, numElements),
2084 creationContext, isolate());
2085 break;
2086 case DoubleArrayTag:
2087 *value =
2088 ToV8(DOMFloat64Array::create(arrayBuffer, byteOffset, numElements),
2089 creationContext, isolate());
2090 break;
2091 case DataViewTag:
2092 *value = ToV8(DOMDataView::create(arrayBuffer, byteOffset, byteLength),
2093 creationContext, isolate());
2094 break;
2095 }
2096 return !value->IsEmpty();
2097 }
2098
2099 bool SerializedScriptValueReader::readRegExp(v8::Local<v8::Value>* value) {
2100 v8::Local<v8::Value> pattern;
2101 if (!readString(&pattern))
2102 return false;
2103 uint32_t flags;
2104 if (!doReadUint32(&flags))
2105 return false;
2106 if (!v8::RegExp::New(getScriptState()->context(), pattern.As<v8::String>(),
2107 static_cast<v8::RegExp::Flags>(flags))
2108 .ToLocal(value))
2109 return false;
2110 return true;
2111 }
2112
2113 bool SerializedScriptValueReader::readBlob(v8::Local<v8::Value>* value,
2114 bool isIndexed) {
2115 if (m_version < 3)
2116 return false;
2117 Blob* blob = nullptr;
2118 if (isIndexed) {
2119 if (m_version < 6)
2120 return false;
2121 ASSERT(m_blobInfo);
2122 uint32_t index;
2123 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2124 return false;
2125 const WebBlobInfo& info = (*m_blobInfo)[index];
2126 blob = Blob::create(
2127 getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2128 } else {
2129 ASSERT(!m_blobInfo);
2130 String uuid;
2131 String type;
2132 uint64_t size;
2133 ASSERT(!m_blobInfo);
2134 if (!readWebCoreString(&uuid))
2135 return false;
2136 if (!readWebCoreString(&type))
2137 return false;
2138 if (!doReadUint64(&size))
2139 return false;
2140 blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size));
2141 }
2142 *value = ToV8(blob, m_scriptState->context()->Global(), isolate());
2143 return !value->IsEmpty();
2144 }
2145
2146 bool SerializedScriptValueReader::readFile(v8::Local<v8::Value>* value,
2147 bool isIndexed) {
2148 File* file = nullptr;
2149 if (isIndexed) {
2150 if (m_version < 6)
2151 return false;
2152 file = readFileIndexHelper();
2153 } else {
2154 file = readFileHelper();
2155 }
2156 if (!file)
2157 return false;
2158 *value = ToV8(file, m_scriptState->context()->Global(), isolate());
2159 return !value->IsEmpty();
2160 }
2161
2162 bool SerializedScriptValueReader::readFileList(v8::Local<v8::Value>* value,
2163 bool isIndexed) {
2164 if (m_version < 3)
2165 return false;
2166 uint32_t length;
2167 if (!doReadUint32(&length))
2168 return false;
2169 FileList* fileList = FileList::create();
2170 for (unsigned i = 0; i < length; ++i) {
2171 File* file = nullptr;
2172 if (isIndexed) {
2173 if (m_version < 6)
2174 return false;
2175 file = readFileIndexHelper();
2176 } else {
2177 file = readFileHelper();
2178 }
2179 if (!file)
2180 return false;
2181 fileList->append(file);
2182 }
2183 *value = ToV8(fileList, m_scriptState->context()->Global(), isolate());
2184 return !value->IsEmpty();
2185 }
2186
2187 File* SerializedScriptValueReader::readFileHelper() {
2188 if (m_version < 3)
2189 return nullptr;
2190 ASSERT(!m_blobInfo);
2191 String path;
2192 String name;
2193 String relativePath;
2194 String uuid;
2195 String type;
2196 uint32_t hasSnapshot = 0;
2197 uint64_t size = 0;
2198 double lastModifiedMS = 0;
2199 if (!readWebCoreString(&path))
2200 return nullptr;
2201 if (m_version >= 4 && !readWebCoreString(&name))
2202 return nullptr;
2203 if (m_version >= 4 && !readWebCoreString(&relativePath))
2204 return nullptr;
2205 if (!readWebCoreString(&uuid))
2206 return nullptr;
2207 if (!readWebCoreString(&type))
2208 return nullptr;
2209 if (m_version >= 4 && !doReadUint32(&hasSnapshot))
2210 return nullptr;
2211 if (hasSnapshot) {
2212 if (!doReadUint64(&size))
2213 return nullptr;
2214 if (!doReadNumber(&lastModifiedMS))
2215 return nullptr;
2216 if (m_version < 8)
2217 lastModifiedMS *= msPerSecond;
2218 }
2219 uint32_t isUserVisible = 1;
2220 if (m_version >= 7 && !doReadUint32(&isUserVisible))
2221 return nullptr;
2222 const File::UserVisibility userVisibility =
2223 (isUserVisible > 0) ? File::IsUserVisible : File::IsNotUserVisible;
2224 return File::createFromSerialization(path, name, relativePath, userVisibility,
2225 hasSnapshot > 0, size, lastModifiedMS,
2226 getOrCreateBlobDataHandle(uuid, type));
2227 }
2228
2229 File* SerializedScriptValueReader::readFileIndexHelper() {
2230 if (m_version < 3)
2231 return nullptr;
2232 ASSERT(m_blobInfo);
2233 uint32_t index;
2234 if (!doReadUint32(&index) || index >= m_blobInfo->size())
2235 return nullptr;
2236 const WebBlobInfo& info = (*m_blobInfo)[index];
2237 // FIXME: transition WebBlobInfo.lastModified to be milliseconds-based also.
2238 double lastModifiedMS = info.lastModified() * msPerSecond;
2239 return File::createFromIndexedSerialization(
2240 info.filePath(), info.fileName(), info.size(), lastModifiedMS,
2241 getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
2242 }
2243
2244 bool SerializedScriptValueReader::doReadUint32(uint32_t* value) {
2245 return doReadUintHelper(value);
2246 }
2247
2248 bool SerializedScriptValueReader::doReadUint64(uint64_t* value) {
2249 return doReadUintHelper(value);
2250 }
2251
2252 bool SerializedScriptValueReader::doReadNumber(double* number) {
2253 if (m_position + sizeof(double) > m_length)
2254 return false;
2255 uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number);
2256 for (unsigned i = 0; i < sizeof(double); ++i)
2257 numberAsByteArray[i] = m_buffer[m_position++];
2258 return true;
2259 }
2260
2261 PassRefPtr<BlobDataHandle>
2262 SerializedScriptValueReader::getOrCreateBlobDataHandle(const String& uuid,
2263 const String& type,
2264 long long size) {
2265 // The containing ssv may have a BDH for this uuid if this ssv is just being
2266 // passed from main to worker thread (for example). We use those values when
2267 // creating the new blob instead of cons'ing up a new BDH.
2268 //
2269 // FIXME: Maybe we should require that it work that way where the ssv must
2270 // have a BDH for any blobs it comes across during deserialization. Would
2271 // require callers to explicitly populate the collection of BDH's for blobs to
2272 // work, which would encourage lifetimes to be considered when passing ssv's
2273 // around cross process. At present, we get 'lucky' in some cases because the
2274 // blob in the src process happens to still exist at the time the dest process
2275 // is deserializing.
2276 // For example in sharedWorker.postMessage(...).
2277 BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid);
2278 if (it != m_blobDataHandles.end()) {
2279 // make assertions about type and size?
2280 return it->value;
2281 }
2282 return BlobDataHandle::create(uuid, type, size);
2283 }
2284
2285 v8::Local<v8::Value> ScriptValueDeserializer::deserialize() {
2286 v8::Isolate* isolate = m_reader.getScriptState()->isolate();
2287 if (!m_reader.readVersion(m_version) ||
2288 m_version > SerializedScriptValue::wireFormatVersion)
2289 return v8::Null(isolate);
2290 m_reader.setVersion(m_version);
2291 v8::EscapableHandleScope scope(isolate);
2292 while (!m_reader.isEof()) {
2293 if (!doDeserialize())
2294 return v8::Null(isolate);
2295 }
2296 if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
2297 return v8::Null(isolate);
2298 v8::Local<v8::Value> result = scope.Escape(element(0));
2299 return result;
2300 }
2301
2302 bool ScriptValueDeserializer::newSparseArray(uint32_t) {
2303 v8::Local<v8::Array> array =
2304 v8::Array::New(m_reader.getScriptState()->isolate(), 0);
2305 openComposite(array);
2306 return true;
2307 }
2308
2309 bool ScriptValueDeserializer::newDenseArray(uint32_t length) {
2310 v8::Local<v8::Array> array =
2311 v8::Array::New(m_reader.getScriptState()->isolate(), length);
2312 openComposite(array);
2313 return true;
2314 }
2315
2316 bool ScriptValueDeserializer::newMap() {
2317 v8::Local<v8::Map> map = v8::Map::New(m_reader.getScriptState()->isolate());
2318 openComposite(map);
2319 return true;
2320 }
2321
2322 bool ScriptValueDeserializer::newSet() {
2323 v8::Local<v8::Set> set = v8::Set::New(m_reader.getScriptState()->isolate());
2324 openComposite(set);
2325 return true;
2326 }
2327
2328 bool ScriptValueDeserializer::consumeTopOfStack(v8::Local<v8::Value>* object) {
2329 if (stackDepth() < 1)
2330 return false;
2331 *object = element(stackDepth() - 1);
2332 pop(1);
2333 return true;
2334 }
2335
2336 bool ScriptValueDeserializer::newObject() {
2337 v8::Local<v8::Object> object =
2338 v8::Object::New(m_reader.getScriptState()->isolate());
2339 if (object.IsEmpty())
2340 return false;
2341 openComposite(object);
2342 return true;
2343 }
2344
2345 bool ScriptValueDeserializer::completeObject(uint32_t numProperties,
2346 v8::Local<v8::Value>* value) {
2347 v8::Local<v8::Object> object;
2348 if (m_version > 0) {
2349 v8::Local<v8::Value> composite;
2350 if (!closeComposite(&composite))
2351 return false;
2352 object = composite.As<v8::Object>();
2353 } else {
2354 object = v8::Object::New(m_reader.getScriptState()->isolate());
2355 }
2356 if (object.IsEmpty())
2357 return false;
2358 return initializeObject(object, numProperties, value);
2359 }
2360
2361 bool ScriptValueDeserializer::completeSparseArray(uint32_t numProperties,
2362 uint32_t length,
2363 v8::Local<v8::Value>* value) {
2364 v8::Local<v8::Array> array;
2365 if (m_version > 0) {
2366 v8::Local<v8::Value> composite;
2367 if (!closeComposite(&composite))
2368 return false;
2369 array = composite.As<v8::Array>();
2370 } else {
2371 array = v8::Array::New(m_reader.getScriptState()->isolate());
2372 }
2373 if (array.IsEmpty())
2374 return false;
2375 return initializeObject(array, numProperties, value);
2376 }
2377
2378 bool ScriptValueDeserializer::completeDenseArray(uint32_t numProperties,
2379 uint32_t length,
2380 v8::Local<v8::Value>* value) {
2381 v8::Local<v8::Array> array;
2382 if (m_version > 0) {
2383 v8::Local<v8::Value> composite;
2384 if (!closeComposite(&composite))
2385 return false;
2386 array = composite.As<v8::Array>();
2387 }
2388 if (array.IsEmpty())
2389 return false;
2390 if (!initializeObject(array, numProperties, value))
2391 return false;
2392 if (length > stackDepth())
2393 return false;
2394 v8::Local<v8::Context> context = m_reader.getScriptState()->context();
2395 for (unsigned i = 0, stackPos = stackDepth() - length; i < length;
2396 i++, stackPos++) {
2397 v8::Local<v8::Value> elem = element(stackPos);
2398 if (!elem->IsUndefined()) {
2399 if (!v8CallBoolean(array->CreateDataProperty(context, i, elem)))
2400 return false;
2401 }
2402 }
2403 pop(length);
2404 return true;
2405 }
2406
2407 bool ScriptValueDeserializer::completeMap(uint32_t length,
2408 v8::Local<v8::Value>* value) {
2409 ASSERT(m_version > 0);
2410 v8::Local<v8::Value> composite;
2411 if (!closeComposite(&composite))
2412 return false;
2413 v8::Local<v8::Map> map = composite.As<v8::Map>();
2414 if (map.IsEmpty())
2415 return false;
2416 v8::Local<v8::Context> context = m_reader.getScriptState()->context();
2417 ASSERT(length % 2 == 0);
2418 for (unsigned i = stackDepth() - length; i + 1 < stackDepth(); i += 2) {
2419 v8::Local<v8::Value> key = element(i);
2420 v8::Local<v8::Value> val = element(i + 1);
2421 if (map->Set(context, key, val).IsEmpty())
2422 return false;
2423 }
2424 pop(length);
2425 *value = map;
2426 return true;
2427 }
2428
2429 bool ScriptValueDeserializer::completeSet(uint32_t length,
2430 v8::Local<v8::Value>* value) {
2431 ASSERT(m_version > 0);
2432 v8::Local<v8::Value> composite;
2433 if (!closeComposite(&composite))
2434 return false;
2435 v8::Local<v8::Set> set = composite.As<v8::Set>();
2436 if (set.IsEmpty())
2437 return false;
2438 v8::Local<v8::Context> context = m_reader.getScriptState()->context();
2439 for (unsigned i = stackDepth() - length; i < stackDepth(); i++) {
2440 v8::Local<v8::Value> key = element(i);
2441 if (set->Add(context, key).IsEmpty())
2442 return false;
2443 }
2444 pop(length);
2445 *value = set;
2446 return true;
2447 }
2448
2449 void ScriptValueDeserializer::pushObjectReference(
2450 const v8::Local<v8::Value>& object) {
2451 m_objectPool.push_back(object);
2452 }
2453
2454 bool ScriptValueDeserializer::tryGetTransferredMessagePort(
2455 uint32_t index,
2456 v8::Local<v8::Value>* object) {
2457 if (!m_transferredMessagePorts)
2458 return false;
2459 if (index >= m_transferredMessagePorts->size())
2460 return false;
2461 v8::Local<v8::Object> creationContext =
2462 m_reader.getScriptState()->context()->Global();
2463 *object = ToV8(m_transferredMessagePorts->at(index).get(), creationContext,
2464 m_reader.getScriptState()->isolate());
2465 return !object->IsEmpty();
2466 }
2467
2468 bool ScriptValueDeserializer::tryGetTransferredArrayBuffer(
2469 uint32_t index,
2470 v8::Local<v8::Value>* object) {
2471 if (!m_arrayBufferContents)
2472 return false;
2473 if (index >= m_arrayBuffers.size())
2474 return false;
2475 v8::Local<v8::Value> result = m_arrayBuffers.at(index);
2476 if (result.IsEmpty()) {
2477 DOMArrayBuffer* buffer =
2478 DOMArrayBuffer::create(m_arrayBufferContents->at(index));
2479 v8::Isolate* isolate = m_reader.getScriptState()->isolate();
2480 v8::Local<v8::Object> creationContext =
2481 m_reader.getScriptState()->context()->Global();
2482 result = ToV8(buffer, creationContext, isolate);
2483 if (result.IsEmpty())
2484 return false;
2485 m_arrayBuffers[index] = result;
2486 }
2487 *object = result;
2488 return true;
2489 }
2490
2491 bool ScriptValueDeserializer::tryGetTransferredImageBitmap(
2492 uint32_t index,
2493 v8::Local<v8::Value>* object) {
2494 if (!m_imageBitmapContents)
2495 return false;
2496 if (index >= m_imageBitmaps.size())
2497 return false;
2498 v8::Local<v8::Value> result = m_imageBitmaps.at(index);
2499 if (result.IsEmpty()) {
2500 ImageBitmap* bitmap = ImageBitmap::create(m_imageBitmapContents->at(index));
2501 v8::Isolate* isolate = m_reader.getScriptState()->isolate();
2502 v8::Local<v8::Object> creationContext =
2503 m_reader.getScriptState()->context()->Global();
2504 result = ToV8(bitmap, creationContext, isolate);
2505 if (result.IsEmpty())
2506 return false;
2507 m_imageBitmaps[index] = result;
2508 }
2509 *object = result;
2510 return true;
2511 }
2512
2513 bool ScriptValueDeserializer::tryGetTransferredSharedArrayBuffer(
2514 uint32_t index,
2515 v8::Local<v8::Value>* object) {
2516 ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
2517 if (!m_arrayBufferContents)
2518 return false;
2519 if (index >= m_arrayBuffers.size())
2520 return false;
2521 v8::Local<v8::Value> result = m_arrayBuffers.at(index);
2522 if (result.IsEmpty()) {
2523 DOMSharedArrayBuffer* buffer =
2524 DOMSharedArrayBuffer::create(m_arrayBufferContents->at(index));
2525 v8::Isolate* isolate = m_reader.getScriptState()->isolate();
2526 v8::Local<v8::Object> creationContext =
2527 m_reader.getScriptState()->context()->Global();
2528 result = ToV8(buffer, creationContext, isolate);
2529 if (result.IsEmpty())
2530 return false;
2531 m_arrayBuffers[index] = result;
2532 }
2533 *object = result;
2534 return true;
2535 }
2536
2537 bool ScriptValueDeserializer::tryGetTransferredOffscreenCanvas(
2538 uint32_t width,
2539 uint32_t height,
2540 uint32_t canvasId,
2541 uint32_t clientId,
2542 uint32_t sinkId,
2543 v8::Local<v8::Value>* object) {
2544 OffscreenCanvas* offscreenCanvas = OffscreenCanvas::create(width, height);
2545 offscreenCanvas->setPlaceholderCanvasId(canvasId);
2546 offscreenCanvas->setFrameSinkId(clientId, sinkId);
2547 *object = ToV8(offscreenCanvas, m_reader.getScriptState());
2548 if ((*object).IsEmpty())
2549 return false;
2550 return true;
2551 }
2552
2553 bool ScriptValueDeserializer::tryGetObjectFromObjectReference(
2554 uint32_t reference,
2555 v8::Local<v8::Value>* object) {
2556 if (reference >= m_objectPool.size())
2557 return false;
2558 *object = m_objectPool[reference];
2559 return object;
2560 }
2561
2562 uint32_t ScriptValueDeserializer::objectReferenceCount() {
2563 return m_objectPool.size();
2564 }
2565
2566 bool ScriptValueDeserializer::initializeObject(v8::Local<v8::Object> object,
2567 uint32_t numProperties,
2568 v8::Local<v8::Value>* value) {
2569 unsigned length = 2 * numProperties;
2570 if (length > stackDepth())
2571 return false;
2572 v8::Local<v8::Context> context = m_reader.getScriptState()->context();
2573 for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) {
2574 v8::Local<v8::Value> propertyName = element(i);
2575 v8::Local<v8::Value> propertyValue = element(i + 1);
2576 bool result = false;
2577 if (propertyName->IsString())
2578 result = v8CallBoolean(object->CreateDataProperty(
2579 context, propertyName.As<v8::String>(), propertyValue));
2580 else if (propertyName->IsUint32())
2581 result = v8CallBoolean(object->CreateDataProperty(
2582 context, propertyName.As<v8::Uint32>()->Value(), propertyValue));
2583 else
2584 ASSERT_NOT_REACHED();
2585 if (!result)
2586 return false;
2587 }
2588 pop(length);
2589 *value = object;
2590 return true;
2591 }
2592
2593 bool ScriptValueDeserializer::read(v8::Local<v8::Value>* value) {
2594 return m_reader.read(value, *this);
2595 }
2596
2597 bool ScriptValueDeserializer::doDeserialize() {
2598 v8::Local<v8::Value> value;
2599 if (!read(&value))
2600 return false;
2601 if (!value.IsEmpty())
2602 push(value);
2603 return true;
2604 }
2605
2606 v8::Local<v8::Value> ScriptValueDeserializer::element(unsigned index) {
2607 SECURITY_DCHECK(index < m_stack.size());
2608 return m_stack[index];
2609 }
2610
2611 void ScriptValueDeserializer::openComposite(
2612 const v8::Local<v8::Value>& object) {
2613 uint32_t newObjectReference = m_objectPool.size();
2614 m_openCompositeReferenceStack.push_back(newObjectReference);
2615 m_objectPool.push_back(object);
2616 }
2617
2618 bool ScriptValueDeserializer::closeComposite(v8::Local<v8::Value>* object) {
2619 if (!m_openCompositeReferenceStack.size())
2620 return false;
2621 uint32_t objectReference =
2622 m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
2623 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() -
2624 1);
2625 if (objectReference >= m_objectPool.size())
2626 return false;
2627 *object = m_objectPool[objectReference];
2628 return true;
2629 }
2630
2631 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698